Simplify ESLint dev dependencies and config, drop JSX syntax, use .mjs files.

This commit is contained in:
Jayden Seric 2022-05-20 11:00:12 +10:00
parent 32ac135165
commit 4a6bb2c992
27 changed files with 597 additions and 5400 deletions

View File

@ -1,3 +1,30 @@
{
"extends": ["env"]
"extends": ["eslint:recommended"],
"env": {
"es2022": true,
"node": true
},
"parserOptions": {
"ecmaVersion": "latest"
},
"plugins": ["simple-import-sort"],
"rules": {
"simple-import-sort/imports": "error",
"simple-import-sort/exports": "error"
},
"overrides": [
{
"files": ["*.mjs"],
"parserOptions": {
"sourceType": "module"
},
"globals": {
"__dirname": "off",
"__filename": "off",
"exports": "off",
"module": "off",
"require": "off"
}
}
]
}

2386
api/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -30,12 +30,7 @@
},
"devDependencies": {
"eslint": "^8.15.0",
"eslint-config-env": "^23.0.2",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-jsdoc": "^37.9.7",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-simple-import-sort": "^7.0.0",
"nodemon": "^2.0.16",
"prettier": "^2.6.2"
},

View File

@ -1,4 +1,5 @@
import { GraphQLNonNull, GraphQLObjectType, GraphQLString } from "graphql";
import UPLOAD_DIRECTORY_URL from "../config/UPLOAD_DIRECTORY_URL.mjs";
export default new GraphQLObjectType({

View File

@ -1,5 +1,6 @@
import { GraphQLList, GraphQLNonNull, GraphQLObjectType } from "graphql";
import GraphQLUpload from "graphql-upload/public/GraphQLUpload.js";
import storeUpload from "../storeUpload.mjs";
import FileType from "./FileType.mjs";

View File

@ -1,5 +1,6 @@
import fs from "fs";
import { GraphQLList, GraphQLNonNull, GraphQLObjectType } from "graphql";
import UPLOAD_DIRECTORY_URL from "../config/UPLOAD_DIRECTORY_URL.mjs";
import FileType from "./FileType.mjs";

View File

@ -1,4 +1,5 @@
import { GraphQLSchema } from "graphql";
import MutationType from "./MutationType.mjs";
import QueryType from "./QueryType.mjs";

View File

@ -1,8 +1,9 @@
import { fileURLToPath } from "url";
import { ApolloServer } from "apollo-server-koa";
import graphqlUploadKoa from "graphql-upload/public/graphqlUploadKoa.js";
import Koa from "koa";
import makeDir from "make-dir";
import { fileURLToPath } from "url";
import UPLOAD_DIRECTORY_URL from "./config/UPLOAD_DIRECTORY_URL.mjs";
import schema from "./schema/index.mjs";

View File

@ -1,5 +1,6 @@
import { createWriteStream, unlink } from "fs";
import shortId from "shortid";
import UPLOAD_DIRECTORY_URL from "./config/UPLOAD_DIRECTORY_URL.mjs";
/**

37
app/.eslintrc.js Normal file
View File

@ -0,0 +1,37 @@
const { resolve } = require("path");
module.exports = {
extends: ["eslint:recommended", "plugin:react-hooks/recommended"],
env: {
es2022: true,
node: true,
browser: true,
},
parser: "@babel/eslint-parser",
parserOptions: {
ecmaVersion: "latest",
babelOptions: {
configFile: resolve(__dirname, ".babelrc"),
},
},
plugins: ["simple-import-sort"],
rules: {
"simple-import-sort/imports": "error",
"simple-import-sort/exports": "error",
},
overrides: [
{
files: ["*.mjs"],
parserOptions: {
sourceType: "module",
},
globals: {
__dirname: "off",
__filename: "off",
exports: "off",
module: "off",
require: "off",
},
},
],
};

View File

@ -1,11 +0,0 @@
{
"extends": ["env"],
"overrides": [
{
"files": ["components/**/*.js", "pages/**/*.js"],
"rules": {
"jsdoc/require-jsdoc": "off"
}
}
]
}

View File

@ -1,5 +0,0 @@
import styles from "./Header.module.css";
export const Header = (props) => (
<header {...props} className={styles.header} />
);

View File

@ -0,0 +1,6 @@
import { createElement as h } from "react";
import styles from "./Header.module.css";
export const Header = (props) =>
h("header", { ...props, className: styles.header });

View File

@ -1,16 +0,0 @@
import Head from "next/head";
import PropTypes from "prop-types";
export const Page = ({ title, children }) => (
<>
<Head>
<title>{title}</title>
</Head>
{children}
</>
);
Page.propTypes = {
title: PropTypes.string.isRequired,
children: PropTypes.node.isRequired,
};

11
app/components/Page.mjs Normal file
View File

@ -0,0 +1,11 @@
import Head from "next/head";
import PropTypes from "prop-types";
import { createElement as h, Fragment } from "react";
export const Page = ({ title, children }) =>
h(Fragment, null, h(Head, null, h("title", null, title)), children);
Page.propTypes = {
title: PropTypes.string.isRequired,
children: PropTypes.node.isRequired,
};

