diff --git a/.eslintrc.yml b/.eslintrc.yml index b3bc8b6c..051a5b10 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -3,7 +3,7 @@ parserOptions: env: es2022: true browser: true -plugins: ['react', 'react-hooks'] +plugins: ['simple-import-sort', 'react', 'react-hooks'] settings: react: version: detect @@ -14,6 +14,8 @@ extends: - 'plugin:react/jsx-runtime' - 'plugin:react-hooks/recommended' rules: + 'simple-import-sort/imports': error + 'simple-import-sort/exports': error 'import/no-extraneous-dependencies': [error, { devDependencies: ['**/*.config.{js,ts}', 'tests/**'] }] overrides: diff --git a/demo/IntrospectionModal.tsx b/demo/IntrospectionModal.tsx index 1953e581..6aa3a77c 100644 --- a/demo/IntrospectionModal.tsx +++ b/demo/IntrospectionModal.tsx @@ -1,28 +1,25 @@ -import * as React from 'react'; - -import Tab from '@mui/material/Tab'; -import Button from '@mui/material/Button'; -import TextField from '@mui/material/TextField'; -import Grid from '@mui/material/Unstable_Grid2'; -import Stack from '@mui/material/Stack'; +import ContentCopyIcon from '@mui/icons-material/ContentCopy'; import TabContext from '@mui/lab/TabContext'; import TabList from '@mui/lab/TabList'; import TabPanel from '@mui/lab/TabPanel'; +import Button from '@mui/material/Button'; import Dialog from '@mui/material/Dialog'; -import DialogContent from '@mui/material/DialogContent'; import DialogActions from '@mui/material/DialogActions'; +import DialogContent from '@mui/material/DialogContent'; +import Stack from '@mui/material/Stack'; +import Tab from '@mui/material/Tab'; +import TextField from '@mui/material/TextField'; import Tooltip from '@mui/material/Tooltip'; import Typography from '@mui/material/Typography'; - -import ContentCopyIcon from '@mui/icons-material/ContentCopy'; - +import Grid from '@mui/material/Unstable_Grid2'; import { buildSchema, getIntrospectionQuery, introspectionFromSchema, } from 'graphql/utilities'; +import * as React from 'react'; -import { PRESETS, defaultPresetName } from './presets'; +import { defaultPresetName, PRESETS } from './presets'; enum InputType { Presets = 'Presets', diff --git a/demo/index.tsx b/demo/index.tsx index 3aa84b9f..13646f57 100644 --- a/demo/index.tsx +++ b/demo/index.tsx @@ -1,18 +1,16 @@ -import * as React from 'react'; -import * as ReactDOMClient from 'react-dom/client'; - +import Box from '@mui/material/Box'; import Button from '@mui/material/Button'; +import Link from '@mui/material/Link'; +import Stack from '@mui/material/Stack'; import { ThemeProvider } from '@mui/material/styles'; import SvgIcon from '@mui/material/SvgIcon'; -import Link from '@mui/material/Link'; import Typography from '@mui/material/Typography'; -import Stack from '@mui/material/Stack'; -import Box from '@mui/material/Box'; +import * as React from 'react'; +import * as ReactDOMClient from 'react-dom/client'; -import { theme } from '../src/components/MUITheme'; import { GraphQLVoyager } from '../src'; +import { theme } from '../src/components/MUITheme'; import LogoIcon from './icons/logo-small.svg'; - import { IntrospectionModal } from './IntrospectionModal'; import { defaultPreset } from './presets'; diff --git a/package-lock.json b/package-lock.json index dc235ff1..3356ebd9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -32,9 +32,10 @@ "cspell": "6.2.3", "css-loader": "6.7.1", "eslint": "8.20.0", - "eslint-plugin-import": "^2.27.5", + "eslint-plugin-import": "2.27.5", "eslint-plugin-react": "7.32.2", "eslint-plugin-react-hooks": "4.6.0", + "eslint-plugin-simple-import-sort": "10.0.0", "graphql": "16.5.0", "html-webpack-plugin": "5.5.0", "mini-css-extract-plugin": "2.6.0", @@ -6515,6 +6516,15 @@ "semver": "bin/semver.js" } }, + "node_modules/eslint-plugin-simple-import-sort": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-10.0.0.tgz", + "integrity": "sha512-AeTvO9UCMSNzIHRkg8S6c3RPy5YEwKWSQPx3DYghLedo2ZQxowPFLGDN1AZ2evfg6r6mjBSZSLxLFsWSu3acsw==", + "dev": true, + "peerDependencies": { + "eslint": ">=5.0.0" + } + }, "node_modules/eslint-scope": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", @@ -20924,6 +20934,13 @@ "dev": true, "requires": {} }, + "eslint-plugin-simple-import-sort": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-10.0.0.tgz", + "integrity": "sha512-AeTvO9UCMSNzIHRkg8S6c3RPy5YEwKWSQPx3DYghLedo2ZQxowPFLGDN1AZ2evfg6r6mjBSZSLxLFsWSu3acsw==", + "dev": true, + "requires": {} + }, "eslint-scope": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", diff --git a/package.json b/package.json index 4745cd15..8f76d0be 100644 --- a/package.json +++ b/package.json @@ -62,9 +62,10 @@ "cspell": "6.2.3", "css-loader": "6.7.1", "eslint": "8.20.0", - "eslint-plugin-import": "^2.27.5", + "eslint-plugin-import": "2.27.5", "eslint-plugin-react": "7.32.2", "eslint-plugin-react-hooks": "4.6.0", + "eslint-plugin-simple-import-sort": "10.0.0", "graphql": "16.5.0", "html-webpack-plugin": "5.5.0", "mini-css-extract-plugin": "2.6.0", diff --git a/scripts/serve-directory.ts b/scripts/serve-directory.ts index 3ab6708b..ae48c0ec 100644 --- a/scripts/serve-directory.ts +++ b/scripts/serve-directory.ts @@ -1,6 +1,6 @@ // Copied from https://developer.mozilla.org/en-US/docs/Learn/Server-side/Node_server_without_framework -import * as http from 'node:http'; import * as fs from 'node:fs'; +import * as http from 'node:http'; import * as path from 'node:path'; import * as util from 'node:util'; diff --git a/src/components/GraphViewport.tsx b/src/components/GraphViewport.tsx index 04b5091b..9a7ee71e 100644 --- a/src/components/GraphViewport.tsx +++ b/src/components/GraphViewport.tsx @@ -1,7 +1,7 @@ import { Component } from 'react'; -import LoadingAnimation from './utils/LoadingAnimation'; import { Viewport } from './../graph/'; +import LoadingAnimation from './utils/LoadingAnimation'; interface GraphViewportProps { svgRenderer: any; diff --git a/src/components/MUITheme.tsx b/src/components/MUITheme.tsx index bf754804..70c29417 100644 --- a/src/components/MUITheme.tsx +++ b/src/components/MUITheme.tsx @@ -1,5 +1,5 @@ -import { createTheme } from '@mui/material/styles'; import { cyan, grey } from '@mui/material/colors'; +import { createTheme } from '@mui/material/styles'; import variables from './variables.css'; diff --git a/src/components/Voyager.tsx b/src/components/Voyager.tsx index 55f88f15..d8500a70 100644 --- a/src/components/Voyager.tsx +++ b/src/components/Voyager.tsx @@ -1,25 +1,23 @@ -import { getIntrospectionQuery } from 'graphql/utilities'; - -import { getSchema, extractTypeId } from '../introspection'; -import { SVGRender, getTypeGraph } from '../graph/'; +import './Voyager.css'; +import './viewport.css'; +import { ThemeProvider } from '@mui/material/styles'; +import { getIntrospectionQuery } from 'graphql/utilities'; import { - createRef, Children, Component, - type ReactNode, + createRef, type ReactElement, + type ReactNode, } from 'react'; -import { theme } from './MUITheme'; -import { ThemeProvider } from '@mui/material/styles'; -import GraphViewport from './GraphViewport'; +import { getTypeGraph, SVGRender } from '../graph/'; +import { extractTypeId, getSchema } from '../introspection'; import DocExplorer from './doc-explorer/DocExplorer'; -import PoweredBy from './utils/PoweredBy'; +import GraphViewport from './GraphViewport'; +import { theme } from './MUITheme'; import Settings from './settings/Settings'; - -import './Voyager.css'; -import './viewport.css'; +import PoweredBy from './utils/PoweredBy'; type IntrospectionProvider = (query: string) => Promise; diff --git a/src/components/doc-explorer/DocExplorer.tsx b/src/components/doc-explorer/DocExplorer.tsx index 4ec3f2a6..de60fb44 100644 --- a/src/components/doc-explorer/DocExplorer.tsx +++ b/src/components/doc-explorer/DocExplorer.tsx @@ -1,14 +1,14 @@ -import { isNode } from '../../graph'; +import './DocExplorer.css'; import { Component } from 'react'; -import TypeList from './TypeList'; -import TypeDoc from './TypeDoc'; + +import { isNode } from '../../graph'; +import SearchBox from '../utils/SearchBox'; import FocusTypeButton from './FocusTypeButton'; -import TypeInfoPopover from './TypeInfoPopover'; import OtherSearchResults from './OtherSearchResults'; -import SearchBox from '../utils/SearchBox'; - -import './DocExplorer.css'; +import TypeDoc from './TypeDoc'; +import TypeInfoPopover from './TypeInfoPopover'; +import TypeList from './TypeList'; interface DocExplorerProps { typeGraph: any; diff --git a/src/components/doc-explorer/FocusTypeButton.tsx b/src/components/doc-explorer/FocusTypeButton.tsx index acf27a72..2ceb27b0 100644 --- a/src/components/doc-explorer/FocusTypeButton.tsx +++ b/src/components/doc-explorer/FocusTypeButton.tsx @@ -1,7 +1,8 @@ +import './FocusTypeButton.css'; + import IconButton from '@mui/material/IconButton'; -import EyeIcon from '../icons/remove-red-eye.svg'; -import './FocusTypeButton.css'; +import EyeIcon from '../icons/remove-red-eye.svg'; function FocusTypeButton(props: { onClick: () => void }) { return ( diff --git a/src/components/doc-explorer/OtherSearchResults.tsx b/src/components/doc-explorer/OtherSearchResults.tsx index 2789068f..8372b615 100644 --- a/src/components/doc-explorer/OtherSearchResults.tsx +++ b/src/components/doc-explorer/OtherSearchResults.tsx @@ -1,4 +1,4 @@ -import { isMatch, highlightTerm } from '../../utils'; +import { highlightTerm, isMatch } from '../../utils'; interface OtherSearchResultsProps { typeGraph: any; diff --git a/src/components/doc-explorer/TypeDetails.tsx b/src/components/doc-explorer/TypeDetails.tsx index 85111f3b..cbd62a3b 100644 --- a/src/components/doc-explorer/TypeDetails.tsx +++ b/src/components/doc-explorer/TypeDetails.tsx @@ -1,10 +1,10 @@ -import { SimplifiedTypeWithIDs } from '../../introspection/types'; import * as _ from 'lodash'; +import { SimplifiedTypeWithIDs } from '../../introspection/types'; import Markdown from '../utils/Markdown'; import Description from './Description'; -import WrappedTypeName from './WrappedTypeName'; import EnumValue from './EnumValue'; +import WrappedTypeName from './WrappedTypeName'; interface TypeDetailsProps { type: SimplifiedTypeWithIDs; diff --git a/src/components/doc-explorer/TypeDoc.tsx b/src/components/doc-explorer/TypeDoc.tsx index 92cd0afd..2dcba0ae 100644 --- a/src/components/doc-explorer/TypeDoc.tsx +++ b/src/components/doc-explorer/TypeDoc.tsx @@ -1,16 +1,15 @@ +import './TypeDoc.css'; + import * as _ from 'lodash'; import { Component } from 'react'; -import './TypeDoc.css'; - import { SimplifiedTypeWithIDs } from '../../introspection/types'; -import { isMatch, highlightTerm } from '../../utils'; - +import { highlightTerm, isMatch } from '../../utils'; import Markdown from '../utils/Markdown'; +import Argument from './Argument'; import Description from './Description'; import TypeLink from './TypeLink'; import WrappedTypeName from './WrappedTypeName'; -import Argument from './Argument'; interface TypeDocProps { selectedType: any; diff --git a/src/components/doc-explorer/TypeInfoPopover.tsx b/src/components/doc-explorer/TypeInfoPopover.tsx index 86621313..2fa4662c 100644 --- a/src/components/doc-explorer/TypeInfoPopover.tsx +++ b/src/components/doc-explorer/TypeInfoPopover.tsx @@ -1,11 +1,10 @@ -import { Component } from 'react'; - import './TypeInfoPopover.css'; -import CloseIcon from '../icons/close-black.svg'; import IconButton from '@mui/material/IconButton'; +import { Component } from 'react'; import TypeDetails from '../doc-explorer/TypeDetails'; +import CloseIcon from '../icons/close-black.svg'; interface ScalarDetailsProps { type: any; diff --git a/src/components/doc-explorer/TypeLink.tsx b/src/components/doc-explorer/TypeLink.tsx index 6e6ab735..0137646a 100644 --- a/src/components/doc-explorer/TypeLink.tsx +++ b/src/components/doc-explorer/TypeLink.tsx @@ -1,12 +1,12 @@ +import './TypeLink.css'; + import { isBuiltInScalarType, - isScalarType, isInputObjectType, + isScalarType, } from '../../introspection'; import { highlightTerm } from '../../utils'; -import './TypeLink.css'; - interface TypeLinkProps { type: { name: string; diff --git a/src/components/doc-explorer/TypeList.tsx b/src/components/doc-explorer/TypeList.tsx index ac830444..6cf55ed0 100644 --- a/src/components/doc-explorer/TypeList.tsx +++ b/src/components/doc-explorer/TypeList.tsx @@ -1,11 +1,11 @@ -import * as _ from 'lodash'; -import { isMatch } from '../../utils'; - import './TypeList.css'; -import TypeLink from './TypeLink'; +import * as _ from 'lodash'; + +import { isMatch } from '../../utils'; import Description from './Description'; import FocusTypeButton from './FocusTypeButton'; +import TypeLink from './TypeLink'; interface TypeListProps { typeGraph: any; diff --git a/src/components/doc-explorer/WrappedTypeName.tsx b/src/components/doc-explorer/WrappedTypeName.tsx index b6dba762..43e4dc43 100644 --- a/src/components/doc-explorer/WrappedTypeName.tsx +++ b/src/components/doc-explorer/WrappedTypeName.tsx @@ -1,11 +1,11 @@ -import Tooltip from '@mui/material/Tooltip'; -import IconButton from '@mui/material/IconButton'; import './WrappedTypeName.css'; -import { stringifyWrappers } from '../../introspection/'; -import TypeLink from './TypeLink'; +import IconButton from '@mui/material/IconButton'; +import Tooltip from '@mui/material/Tooltip'; +import { stringifyWrappers } from '../../introspection/'; import RelayIcon from '../icons/relay-icon.svg'; +import TypeLink from './TypeLink'; interface WrappedTypeNameProps { container: any; diff --git a/src/components/settings/RootSelector.tsx b/src/components/settings/RootSelector.tsx index ba482ee2..0fb6b1a8 100644 --- a/src/components/settings/RootSelector.tsx +++ b/src/components/settings/RootSelector.tsx @@ -1,7 +1,7 @@ -import { isNode, getDefaultRoot } from '../../graph/'; - -import Select from '@mui/material/Select'; import MenuItem from '@mui/material/MenuItem'; +import Select from '@mui/material/Select'; + +import { getDefaultRoot, isNode } from '../../graph/'; interface RootSelectorProps { rootType?: string; diff --git a/src/components/settings/Settings.tsx b/src/components/settings/Settings.tsx index 0d6afebf..42519b05 100644 --- a/src/components/settings/Settings.tsx +++ b/src/components/settings/Settings.tsx @@ -1,4 +1,5 @@ import Checkbox from '@mui/material/Checkbox'; + import RootSelector from './RootSelector'; interface SettingsProps { diff --git a/src/components/utils/Markdown.tsx b/src/components/utils/Markdown.tsx index 11f25005..7e12c32b 100644 --- a/src/components/utils/Markdown.tsx +++ b/src/components/utils/Markdown.tsx @@ -1,5 +1,5 @@ -import { Component } from 'react'; import { HtmlRenderer, Parser } from 'commonmark'; +import { Component } from 'react'; interface MarkdownProps { text: string; diff --git a/src/components/utils/SearchBox.tsx b/src/components/utils/SearchBox.tsx index 39efd7d4..087d0ef8 100644 --- a/src/components/utils/SearchBox.tsx +++ b/src/components/utils/SearchBox.tsx @@ -1,8 +1,8 @@ -import { Component } from 'react'; +import './SearchBox.css'; + import Input from '@mui/material/Input'; import InputAdornment from '@mui/material/InputAdornment'; - -import './SearchBox.css'; +import { Component } from 'react'; interface SearchBoxProps { placeholder: string; diff --git a/src/graph/dot.ts b/src/graph/dot.ts index 45f1575e..32e6a335 100644 --- a/src/graph/dot.ts +++ b/src/graph/dot.ts @@ -1,6 +1,7 @@ -import { stringifyWrappers } from '../introspection/'; import * as _ from 'lodash'; +import { stringifyWrappers } from '../introspection/'; + export function getDot(typeGraph, displayOptions): string { function isNode(type) { return typeGraph.nodes[type.id] !== undefined; diff --git a/src/graph/index.ts b/src/graph/index.ts index da639c6c..0d367ad0 100644 --- a/src/graph/index.ts +++ b/src/graph/index.ts @@ -1,4 +1,4 @@ +export * from './dot'; +export * from './svg-renderer'; export * from './type-graph'; export * from './viewport'; -export * from './svg-renderer'; -export * from './dot'; diff --git a/src/graph/svg-renderer.ts b/src/graph/svg-renderer.ts index 0113f28d..3cbbb0b6 100644 --- a/src/graph/svg-renderer.ts +++ b/src/graph/svg-renderer.ts @@ -1,8 +1,7 @@ -import { getDot } from './dot'; - // eslint-disable-next-line import/no-unresolved import VizWorker from '../../worker/voyager.worker.js'; import { stringToSvg } from '../utils/'; +import { getDot } from './dot'; const RelayIconSvg = require('!!svg-as-symbol-loader?id=RelayIcon!../components/icons/relay-icon.svg'); const DeprecatedIconSvg = require('!!svg-as-symbol-loader?id=DeprecatedIcon!../components/icons/deprecated-icon.svg'); diff --git a/src/graph/type-graph.ts b/src/graph/type-graph.ts index 735a5631..c2999591 100644 --- a/src/graph/type-graph.ts +++ b/src/graph/type-graph.ts @@ -1,9 +1,10 @@ import * as _ from 'lodash'; + import { - typeNameToId, - isScalarType, isInputObjectType, + isScalarType, isSystemType, + typeNameToId, } from '../introspection/'; export function isNode(type) { diff --git a/src/graph/viewport.ts b/src/graph/viewport.ts index 25bd1e64..5086110b 100644 --- a/src/graph/viewport.ts +++ b/src/graph/viewport.ts @@ -1,7 +1,7 @@ import * as svgPanZoom from 'svg-pan-zoom'; -import { stringToSvg } from '../utils/'; import { typeNameToId } from '../introspection'; +import { stringToSvg } from '../utils/'; // FIXME: we are waiting for this [PR](https://github.com/ariutta/svg-pan-zoom/pull/379), after that this two interfaces might be removed in favor to `import { Instance, Point } from 'svg-pan-zoom'` interface Point { diff --git a/src/index.tsx b/src/index.tsx index ca920da3..84564d62 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,8 +1,9 @@ import * as ReactDOM from 'react-dom'; + import { Voyager, VoyagerProps } from './components'; function init(element: HTMLElement, options: VoyagerProps) { ReactDOM.render(, element); } -export { Voyager as GraphQLVoyager, Voyager, init }; +export { Voyager as GraphQLVoyager, init, Voyager }; diff --git a/src/introspection/introspection.ts b/src/introspection/introspection.ts index e2b5b193..0bdcb950 100644 --- a/src/introspection/introspection.ts +++ b/src/introspection/introspection.ts @@ -1,27 +1,28 @@ -import * as _ from 'lodash'; import { - GraphQLNamedType, - GraphQLSchema, + buildClientSchema, GraphQLArgument, - GraphQLInputField, GraphQLField, - isWrappingType, - isNonNullType, - isUnionType, + GraphQLInputField, + GraphQLNamedType, + GraphQLSchema, isEnumType, isInputObjectType, - isObjectType, isInterfaceType, + isNonNullType, + isObjectType, isScalarType, - buildClientSchema, + isUnionType, + isWrappingType, lexicographicSortSchema, } from 'graphql'; +import * as _ from 'lodash'; + import { + SimplifiedField, + SimplifiedInputField, SimplifiedIntrospection, SimplifiedIntrospectionWithIds, SimplifiedType, - SimplifiedInputField, - SimplifiedField, } from './types'; import { typeNameToId } from './utils'; diff --git a/tests/demo.spec.ts b/tests/demo.spec.ts index 9b37404e..30cc8ac1 100644 --- a/tests/demo.spec.ts +++ b/tests/demo.spec.ts @@ -1,5 +1,4 @@ -import { test, expect, type Page, type Locator } from '@playwright/test'; - +import { expect, type Locator, type Page, test } from '@playwright/test'; import { buildSchema, graphqlSync } from 'graphql'; interface VoyagerURLSearchParams { diff --git a/webpack-demo.config.ts b/webpack-demo.config.ts index 4069d854..5fcb3ae8 100644 --- a/webpack-demo.config.ts +++ b/webpack-demo.config.ts @@ -1,12 +1,12 @@ -import * as path from 'node:path'; - import 'webpack-dev-server'; -import * as webpack from 'webpack'; -import * as HtmlWebpackPlugin from 'html-webpack-plugin'; -import * as MiniCssExtractPlugin from 'mini-css-extract-plugin'; + +import * as path from 'node:path'; // eslint-disable-next-line import/namespace import * as CopyWebpackPlugin from 'copy-webpack-plugin'; +import * as HtmlWebpackPlugin from 'html-webpack-plugin'; +import * as MiniCssExtractPlugin from 'mini-css-extract-plugin'; +import * as webpack from 'webpack'; export default function buildWebpackConfig(): webpack.Configuration { return { diff --git a/webpack.config.ts b/webpack.config.ts index 835418c8..5d4a8d39 100644 --- a/webpack.config.ts +++ b/webpack.config.ts @@ -1,7 +1,7 @@ import * as path from 'node:path'; -import * as webpack from 'webpack'; import * as MiniCssExtractPlugin from 'mini-css-extract-plugin'; +import * as webpack from 'webpack'; import * as NodeExternals from 'webpack-node-externals'; const packageJSON = require('./package.json');