View File

@ -1,5 +0,0 @@
import styles from "./Section.module.css";
export const Section = (props) => (
<section {...props} className={styles.section} />
);

View File

@ -0,0 +1,6 @@
import { createElement as h } from "react";
import styles from "./Section.module.css";
export const Section = (props) =>
h("section", { ...props, className: styles.section });

View File

@ -3,7 +3,7 @@ import ButtonSubmit from "device-agnostic-ui/ButtonSubmit.mjs";
import Code from "device-agnostic-ui/Code.mjs";
import Fieldset from "device-agnostic-ui/Fieldset.mjs";
import Textbox from "device-agnostic-ui/Textbox.mjs";
import React from "react";
import { createElement as h, Fragment, useState } from "react";
const SINGLE_UPLOAD_MUTATION = gql`
mutation singleUpload($file: Upload!) {
@ -14,8 +14,8 @@ const SINGLE_UPLOAD_MUTATION = gql`
`;
export function UploadBlob() {
const [name, setName] = React.useState("");
const [content, setContent] = React.useState("");
const [name, setName] = useState("");
const [content, setContent] = useState("");
const [singleUploadMutation, { loading }] = useMutation(
SINGLE_UPLOAD_MUTATION
);
@ -34,32 +34,38 @@ export function UploadBlob() {
});
};
return (
<form onSubmit={onSubmit}>
<Fieldset
legend={
<>
File name (without <Code>.txt</Code>)
</>
}
>
<Textbox
placeholder="Name"
required
value={name}
onChange={onNameChange}
/>
</Fieldset>
<Fieldset legend="File content">
<Textbox
type="textarea"
placeholder="Content"
required
value={content}
onChange={onContentChange}
/>
</Fieldset>
<ButtonSubmit loading={loading}>Upload</ButtonSubmit>
</form>
return h(
"form",
{ onSubmit },
h(
Fieldset,
{
legend: h(
Fragment,
null,
"File name (without ",
h(Code, null, ".txt"),
")"
),
},
h(Textbox, {
placeholder: "Name",
required: true,
value: name,
onChange: onNameChange,
})
),
h(
Fieldset,
{ legend: "File content" },
h(Textbox, {
type: "textarea",
placeholder: "Content",
required: true,
value: content,
onChange: onContentChange,
})
),
h(ButtonSubmit, { loading }, "Upload")
);
}

View File

@ -1,4 +1,5 @@
import { gql, useApolloClient, useMutation } from "@apollo/client";
import { createElement as h } from "react";
const SINGLE_UPLOAD_MUTATION = gql`
mutation singleUpload($file: Upload!) {
@ -23,5 +24,5 @@ export function UploadFile() {
apolloClient.resetStore();
});
return <input type="file" required onChange={onChange} />;
return h("input", { type: "file", required: true, onChange });
}

View File

@ -1,4 +1,5 @@
import { gql, useApolloClient, useMutation } from "@apollo/client";
import { createElement as h } from "react";
const MULTIPLE_UPLOAD_MUTATION = gql`
mutation multipleUpload($files: [Upload!]!) {
@ -18,5 +19,5 @@ export function UploadFileList() {
apolloClient.resetStore();
});
return <input type="file" multiple required onChange={onChange} />;
return h("input", { type: "file", multiple: true, required: true, onChange });
}

View File

@ -1,6 +1,7 @@
import { gql, useQuery } from "@apollo/client";
import Scroll from "device-agnostic-ui/Scroll.mjs";
import Table from "device-agnostic-ui/Table.mjs";
import { createElement as h } from "react";
const UPLOADS_QUERY = gql`
query uploads {
@ -14,22 +15,18 @@ const UPLOADS_QUERY = gql`
export function Uploads() {
const { data: { uploads = [] } = {} } = useQuery(UPLOADS_QUERY);
return (
<Scroll>
<Table>
<thead>
<tr>
<th>Stored file URL</th>
</tr>
</thead>
<tbody>
{uploads.map(({ id, url }) => (
<tr key={id}>
<td>{url}</td>
</tr>
))}
</tbody>
</Table>
</Scroll>
return h(
Scroll,
null,
h(
Table,
null,
h("thead", null, h("tr", null, h("th", null, "Stored file URL"))),
h(
"tbody",
null,
uploads.map(({ id, url }) => h("tr", { key: id }, h("td", null, url)))
)
)
);
}

View File

@ -1,4 +1,4 @@
module.exports = {
export default {
env: {
API_URI: process.env.API_URI,
},
@ -6,5 +6,6 @@ module.exports = {
locales: ["en-US"],
defaultLocale: "en-US",
},
pageExtensions: ["mjs"],
reactStrictMode: true,
};

3199
app/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -32,18 +32,10 @@
},
"devDependencies": {
"@babel/eslint-parser": "^7.17.0",
"@next/eslint-plugin-next": "^12.1.6",
"babel-plugin-graphql-tag": "^3.3.0",
"eslint": "^8.15.0",
"eslint-config-env": "^23.0.2",
"eslint-config-next": "^12.1.6",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-jsdoc": "^37.9.7",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-react": "^7.30.0",
"eslint-plugin-react-hooks": "^4.5.0",
"eslint-plugin-simple-import-sort": "^7.0.0",
"prettier": "^2.6.2",
"stylelint": "^14.8.2",
"stylelint-config-prettier": "^9.0.3",

View File

@ -10,10 +10,12 @@ import "device-agnostic-ui/Margin.css";
import "device-agnostic-ui/Scroll.css";
import "device-agnostic-ui/Table.css";
import "device-agnostic-ui/Textbox.css";
import { ApolloClient, ApolloProvider, InMemoryCache } from "@apollo/client";
import { createUploadLink } from "apollo-upload-client";
import Head from "next/head";
import PropTypes from "prop-types";
import { createElement as h } from "react";
const createApolloClient = (cache = {}) =>
new ApolloClient({
@ -27,17 +29,23 @@ const App = ({
pageProps,
apolloCache,
apolloClient = createApolloClient(apolloCache),
}) => (
<ApolloProvider client={apolloClient}>
<Head>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="color-scheme" content="light dark" />
<meta name="theme-color" content="white" />
<link rel="manifest" href="/manifest.webmanifest" />
</Head>
<Component {...pageProps} />
</ApolloProvider>
);
}) =>
h(
ApolloProvider,
{ client: apolloClient },
h(
Head,
null,
h("meta", {
name: "viewport",
content: "width=device-width, initial-scale=1",
}),
h("meta", { name: "color-scheme", content: "light dark" }),
h("meta", { name: "theme-color", content: "white" }),
h("link", { rel: "manifest", href: "/manifest.webmanifest" })
),
h(Component, pageProps)
);
App.getInitialProps = async (context) => {
const props = {
@ -51,12 +59,12 @@ App.getInitialProps = async (context) => {
try {
const { getDataFromTree } = await import("@apollo/client/react/ssr");
await getDataFromTree(
<App
{...props}
apolloClient={apolloClient}
router={context.router}
Component={context.Component}
/>
h(App, {
...props,
apolloClient,
router: context.router,
Component: context.Component,
})
);
} catch (error) {
// Prevent crash from GraphQL errors.

View File

@ -1,58 +0,0 @@
import Code from "device-agnostic-ui/Code.mjs";
import Heading from "device-agnostic-ui/Heading.mjs";
import Margin from "device-agnostic-ui/Margin.mjs";
import { Header } from "../components/Header";
import { Page } from "../components/Page";
import { Section } from "../components/Section";
import { UploadBlob } from "../components/UploadBlob";
import { UploadFile } from "../components/UploadFile";
import { UploadFileList } from "../components/UploadFileList";
import { Uploads } from "../components/Uploads";
const IndexPage = () => (
<Page title="Apollo upload examples">
<Header>
<Heading level={1} size={1}>
Apollo upload examples
</Heading>
</Header>
<Section>
<Header>
<Heading level={2} size={2}>
Upload <Code>FileList</Code>
</Heading>
</Header>
<Margin>
<UploadFileList />
</Margin>
</Section>
<Section>
<Header>
<Heading level={2} size={2}>
Upload <Code>File</Code>
</Heading>
</Header>
<Margin>
<UploadFile />
</Margin>
</Section>
<Section>
<Header>
<Heading level={2} size={2}>
Upload <Code>Blob</Code>
</Heading>
</Header>
<Margin>
<UploadBlob />
</Margin>
</Section>
<Section>
<Header>
<Heading>Uploads</Heading>
</Header>
<Uploads />
</Section>
</Page>
);
export default IndexPage;

55
app/pages/index.mjs Normal file
View File

@ -0,0 +1,55 @@
import Code from "device-agnostic-ui/Code.mjs";
import Heading from "device-agnostic-ui/Heading.mjs";
import Margin from "device-agnostic-ui/Margin.mjs";
import { createElement as h } from "react";
import { Header } from "../components/Header.mjs";
import { Page } from "../components/Page.mjs";
import { Section } from "../components/Section.mjs";
import { UploadBlob } from "../components/UploadBlob.mjs";
import { UploadFile } from "../components/UploadFile.mjs";
import { UploadFileList } from "../components/UploadFileList.mjs";
import { Uploads } from "../components/Uploads.mjs";
export default function IndexPage() {
return h(
Page,
{ title: "Apollo upload examples" },
h(
Header,
null,
h(Heading, { level: 1, size: 1 }, "Apollo upload examples")
),
h(
Section,
null,
h(
Header,
null,
h(Heading, { level: 2, size: 2 }, "Upload ", h(Code, null, "FileList"))
),
h(Margin, null, h(UploadFileList))
),
h(
Section,
null,
h(
Header,
null,
h(Heading, { level: 2, size: 2 }, "Upload ", h(Code, null, "File"))
),
h(Margin, null, h(UploadFile))
),
h(
Section,
null,
h(
Header,
null,
h(Heading, { level: 2, size: 2 }, "Upload ", h(Code, null, "Blob"))
),
h(Margin, null, h(UploadBlob))
),
h(Section, null, h(Header, null, h(Heading, null, "Uploads")), h(Uploads))
);
}