├── .changeset ├── README.md └── config.json ├── .codesandbox └── ci.json ├── .editorconfig ├── .eslint-doc-generatorrc.mjs ├── .eslintignore ├── .eslintrc.js ├── .github └── workflows │ ├── ci.yml │ ├── codeql.yml │ └── release.yml ├── .gitignore ├── .prettierignore ├── .prettierrc.mjs ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── babel.config.js ├── docs └── rules │ ├── consistent-type-specifier-style.md │ ├── default.md │ ├── dynamic-import-chunkname.md │ ├── export.md │ ├── exports-last.md │ ├── extensions.md │ ├── first.md │ ├── group-exports.md │ ├── imports-first.md │ ├── max-dependencies.md │ ├── named.md │ ├── namespace.md │ ├── newline-after-import.md │ ├── no-absolute-path.md │ ├── no-amd.md │ ├── no-anonymous-default-export.md │ ├── no-commonjs.md │ ├── no-cycle.md │ ├── no-default-export.md │ ├── no-deprecated.md │ ├── no-duplicates.md │ ├── no-dynamic-require.md │ ├── no-empty-named-blocks.md │ ├── no-extraneous-dependencies.md │ ├── no-import-module-exports.md │ ├── no-internal-modules.md │ ├── no-mutable-exports.md │ ├── no-named-as-default-member.md │ ├── no-named-as-default.md │ ├── no-named-default.md │ ├── no-named-export.md │ ├── no-namespace.md │ ├── no-nodejs-modules.md │ ├── no-relative-packages.md │ ├── no-relative-parent-imports.md │ ├── no-restricted-paths.md │ ├── no-self-import.md │ ├── no-unassigned-import.md │ ├── no-unresolved.md │ ├── no-unused-modules.md │ ├── no-useless-path-segments.md │ ├── no-webpack-loader-syntax.md │ ├── order.md │ ├── prefer-default-export.md │ └── unambiguous.md ├── jest.config.ts ├── package.json ├── patches └── @typescript-eslint+utils+5.62.0.patch ├── src ├── config │ ├── electron.ts │ ├── errors.ts │ ├── react-native.ts │ ├── react.ts │ ├── recommended.ts │ ├── stage-0.ts │ ├── typescript.ts │ └── warnings.ts ├── global.d.ts ├── index.ts ├── rules │ ├── consistent-type-specifier-style.ts │ ├── default.ts │ ├── dynamic-import-chunkname.ts │ ├── export.ts │ ├── exports-last.ts │ ├── extensions.ts │ ├── first.ts │ ├── group-exports.ts │ ├── imports-first.ts │ ├── max-dependencies.ts │ ├── named.ts │ ├── namespace.ts │ ├── newline-after-import.ts │ ├── no-absolute-path.ts │ ├── no-amd.ts │ ├── no-anonymous-default-export.ts │ ├── no-commonjs.ts │ ├── no-cycle.ts │ ├── no-default-export.ts │ ├── no-deprecated.ts │ ├── no-duplicates.ts │ ├── no-dynamic-require.ts │ ├── no-empty-named-blocks.ts │ ├── no-extraneous-dependencies.ts │ ├── no-import-module-exports.ts │ ├── no-internal-modules.ts │ ├── no-mutable-exports.ts │ ├── no-named-as-default-member.ts │ ├── no-named-as-default.ts │ ├── no-named-default.ts │ ├── no-named-export.ts │ ├── no-namespace.ts │ ├── no-nodejs-modules.ts │ ├── no-relative-packages.ts │ ├── no-relative-parent-imports.ts │ ├── no-restricted-paths.ts │ ├── no-self-import.ts │ ├── no-unassigned-import.ts │ ├── no-unresolved.ts │ ├── no-unused-modules.ts │ ├── no-useless-path-segments.ts │ ├── no-webpack-loader-syntax.ts │ ├── order.ts │ ├── prefer-default-export.ts │ └── unambiguous.ts ├── tsconfig.json ├── types.ts └── utils │ ├── constants.ts │ ├── create-rule.ts │ ├── declared-scope.ts │ ├── docs-url.ts │ ├── export-map.ts │ ├── hash.ts │ ├── ignore.ts │ ├── import-declaration.ts │ ├── import-type.ts │ ├── index.ts │ ├── module-cache.ts │ ├── module-require.ts │ ├── module-visitor.ts │ ├── package-path.ts │ ├── parse.ts │ ├── pkg-dir.ts │ ├── pkg-up.ts │ ├── read-pkg-up.ts │ ├── resolve.ts │ ├── static-require.ts │ ├── unambiguous.ts │ └── visit.ts ├── test ├── cli.spec.ts ├── config │ └── typescript.spec.ts ├── fixtures │ ├── .eslintrc.js │ ├── @importType │ │ └── index.js │ ├── @my-alias │ │ └── fn.js │ ├── CaseyKasem.js │ ├── alternate-root │ │ └── in-alternate-root.js │ ├── bar.coffee │ ├── bar.js │ ├── bar.json │ ├── bar.jsx │ ├── bar │ │ └── index.js │ ├── broken-trampoline.js │ ├── bundled-dependencies │ │ ├── as-array-bundle-deps │ │ │ ├── node_modules │ │ │ │ └── @generated │ │ │ │ │ ├── bar │ │ │ │ │ └── index.js │ │ │ │ │ └── foo │ │ │ │ │ └── index.js │ │ │ └── package.json │ │ ├── as-object │ │ │ ├── node_modules │ │ │ │ └── @generated │ │ │ │ │ ├── bar │ │ │ │ │ └── index.js │ │ │ │ │ └── foo │ │ │ │ │ └── index.js │ │ │ └── package.json │ │ └── race-condition │ │ │ ├── node_modules │ │ │ └── @generated │ │ │ │ ├── bar │ │ │ │ └── index.js │ │ │ │ └── foo │ │ │ │ └── index.js │ │ │ └── package.json │ ├── color.js │ ├── common-module.js │ ├── common.js │ ├── commonjs-namespace │ │ ├── a.js │ │ └── b.js │ ├── component.html │ ├── constants │ │ └── index.js │ ├── cycles │ │ ├── depth-zero.js │ │ ├── es6 │ │ │ ├── depth-one-dynamic.js │ │ │ ├── depth-one-reexport.js │ │ │ ├── depth-one.js │ │ │ ├── depth-three-indirect.js │ │ │ ├── depth-three-star.js │ │ │ └── depth-two.js │ │ ├── external-depth-two.js │ │ ├── external │ │ │ └── depth-one.js │ │ ├── flow-typeof.js │ │ ├── flow-types-depth-one.js │ │ ├── flow-types-depth-two.js │ │ ├── flow-types-only-importing-multiple-types.js │ │ ├── flow-types-only-importing-type.js │ │ ├── flow-types-some-type-imports.js │ │ ├── flow-types.js │ │ ├── ignore │ │ │ ├── .eslintrc │ │ │ └── index.js │ │ └── intermediate-ignore.js │ ├── data.json │ ├── deep-deprecated.js │ ├── deep-es7 │ │ ├── a.js │ │ ├── b.js │ │ ├── c.js │ │ └── d.js │ ├── deep │ │ ├── a.js │ │ ├── b.js │ │ ├── c.js │ │ ├── cache-1.js │ │ ├── cache-2a.js │ │ ├── cache-2b.js │ │ ├── d.js │ │ └── default.js │ ├── default-class.js │ ├── default-export-default-property.js │ ├── default-export-from-ignored.js │ ├── default-export-from-named.js │ ├── default-export-from.js │ ├── default-export-namespace-string.js │ ├── default-export-string.js │ ├── default-export.js │ ├── deprecated-file.js │ ├── deprecated.js │ ├── dynamic-import-in-commonjs.js │ ├── empty-folder │ │ └── anchor.txt │ ├── empty-named-blocks.js │ ├── empty │ │ └── package.json │ ├── export-all.js │ ├── export-default-string-and-named.js │ ├── export-props.js │ ├── export-star-2 │ │ ├── middle.js │ │ └── upstream.js │ ├── export-star-3 │ │ ├── b.ts │ │ └── c.ts │ ├── export-star-4 │ │ └── module │ │ │ ├── feature.jsx │ │ │ └── index.ts │ ├── export-star │ │ ├── extfield.js │ │ ├── extfield2.js │ │ └── models.js │ ├── exports-calc-keys.js │ ├── exports-missing.js │ ├── file.with.dot.js │ ├── flowtypes.js │ ├── foo-bar-resolver-invalid.js │ ├── foo-bar-resolver-no-version.js │ ├── foo-bar-resolver-v1.js │ ├── foo-bar-resolver-v2.js │ ├── foobar.json │ ├── ignore.invalid.extension │ ├── importType │ │ └── index.js │ ├── index.js │ ├── internal-modules │ │ ├── api │ │ │ └── service │ │ │ │ └── index.js │ │ ├── package.json │ │ ├── plugins │ │ │ ├── plugin.js │ │ │ └── plugin2 │ │ │ │ ├── app │ │ │ │ └── index.js │ │ │ │ ├── index.js │ │ │ │ └── internal.js │ │ ├── test.js │ │ └── typescript │ │ │ ├── plugin2 │ │ │ ├── app │ │ │ │ └── index.ts │ │ │ ├── index.ts │ │ │ └── internal.ts │ │ │ └── plugins.ts │ ├── issue-195 │ │ ├── Bookings.js │ │ ├── Endpoints.js │ │ └── Users.js │ ├── issue-370-commonjs-namespace │ │ ├── bar.js │ │ └── foo.js │ ├── issue210.config.js │ ├── issue210.js │ ├── jsx.js │ ├── jsx │ │ ├── AnotherComponent.jsx │ │ ├── App.js │ │ ├── FooES7.js │ │ ├── MyCoolComponent.jsx │ │ ├── MyUnCoolComponent.jsx │ │ ├── bar │ │ │ ├── baz.jsx │ │ │ ├── index.js │ │ │ └── qux.jsx │ │ ├── named.jsx │ │ └── re-export.js │ ├── just-json-files │ │ ├── .eslintrc.json │ │ └── invalid.json │ ├── load-error-resolver.js │ ├── malformed.js │ ├── missing-entrypoint │ │ └── package.json │ ├── mixed-exports.js │ ├── monorepo │ │ ├── package.json │ │ └── packages │ │ │ └── nested-package │ │ │ └── package.json │ ├── mutator.js │ ├── named-default-export.js │ ├── named-export-collision │ │ ├── a.js │ │ └── b.js │ ├── named-exports.js │ ├── named-trampoline.js │ ├── narcissist.js │ ├── nested-common.js │ ├── no-self-import-folder │ │ └── index.js │ ├── no-self-import.js │ ├── no-unused-modules │ │ ├── arbitrary-module-namespace-identifier-name-a.js │ │ ├── arbitrary-module-namespace-identifier-name-b.js │ │ ├── arbitrary-module-namespace-identifier-name-c.js │ │ ├── bin.js │ │ ├── binObject │ │ │ ├── index.js │ │ │ └── package.json │ │ ├── browser.js │ │ ├── browserObject │ │ │ ├── index.js │ │ │ └── package.json │ │ ├── cjs.js │ │ ├── destructuring-a.js │ │ ├── destructuring-b.js │ │ ├── dynamic-import-js-2.js │ │ ├── dynamic-import-js.js │ │ ├── empty_file.js │ │ ├── exports-for-dynamic-js-2.js │ │ ├── exports-for-dynamic-js.js │ │ ├── file-0.js │ │ ├── file-a.js │ │ ├── file-b.js │ │ ├── file-c.js │ │ ├── file-d.js │ │ ├── file-destructured-1.js │ │ ├── file-destructured-2.js │ │ ├── file-e.js │ │ ├── file-f.js │ │ ├── file-g.js │ │ ├── file-h.js │ │ ├── file-i.js │ │ ├── file-ignored-a.js │ │ ├── file-ignored-b.js │ │ ├── file-ignored-c.js │ │ ├── file-ignored-d.js │ │ ├── file-ignored-e.js │ │ ├── file-ignored-l.js │ │ ├── file-j.js │ │ ├── file-k.js │ │ ├── file-l.js │ │ ├── file-m.js │ │ ├── file-n.js │ │ ├── file-o.js │ │ ├── file-p.js │ │ ├── file-q.js │ │ ├── file-s.js │ │ ├── filte-r.js │ │ ├── flow │ │ │ ├── flow-0.js │ │ │ ├── flow-1.js │ │ │ ├── flow-2.js │ │ │ ├── flow-3.js │ │ │ └── flow-4.js │ │ ├── import-export-1.js │ │ ├── import-export-2.js │ │ ├── jsx │ │ │ ├── file-jsx-a.jsx │ │ │ └── file-jsx-b.jsx │ │ ├── main │ │ │ └── index.js │ │ ├── node_modules.js │ │ ├── package.json │ │ ├── prefix-child.js │ │ ├── prefix-parent-bom.js │ │ ├── prefix-parent-bomhashbang.js │ │ ├── prefix-parent-hashbang.js │ │ ├── prefix-parent.js │ │ ├── privatePkg │ │ │ ├── index.js │ │ │ └── package.json │ │ ├── renameDefault-2 │ │ │ ├── ComponentA.js │ │ │ ├── ComponentB.js │ │ │ ├── components.js │ │ │ └── usage.js │ │ ├── renameDefault │ │ │ ├── Component.js │ │ │ ├── components.js │ │ │ └── usage.js │ │ └── typescript │ │ │ ├── dynamic-import-ts.ts │ │ │ ├── exports-for-dynamic-ts.ts │ │ │ ├── file-ts-a-import-type.ts │ │ │ ├── file-ts-a.ts │ │ │ ├── file-ts-b-unused.ts │ │ │ ├── file-ts-b-used-as-type.ts │ │ │ ├── file-ts-b.ts │ │ │ ├── file-ts-c-unused.ts │ │ │ ├── file-ts-c-used-as-type.ts │ │ │ ├── file-ts-c.ts │ │ │ ├── file-ts-d-unused.ts │ │ │ ├── file-ts-d-used-as-type.ts │ │ │ ├── file-ts-d.ts │ │ │ ├── file-ts-e-unused.ts │ │ │ ├── file-ts-e-used-as-type.ts │ │ │ ├── file-ts-e.ts │ │ │ ├── file-ts-f-import-type.ts │ │ │ ├── file-ts-f.ts │ │ │ ├── file-ts-g-used-as-type.ts │ │ │ └── file-ts-g.ts │ ├── node_modules │ │ ├── @generated │ │ │ ├── bar │ │ │ │ ├── index.js │ │ │ │ └── package.json │ │ │ └── foo │ │ │ │ ├── index.js │ │ │ │ └── package.json │ │ ├── @org │ │ │ ├── not-a-dependency │ │ │ │ ├── foo.js │ │ │ │ ├── index.js │ │ │ │ └── package.json │ │ │ └── package │ │ │ │ ├── index.js │ │ │ │ ├── internal.js │ │ │ │ └── package.json │ │ ├── a │ │ │ ├── index.js │ │ │ └── package.json │ │ ├── es6-module │ │ │ ├── index.js │ │ │ └── package.json │ │ ├── eslint-import-resolver-foo │ │ │ ├── index.js │ │ │ └── package.json │ │ ├── esm-package-not-in-pkg-json │ │ │ ├── esm-module │ │ │ │ ├── index.js │ │ │ │ └── package.json │ │ │ ├── index.js │ │ │ └── package.json │ │ ├── esm-package │ │ │ ├── esm-module │ │ │ │ ├── index.js │ │ │ │ └── package.json │ │ │ ├── index.js │ │ │ └── package.json │ │ ├── exceljs │ │ │ ├── excel.js │ │ │ └── package.json │ │ ├── jest │ │ │ ├── index.js │ │ │ └── package.json │ │ ├── jquery │ │ │ └── package.json │ │ ├── jsx-module │ │ │ ├── foo.jsx │ │ │ └── package.json │ │ ├── left-pad │ │ │ ├── index.js │ │ │ ├── not-a-dependency │ │ │ └── package.json │ │ ├── not-a-dependency │ │ │ ├── index.js │ │ │ └── package.json │ │ ├── react │ │ │ ├── index.js │ │ │ ├── not-a-dependency │ │ │ └── package.json │ │ └── rxjs │ │ │ ├── index.js │ │ │ ├── operators │ │ │ ├── index.js │ │ │ └── package.json │ │ │ └── package.json │ ├── order-redirect-scoped │ │ ├── module │ │ │ └── package.json │ │ ├── other-module │ │ │ └── file.js │ │ └── package.json │ ├── order-redirect │ │ ├── module │ │ │ └── package.json │ │ ├── other-module │ │ │ └── file.js │ │ └── package.json │ ├── package-named │ │ ├── index.js │ │ └── package.json │ ├── package-scoped │ │ ├── index.js │ │ └── package.json │ ├── package.json │ ├── package │ │ ├── index.js │ │ └── package.json │ ├── qc.js │ ├── re-export-common-star.js │ ├── re-export-common.js │ ├── re-export-default.js │ ├── re-export-names.js │ ├── re-export-node_modules.js │ ├── re-export.js │ ├── redux.js │ ├── restricted-paths │ │ ├── client │ │ │ ├── a.js │ │ │ └── one │ │ │ │ └── a.js │ │ └── server │ │ │ ├── b.js │ │ │ ├── c.js │ │ │ ├── c.ts │ │ │ ├── one │ │ │ ├── a.js │ │ │ └── b.js │ │ │ ├── three │ │ │ └── a.js │ │ │ ├── two-new │ │ │ └── a.js │ │ │ └── two │ │ │ └── a.js │ ├── sibling-with-names.js │ ├── src-root │ │ └── src-bar.js │ ├── symlinked-module │ │ ├── index.js │ │ └── package.json │ ├── test-module │ │ └── index.js │ ├── test.coffee │ ├── test.giffy │ ├── tomdoc-deprecated.js │ ├── trampoline.js │ ├── ts-deprecated.ts │ ├── typescript-d-ts │ │ ├── .eslintrc │ │ ├── file1.ts │ │ └── file2.ts │ ├── typescript-declare-interface.d.ts │ ├── typescript-declare-module.ts │ ├── typescript-declare-nested.d.ts │ ├── typescript-declare.d.ts │ ├── typescript-default.ts │ ├── typescript-export-as-default-namespace │ │ ├── index.d.ts │ │ └── tsconfig.json │ ├── typescript-export-assign-default-namespace │ │ ├── index.d.ts │ │ └── tsconfig.json │ ├── typescript-export-assign-default-reexport.ts │ ├── typescript-export-assign-default.d.ts │ ├── typescript-export-assign-function.ts │ ├── typescript-export-assign-mixed.d.ts │ ├── typescript-export-assign-namespace-merged.d.ts │ ├── typescript-export-assign-namespace.d.ts │ ├── typescript-export-assign-object │ │ ├── index.ts │ │ └── tsconfig.json │ ├── typescript-export-assign-property.ts │ ├── typescript-export-react-test-renderer │ │ ├── index.d.ts │ │ └── tsconfig.json │ ├── typescript-extended-config │ │ ├── index.d.ts │ │ ├── tsconfig.base.json │ │ └── tsconfig.json │ ├── typescript-no-compiler-options │ │ ├── index.d.ts │ │ └── tsconfig.json │ ├── typescript.ts │ ├── umd.js │ ├── unused-modules-reexport-crash │ │ └── src │ │ │ ├── App.tsx │ │ │ ├── index.tsx │ │ │ └── magic │ │ │ ├── index.js │ │ │ └── test.js │ ├── webpack.config.js │ ├── webpack.empty.config.js │ ├── with-flow-typed │ │ ├── flow-typed │ │ │ └── npm │ │ │ │ └── myflowtyped_v1.x.x.js │ │ └── package.json │ ├── with-syntax-error │ │ └── package.json │ └── with-typescript-dev-dependencies │ │ └── package.json ├── index.js ├── package.spec.ts ├── rules │ ├── consistent-type-specifier-style.spec.ts │ ├── default.spec.ts │ ├── dynamic-import-chunkname.spec.ts │ ├── export.spec.ts │ ├── exports-last.spec.ts │ ├── extensions.spec.ts │ ├── first.spec.ts │ ├── group-exports.spec.ts │ ├── max-dependencies.spec.ts │ ├── named.spec.ts │ ├── namespace.spec.ts │ ├── newline-after-import.spec.ts │ ├── no-absolute-path.spec.ts │ ├── no-amd.spec.ts │ ├── no-anonymous-default-export.spec.ts │ ├── no-commonjs.spec.ts │ ├── no-cycle.spec.ts │ ├── no-default-export.spec.ts │ ├── no-deprecated.spec.ts │ ├── no-duplicates.spec.ts │ ├── no-dynamic-require.spec.ts │ ├── no-empty-named-blocks.spec.ts │ ├── no-extraneous-dependencies.spec.ts │ ├── no-import-module-exports.spec.ts │ ├── no-internal-modules.spec.ts │ ├── no-mutable-exports.spec.ts │ ├── no-named-as-default-member.spec.ts │ ├── no-named-as-default.spec.ts │ ├── no-named-default.spec.ts │ ├── no-named-export.spec.ts │ ├── no-namespace.spec.ts │ ├── no-nodejs-modules.spec.ts │ ├── no-relative-packages.spec.ts │ ├── no-relative-parent-imports.spec.ts │ ├── no-restricted-paths.spec.ts │ ├── no-self-import.spec.ts │ ├── no-unassigned-import.spec.ts │ ├── no-unresolved.spec.ts │ ├── no-unused-modules.spec.ts │ ├── no-useless-path-segments.spec.ts │ ├── no-webpack-loader-syntax.spec.ts │ ├── order.spec.ts │ ├── prefer-default-export.spec.ts │ └── unambiguous.spec.ts ├── tsconfig.json ├── utils.ts └── utils │ ├── docs-url.spec.ts │ ├── eslint-parser.ts │ ├── export-map.spec.ts │ ├── hash.spec.ts │ ├── ignore.spec.ts │ ├── import-type.spec.ts │ ├── parse-stub-parser.ts │ ├── parse.spec.ts │ └── resolve.spec.ts ├── tsconfig.base.json └── yarn.lock /.changeset/README.md: -------------------------------------------------------------------------------- 1 | # Changesets 2 | 3 | Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works 4 | with multi-package repos, or single-package repos to help you version and publish your code. You can 5 | find the full documentation for it [in our repository](https://github.com/changesets/changesets) 6 | 7 | We have a quick list of common questions to get you started engaging with this project in 8 | [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md) 9 | -------------------------------------------------------------------------------- /.changeset/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/@changesets/config/schema.json", 3 | "changelog": [ 4 | "@changesets/changelog-github", 5 | { 6 | "repo": "un-ts/eslint-plugin-import-x" 7 | } 8 | ], 9 | "commit": false, 10 | "fixed": [], 11 | "access": "public", 12 | "baseBranch": "master", 13 | "updateInternalDependencies": "patch", 14 | "ignore": [] 15 | } 16 | -------------------------------------------------------------------------------- /.codesandbox/ci.json: -------------------------------------------------------------------------------- 1 | { 2 | "node": "18", 3 | "installCommand": "codesandbox:install", 4 | "sandboxes": [] 5 | } 6 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root=true 2 | 3 | [*] 4 | charset=utf-8 5 | trim_trailing_whitespace=true 6 | insert_final_newline=true 7 | indent_style=space 8 | indent_size=2 9 | end_of_line=lf 10 | -------------------------------------------------------------------------------- /.eslint-doc-generatorrc.mjs: -------------------------------------------------------------------------------- 1 | import prettier from 'prettier' 2 | 3 | import prettierRC from './.prettierrc.mjs' 4 | 5 | /** @type {import('eslint-doc-generator').GenerateOptions} */ 6 | const config = { 7 | postprocess: (content, path) => 8 | prettier.format(content, { ...prettierRC, parser: 'markdown' }), 9 | } 10 | 11 | export default config 12 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | lib 2 | coverage 3 | node_modules 4 | test/fixtures/malformed.js 5 | test/fixtures/with-syntax-error 6 | test/fixtures/just-json-files/invalid.json 7 | test/fixtures/typescript-d-ts/ 8 | # we want to ignore "test/fixtures" here, but unfortunately doing so would 9 | # interfere with unit test and fail it for some reason. 10 | # test/fixtures 11 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | - push 5 | - pull_request 6 | 7 | jobs: 8 | ci: 9 | name: Lint and Test with Node.js ${{ matrix.node }} and ESLint ${{ matrix.eslint }} on ${{ matrix.os }} 10 | strategy: 11 | matrix: 12 | os: 13 | - macos-latest 14 | - ubuntu-latest 15 | # - windows-latest 16 | node: 17 | - 16 18 | - 18 19 | - 20 20 | eslint: 21 | - 7.2 22 | - 7 23 | - 8 24 | runs-on: ${{ matrix.os }} 25 | steps: 26 | - name: Checkout Repo 27 | uses: actions/checkout@v4 28 | 29 | - name: Enable Corepack 30 | run: corepack enable 31 | 32 | - name: Setup Node.js ${{ matrix.node }} 33 | uses: actions/setup-node@v4 34 | with: 35 | node-version: ${{ matrix.node }} 36 | cache: yarn 37 | env: 38 | # https://github.com/actions/setup-node/issues/531#issuecomment-1819151412 39 | SKIP_YARN_COREPACK_CHECK: 1 40 | 41 | - name: Install ESLint ${{ matrix.eslint }} 42 | run: | 43 | yarn add -D --ignore-engines eslint@${{ matrix.eslint }} 44 | 45 | - name: Install Dependencies 46 | run: yarn --ignore-engines 47 | env: 48 | SKIP_YARN_COREPACK_CHECK: 1 49 | 50 | - name: Build and Test 51 | run: | 52 | yarn test-compiled 53 | yarn test 54 | env: 55 | SKIP_YARN_COREPACK_CHECK: 1 56 | 57 | - name: Lint 58 | run: yarn lint 59 | env: 60 | EFF_NO_LINK_RULES: true 61 | PARSER_NO_WATCH: true 62 | SKIP_YARN_COREPACK_CHECK: 1 63 | if: ${{ matrix.node == 20 && matrix.eslint == 8 }} 64 | 65 | - name: Codecov 66 | uses: codecov/codecov-action@v3 67 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | name: CodeQL 2 | 3 | on: 4 | push: 5 | pull_request: 6 | schedule: 7 | - cron: '41 19 * * 6' 8 | 9 | jobs: 10 | analyze: 11 | name: Analyze 12 | runs-on: ubuntu-latest 13 | permissions: 14 | actions: read 15 | contents: read 16 | security-events: write 17 | 18 | strategy: 19 | fail-fast: false 20 | matrix: 21 | language: 22 | - javascript 23 | 24 | steps: 25 | - name: Checkout 26 | uses: actions/checkout@v4 27 | 28 | - name: Initialize CodeQL 29 | uses: github/codeql-action/init@v3 30 | with: 31 | languages: ${{ matrix.language }} 32 | queries: +security-and-quality 33 | 34 | - name: Autobuild 35 | uses: github/codeql-action/autobuild@v3 36 | 37 | - name: Perform CodeQL Analysis 38 | uses: github/codeql-action/analyze@v3 39 | with: 40 | category: '/language:${{ matrix.language }}' 41 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | release: 10 | name: Release 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout Repo 14 | uses: actions/checkout@v4 15 | with: 16 | # This makes Actions fetch all Git history so that Changesets can generate changelogs with the correct commits 17 | fetch-depth: 0 18 | 19 | - name: Enable Corepack 20 | run: corepack enable 21 | 22 | - name: Setup Node.js LTS 23 | uses: actions/setup-node@v4 24 | with: 25 | node-version: lts/* 26 | cache: yarn 27 | env: 28 | # https://github.com/actions/setup-node/issues/531#issuecomment-1819151412 29 | SKIP_YARN_COREPACK_CHECK: 1 30 | 31 | - name: Install Dependencies 32 | run: yarn --immutable 33 | env: 34 | SKIP_YARN_COREPACK_CHECK: 1 35 | 36 | # required for linting before commit 37 | - name: Build 38 | run: yarn build 39 | env: 40 | SKIP_YARN_COREPACK_CHECK: 1 41 | 42 | - name: Create Release Pull Request or Publish to npm 43 | id: changesets 44 | uses: changesets/action@v1 45 | with: 46 | commit: 'chore: release eslint-plugin-import-x' 47 | title: 'chore: release eslint-plugin-import-x' 48 | publish: yarn release 49 | env: 50 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 51 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 52 | SKIP_YARN_COREPACK_CHECK: 1 53 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # Compiled binary addons (https://nodejs.org/api/addons.html) 20 | build/Release 21 | 22 | # Dependency directory 23 | # Commenting this out is preferred by some people, see 24 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- 25 | node_modules 26 | !test/**/node_modules/ 27 | 28 | # Users Environment Variables 29 | .lock-wscript 30 | 31 | # added by GitSavvy 32 | *.sublime-workspace 33 | 34 | # generated output 35 | lib/ 36 | **/.nyc_output/ 37 | 38 | # macOS 39 | .DS_Store 40 | .*cache 41 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | test/fixtures/just-json-files/invalid.json 2 | test/fixtures/malformed.js 3 | test/fixtures/with-syntax-error/package.json 4 | -------------------------------------------------------------------------------- /.prettierrc.mjs: -------------------------------------------------------------------------------- 1 | import baseConfig from '@1stg/prettier-config' 2 | 3 | export default { 4 | ...baseConfig, 5 | overrides: [ 6 | ...baseConfig.overrides, 7 | { 8 | files: ['**/*.js'], 9 | options: { 10 | parser: 'babel-flow', 11 | }, 12 | }, 13 | ], 14 | } 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Ben Mosher 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @type {import('@babel/core').TransformOptions} 3 | */ 4 | module.exports = { 5 | presets: [ 6 | [ 7 | '@babel/env', 8 | { 9 | targets: { 10 | node: 12, 11 | }, 12 | }, 13 | ], 14 | '@babel/flow', 15 | '@babel/react', 16 | ], 17 | plugins: [ 18 | [ 19 | '@babel/proposal-decorators', 20 | { 21 | version: 'legacy', 22 | }, 23 | ], 24 | '@babel/proposal-export-default-from', 25 | ], 26 | sourceMaps: 'inline', 27 | retainLines: true, 28 | overrides: [ 29 | { 30 | include: '**/*.ts', 31 | presets: [ 32 | [ 33 | '@babel/typescript', 34 | { 35 | allowDeclareFields: true, 36 | }, 37 | ], 38 | ], 39 | }, 40 | ], 41 | } 42 | -------------------------------------------------------------------------------- /docs/rules/default.md: -------------------------------------------------------------------------------- 1 | # import-x/default 2 | 3 | 💼 This rule is enabled in the following configs: ❗ `errors`, ☑️ `recommended`. 4 | 5 | 6 | 7 | If a default import is requested, this rule will report if there is no default 8 | export in the imported module. 9 | 10 | For [ES7], reports if a default is named and exported but is not found in the 11 | referenced module. 12 | 13 | Note: for packages, the plugin will find exported names 14 | from [`jsnext:main`], if present in `package.json`. 15 | Redux's npm module includes this key, and thereby is lintable, for example. 16 | 17 | A module path that is [ignored] or not [unambiguously an ES module] will not be reported when imported. 18 | 19 | [ignored]: ../README.md#importignore 20 | [unambiguously an ES module]: https://github.com/bmeck/UnambiguousJavaScriptGrammar 21 | 22 | ## Rule Details 23 | 24 | Given: 25 | 26 | ```js 27 | // ./foo.js 28 | export default function () { 29 | return 42 30 | } 31 | 32 | // ./bar.js 33 | export function bar() { 34 | return null 35 | } 36 | 37 | // ./baz.js 38 | module.exports = function () { 39 | /* ... */ 40 | } 41 | 42 | // node_modules/some-module/index.js 43 | exports.sharedFunction = function shared() { 44 | /* ... */ 45 | } 46 | ``` 47 | 48 | The following is considered valid: 49 | 50 | ```js 51 | import foo from './foo' 52 | 53 | // assuming 'node_modules' are ignored (true by default) 54 | import someModule from 'some-module' 55 | ``` 56 | 57 | ...and the following cases are reported: 58 | 59 | ```js 60 | import bar from './bar' // no default export found in ./bar 61 | import baz from './baz' // no default export found in ./baz 62 | ``` 63 | 64 | ## When Not To Use It 65 | 66 | If you are using CommonJS and/or modifying the exported namespace of any module at 67 | runtime, you will likely see false positives with this rule. 68 | 69 | This rule currently does not interpret `module.exports = ...` as a `default` export, 70 | either, so such a situation will be reported in the importing module. 71 | 72 | ## Further Reading 73 | 74 | - Lee Byron's [ES7] export proposal 75 | - [`import-x/ignore`] setting 76 | - [`jsnext:main`] (Rollup) 77 | 78 | [ES7]: https://github.com/leebyron/ecmascript-more-export-from 79 | [`import-x/ignore`]: ../../README.md#importignore 80 | [`jsnext:main`]: https://github.com/rollup/rollup/wiki/jsnext:main 81 | -------------------------------------------------------------------------------- /docs/rules/export.md: -------------------------------------------------------------------------------- 1 | # import-x/export 2 | 3 | 💼 This rule is enabled in the following configs: ❗ `errors`, ☑️ `recommended`. 4 | 5 | 6 | 7 | Reports funny business with exports, like repeated exports of names or defaults. 8 | 9 | ## Rule Details 10 | 11 | ```js 12 | export default class MyClass { /*...*/ } // Multiple default exports. 13 | 14 | function makeClass() { return new MyClass(...arguments) } 15 | 16 | export default makeClass // Multiple default exports. 17 | ``` 18 | 19 | or 20 | 21 | ```js 22 | export const foo = function () { 23 | /*...*/ 24 | } // Multiple exports of name 'foo'. 25 | 26 | function bar() { 27 | /*...*/ 28 | } 29 | export { bar as foo } // Multiple exports of name 'foo'. 30 | ``` 31 | 32 | In the case of named/default re-export, all `n` re-exports will be reported, 33 | as at least `n-1` of them are clearly mistakes, but it is not clear which one 34 | (if any) is intended. Could be the result of copy/paste, code duplication with 35 | intent to rename, etc. 36 | 37 | ## Further Reading 38 | 39 | - Lee Byron's [ES7] export proposal 40 | 41 | [ES7]: https://github.com/leebyron/ecmascript-more-export-from 42 | -------------------------------------------------------------------------------- /docs/rules/exports-last.md: -------------------------------------------------------------------------------- 1 | # import-x/exports-last 2 | 3 | 4 | 5 | This rule enforces that all exports are declared at the bottom of the file. This rule will report any export declarations that comes before any non-export statements. 6 | 7 | ## This will be reported 8 | 9 | ```JS 10 | 11 | const bool = true 12 | 13 | export default bool 14 | 15 | const str = 'foo' 16 | 17 | ``` 18 | 19 | ```JS 20 | 21 | export const bool = true 22 | 23 | const str = 'foo' 24 | 25 | ``` 26 | 27 | ## This will not be reported 28 | 29 | ```JS 30 | const arr = ['bar'] 31 | 32 | export const bool = true 33 | 34 | export default bool 35 | 36 | export function func() { 37 | console.log('Hello World 🌍') 38 | } 39 | 40 | export const str = 'foo' 41 | ``` 42 | 43 | ## When Not To Use It 44 | 45 | If you don't mind exports being sprinkled throughout a file, you may not want to enable this rule. 46 | 47 | ### ES6 exports only 48 | 49 | The exports-last rule is currently only working on ES6 exports. You may not want to enable this rule if you're using CommonJS exports. 50 | 51 | If you need CommonJS support feel free to open an issue or create a PR. 52 | -------------------------------------------------------------------------------- /docs/rules/first.md: -------------------------------------------------------------------------------- 1 | # import-x/first 2 | 3 | 🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix). 4 | 5 | 6 | 7 | This rule reports any imports that come after non-import 8 | statements. 9 | 10 | ## Rule Details 11 | 12 | ```js 13 | import foo from './foo' 14 | 15 | // some module-level initializer 16 | initWith(foo) 17 | 18 | import bar from './bar' // <- reported 19 | ``` 20 | 21 | Providing `absolute-first` as an option will report any absolute imports (i.e. 22 | packages) that come after any relative imports: 23 | 24 | ```js 25 | import foo from 'foo' 26 | import bar from './bar' 27 | 28 | import * as _ from 'lodash' // <- reported 29 | ``` 30 | 31 | If you really want import type ordering, check out [`import-x/order`]. 32 | 33 | Notably, `import`s are hoisted, which means the imported modules will be evaluated 34 | before any of the statements interspersed between them. Keeping all `import`s together 35 | at the top of the file may prevent surprises resulting from this part of the spec. 36 | 37 | ### On directives 38 | 39 | Directives are allowed as long as they occur strictly before any `import` declarations, 40 | as follows: 41 | 42 | ```js 43 | 'use super-mega-strict' 44 | 45 | import { suchFoo } from 'lame-fake-module-name' // no report here 46 | ``` 47 | 48 | A directive in this case is assumed to be a single statement that contains only 49 | a literal string-valued expression. 50 | 51 | `'use strict'` would be a good example, except that [modules are always in strict 52 | mode](https://262.ecma-international.org/6.0/#sec-strict-mode-code) so it would be surprising to see a `'use strict'` sharing a file with `import`s and 53 | `export`s. 54 | 55 | Given that, see [#255] for the reasoning. 56 | 57 | ### With Fixer 58 | 59 | This rule contains a fixer to reorder in-body import to top, the following criteria applied: 60 | 61 | 1. Never re-order relative to each other, even if `absolute-first` is set. 62 | 2. If an import creates an identifier, and that identifier is referenced at module level _before_ the import itself, that won't be re-ordered. 63 | 64 | ## When Not To Use It 65 | 66 | If you don't mind imports being sprinkled throughout, you may not want to 67 | enable this rule. 68 | 69 | ## Further Reading 70 | 71 | - [`import-x/order`]: a major step up from `absolute-first` 72 | - Issue [#255] 73 | 74 | [`import-x/order`]: ./order.md 75 | [#255]: https://github.com/import-js/eslint-plugin-import/issues/255 76 | -------------------------------------------------------------------------------- /docs/rules/imports-first.md: -------------------------------------------------------------------------------- 1 | # import-x/imports-first 2 | 3 | ❌ This rule is deprecated. 4 | 5 | 🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix). 6 | 7 | 8 | 9 | This rule was **deprecated** in eslint-plugin-import v2.0.0. Please use the corresponding rule [`first`](https://github.com/import-js/eslint-plugin-import/blob/HEAD/docs/rules/first.md). 10 | -------------------------------------------------------------------------------- /docs/rules/max-dependencies.md: -------------------------------------------------------------------------------- 1 | # import-x/max-dependencies 2 | 3 | 4 | 5 | Forbid modules to have too many dependencies (`import` or `require` statements). 6 | 7 | This is a useful rule because a module with too many dependencies is a code smell, and usually indicates the module is doing too much and/or should be broken up into smaller modules. 8 | 9 | Importing multiple named exports from a single module will only count once (e.g. `import {x, y, z} from './foo'` will only count as a single dependency). 10 | 11 | ## Options 12 | 13 | This rule has the following options, with these defaults: 14 | 15 | ```js 16 | "import-x/max-dependencies": ["error", { 17 | "max": 10, 18 | "ignoreTypeImports": false, 19 | }] 20 | ``` 21 | 22 | ### `max` 23 | 24 | This option sets the maximum number of dependencies allowed. Anything over will trigger the rule. **Default is 10** if the rule is enabled and no `max` is specified. 25 | 26 | Given a max value of `{"max": 2}`: 27 | 28 | ### Fail 29 | 30 | ```js 31 | import a from './a' // 1 32 | const b = require('./b') // 2 33 | import c from './c' // 3 - exceeds max! 34 | ``` 35 | 36 | ### Pass 37 | 38 | ```js 39 | import a from './a' // 1 40 | const anotherA = require('./a') // still 1 41 | import { x, y, z } from './foo' // 2 42 | ``` 43 | 44 | ### `ignoreTypeImports` 45 | 46 | Ignores `type` imports. Type imports are a feature released in TypeScript 3.8, you can [read more here](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-export). Defaults to `false`. 47 | 48 | Given `{"max": 2, "ignoreTypeImports": true}`: 49 | 50 | 51 | 52 | ### Fail 53 | 54 | ```ts 55 | import a from './a' 56 | import b from './b' 57 | import c from './c' 58 | ``` 59 | 60 | 61 | 62 | ### Pass 63 | 64 | ```ts 65 | import a from './a' 66 | import b from './b' 67 | import type c from './c' // Doesn't count against max 68 | ``` 69 | 70 | ## When Not To Use It 71 | 72 | If you don't care how many dependencies a module has. 73 | -------------------------------------------------------------------------------- /docs/rules/no-absolute-path.md: -------------------------------------------------------------------------------- 1 | # import-x/no-absolute-path 2 | 3 | 🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix). 4 | 5 | 6 | 7 | Node.js allows the import of modules using an absolute path such as `/home/xyz/file.js`. That is a bad practice as it ties the code using it to your computer, and therefore makes it unusable in packages distributed on `npm` for instance. 8 | 9 | This rule forbids the import of modules using absolute paths. 10 | 11 | ## Rule Details 12 | 13 | ### Fail 14 | 15 | ```js 16 | import f from '/foo' 17 | import f from '/some/path' 18 | 19 | var f = require('/foo') 20 | var f = require('/some/path') 21 | ``` 22 | 23 | ### Pass 24 | 25 | ```js 26 | import _ from 'lodash' 27 | import foo from 'foo' 28 | import foo from './foo' 29 | 30 | var _ = require('lodash') 31 | var foo = require('foo') 32 | var foo = require('./foo') 33 | ``` 34 | 35 | ### Options 36 | 37 | By default, only ES6 imports and CommonJS `require` calls will have this rule enforced. 38 | 39 | You may provide an options object providing true/false for any of 40 | 41 | - `esmodule`: defaults to `true` 42 | - `commonjs`: defaults to `true` 43 | - `amd`: defaults to `false` 44 | 45 | If `{ amd: true }` is provided, dependency paths for AMD-style `define` and `require` 46 | calls will be resolved: 47 | 48 | ```js 49 | /*eslint import-x/no-absolute-path: [2, { commonjs: false, amd: true }]*/ 50 | define(['/foo'], function (foo) { 51 | /*...*/ 52 | }) // reported 53 | require(['/foo'], function (foo) { 54 | /*...*/ 55 | }) // reported 56 | 57 | const foo = require('/foo') // ignored because of explicit `commonjs: false` 58 | ``` 59 | -------------------------------------------------------------------------------- /docs/rules/no-amd.md: -------------------------------------------------------------------------------- 1 | # import-x/no-amd 2 | 3 | 4 | 5 | Reports `require([array], ...)` and `define([array], ...)` function calls at the 6 | module scope. Will not report if !=2 arguments, or first argument is not a literal array. 7 | 8 | Intended for temporary use when migrating to pure ES6 modules. 9 | 10 | ## Rule Details 11 | 12 | This will be reported: 13 | 14 | ```js 15 | define(['a', 'b'], function (a, b) { 16 | /* ... */ 17 | }) 18 | 19 | require(['b', 'c'], function (b, c) { 20 | /* ... */ 21 | }) 22 | ``` 23 | 24 | CommonJS `require` is still valid. 25 | 26 | ## When Not To Use It 27 | 28 | If you don't mind mixing module systems (sometimes this is useful), you probably 29 | don't want this rule. 30 | 31 | It is also fairly noisy if you have a larger codebase that is being transitioned 32 | from AMD to ES6 modules. 33 | 34 | ## Contributors 35 | 36 | Special thanks to @xjamundx for donating his no-define rule as a start to this. 37 | 38 | ## Further Reading 39 | 40 | - [`no-commonjs`](./no-commonjs.md): report CommonJS `require` and `exports` 41 | - Source: 42 | -------------------------------------------------------------------------------- /docs/rules/no-anonymous-default-export.md: -------------------------------------------------------------------------------- 1 | # import-x/no-anonymous-default-export 2 | 3 | 4 | 5 | Reports if a module's default export is unnamed. This includes several types of unnamed data types; literals, object expressions, arrays, anonymous functions, arrow functions, and anonymous class declarations. 6 | 7 | Ensuring that default exports are named helps improve the grepability of the codebase by encouraging the re-use of the same identifier for the module's default export at its declaration site and at its import sites. 8 | 9 | ## Options 10 | 11 | By default, all types of anonymous default exports are forbidden, but any types can be selectively allowed by toggling them on in the options. 12 | 13 | The complete default configuration looks like this. 14 | 15 | ```js 16 | "import-x/no-anonymous-default-export": ["error", { 17 | "allowArray": false, 18 | "allowArrowFunction": false, 19 | "allowAnonymousClass": false, 20 | "allowAnonymousFunction": false, 21 | "allowCallExpression": true, // The true value here is for backward compatibility 22 | "allowNew": false, 23 | "allowLiteral": false, 24 | "allowObject": false 25 | }] 26 | ``` 27 | 28 | ## Rule Details 29 | 30 | ### Fail 31 | 32 | ```js 33 | export default [] 34 | 35 | export default () => {} 36 | 37 | export default class {} 38 | 39 | export default function () {} 40 | 41 | /* eslint import-x/no-anonymous-default-export: [2, {"allowCallExpression": false}] */ 42 | export default foo(bar) 43 | 44 | export default 123 45 | 46 | export default {} 47 | 48 | export default new Foo() 49 | ``` 50 | 51 | ### Pass 52 | 53 | ```js 54 | const foo = 123 55 | export default foo 56 | 57 | export default class MyClass() {} 58 | 59 | export default function foo() {} 60 | 61 | /* eslint import-x/no-anonymous-default-export: [2, {"allowArray": true}] */ 62 | export default [] 63 | 64 | /* eslint import-x/no-anonymous-default-export: [2, {"allowArrowFunction": true}] */ 65 | export default () => {} 66 | 67 | /* eslint import-x/no-anonymous-default-export: [2, {"allowAnonymousClass": true}] */ 68 | export default class {} 69 | 70 | /* eslint import-x/no-anonymous-default-export: [2, {"allowAnonymousFunction": true}] */ 71 | export default function () {} 72 | 73 | export default foo(bar) 74 | 75 | /* eslint import-x/no-anonymous-default-export: [2, {"allowLiteral": true}] */ 76 | export default 123 77 | 78 | /* eslint import-x/no-anonymous-default-export: [2, {"allowObject": true}] */ 79 | export default {} 80 | 81 | /* eslint import-x/no-anonymous-default-export: [2, {"allowNew": true}] */ 82 | export default new Foo() 83 | ``` 84 | -------------------------------------------------------------------------------- /docs/rules/no-default-export.md: -------------------------------------------------------------------------------- 1 | # import-x/no-default-export 2 | 3 | 4 | 5 | Prohibit default exports. Mostly an inverse of [`prefer-default-export`]. 6 | 7 | [`prefer-default-export`]: ./prefer-default-export.md 8 | 9 | ## Rule Details 10 | 11 | The following patterns are considered warnings: 12 | 13 | ```javascript 14 | // bad1.js 15 | 16 | // There is a default export. 17 | export const foo = 'foo' 18 | const bar = 'bar' 19 | export default 'bar' 20 | ``` 21 | 22 | ```javascript 23 | // bad2.js 24 | 25 | // There is a default export. 26 | const foo = 'foo' 27 | export { foo as default } 28 | ``` 29 | 30 | The following patterns are not warnings: 31 | 32 | ```javascript 33 | // good1.js 34 | 35 | // There is only a single module export and it's a named export. 36 | export const foo = 'foo' 37 | ``` 38 | 39 | ```javascript 40 | // good2.js 41 | 42 | // There is more than one named export in the module. 43 | export const foo = 'foo' 44 | export const bar = 'bar' 45 | ``` 46 | 47 | ```javascript 48 | // good3.js 49 | 50 | // There is more than one named export in the module 51 | const foo = 'foo' 52 | const bar = 'bar' 53 | export { foo, bar } 54 | ``` 55 | 56 | ```javascript 57 | // export-star.js 58 | 59 | // Any batch export will disable this rule. The remote module is not inspected. 60 | export * from './other-module' 61 | ``` 62 | 63 | ## When Not To Use It 64 | 65 | If you don't care if default imports are used, or if you prefer default imports over named imports. 66 | -------------------------------------------------------------------------------- /docs/rules/no-deprecated.md: -------------------------------------------------------------------------------- 1 | # import-x/no-deprecated 2 | 3 | 4 | 5 | Reports use of a deprecated name, as indicated by a JSDoc block with a `@deprecated` 6 | tag or TomDoc `Deprecated:` comment. 7 | 8 | using a JSDoc `@deprecated` tag: 9 | 10 | ```js 11 | // @file: ./answer.js 12 | 13 | /** 14 | * this is what you get when you trust a mouse talk show 15 | * @deprecated need to restart the experiment 16 | * @returns {Number} nonsense 17 | */ 18 | export function multiply(six, nine) { 19 | return 42 20 | } 21 | ``` 22 | 23 | will report as such: 24 | 25 | ```js 26 | import { multiply } from './answer' // Deprecated: need to restart the experiment 27 | 28 | function whatever(y, z) { 29 | return multiply(y, z) // Deprecated: need to restart the experiment 30 | } 31 | ``` 32 | 33 | or using the TomDoc equivalent: 34 | 35 | ```js 36 | // Deprecated: This is what you get when you trust a mouse talk show, need to 37 | // restart the experiment. 38 | // 39 | // Returns a Number nonsense 40 | export function multiply(six, nine) { 41 | return 42 42 | } 43 | ``` 44 | 45 | Only JSDoc is enabled by default. Other documentation styles can be enabled with 46 | the `import-x/docstyle` setting. 47 | 48 | ```yaml 49 | # .eslintrc.yml 50 | settings: 51 | import-x/docstyle: ['jsdoc', 'tomdoc'] 52 | ``` 53 | 54 | ## Worklist 55 | 56 | - [x] report explicit imports on the import node 57 | - [x] support namespaces 58 | - [x] should bubble up through deep namespaces (#157) 59 | - [x] report explicit imports at reference time (at the identifier) similar to namespace 60 | - [x] mark module deprecated if file JSDoc has a @deprecated tag? 61 | - [ ] don't flag redeclaration of imported, deprecated names 62 | - [ ] flag destructuring 63 | -------------------------------------------------------------------------------- /docs/rules/no-dynamic-require.md: -------------------------------------------------------------------------------- 1 | # import-x/no-dynamic-require 2 | 3 | 4 | 5 | The `require` method from CommonJS is used to import modules from different files. Unlike the ES6 `import` syntax, it can be given expressions that will be resolved at runtime. While this is sometimes necessary and useful, in most cases it isn't. Using expressions (for instance, concatenating a path and variable) as the argument makes it harder for tools to do static code analysis, or to find where in the codebase a module is used. 6 | 7 | This rule forbids every call to `require()` that uses expressions for the module name argument. 8 | 9 | ## Rule Details 10 | 11 | ### Fail 12 | 13 | ```js 14 | require(name) 15 | require('../' + name) 16 | require(`../${name}`) 17 | require(name()) 18 | ``` 19 | 20 | ### Pass 21 | 22 | ```js 23 | require('../name') 24 | require(`../name`) 25 | ``` 26 | -------------------------------------------------------------------------------- /docs/rules/no-empty-named-blocks.md: -------------------------------------------------------------------------------- 1 | # import-x/no-empty-named-blocks 2 | 3 | 🔧💡 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix) and manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions). 4 | 5 | 6 | 7 | Reports the use of empty named import blocks. 8 | 9 | ## Rule Details 10 | 11 | ### Valid 12 | 13 | ```js 14 | import { mod } from 'mod' 15 | import Default, { mod } from 'mod' 16 | ``` 17 | 18 | When using typescript 19 | 20 | ```js 21 | import type { mod } from 'mod' 22 | ``` 23 | 24 | When using flow 25 | 26 | ```js 27 | import typeof { mod } from 'mod' 28 | ``` 29 | 30 | ### Invalid 31 | 32 | ```js 33 | import {} from 'mod' 34 | import Default from 'mod' 35 | ``` 36 | 37 | When using typescript 38 | 39 | ```js 40 | import type Default, {} from 'mod' 41 | import type {} from 'mod' 42 | ``` 43 | 44 | When using flow 45 | 46 | ```js 47 | import typeof {} from 'mod' 48 | import typeof Default, {} from 'mod' 49 | ``` 50 | -------------------------------------------------------------------------------- /docs/rules/no-import-module-exports.md: -------------------------------------------------------------------------------- 1 | # import-x/no-import-module-exports 2 | 3 | 🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix). 4 | 5 | 6 | 7 | Reports the use of import declarations with CommonJS exports in any module 8 | except for the [main module](https://docs.npmjs.com/files/package.json#main). 9 | 10 | If you have multiple entry points or are using `js:next` this rule includes an 11 | `exceptions` option which you can use to exclude those files from the rule. 12 | 13 | ## Options 14 | 15 | ### `exceptions` 16 | 17 | - An array of globs. The rule will be omitted from any file that matches a glob 18 | in the options array. For example, the following setting will omit the rule 19 | in the `some-file.js` file. 20 | 21 | ```json 22 | "import-x/no-import-module-exports": ["error", { 23 | "exceptions": ["**/*/some-file.js"] 24 | }] 25 | ``` 26 | 27 | ## Rule Details 28 | 29 | ### Fail 30 | 31 | ```js 32 | import { stuff } from 'starwars' 33 | module.exports = thing 34 | 35 | import * as allThings from 'starwars' 36 | exports.bar = thing 37 | 38 | import thing from 'other-thing' 39 | exports.foo = bar 40 | 41 | import thing from 'starwars' 42 | const baz = (module.exports = thing) 43 | console.log(baz) 44 | ``` 45 | 46 | ### Pass 47 | 48 | Given the following package.json: 49 | 50 | ```json 51 | { 52 | "main": "lib/index.js" 53 | } 54 | ``` 55 | 56 | ```js 57 | import thing from 'other-thing' 58 | export default thing 59 | 60 | const thing = require('thing') 61 | module.exports = thing 62 | 63 | const thing = require('thing') 64 | exports.foo = bar 65 | 66 | import thing from 'otherthing' 67 | console.log(thing.module.exports) 68 | 69 | // in lib/index.js 70 | import foo from 'path' 71 | module.exports = foo 72 | 73 | // in some-file.js 74 | // eslint import-x/no-import-module-exports: ["error", {"exceptions": ["**/*/some-file.js"]}] 75 | import foo from 'path' 76 | module.exports = foo 77 | ``` 78 | 79 | ### Further Reading 80 | 81 | - [webpack issue #4039](https://github.com/webpack/webpack/issues/4039) 82 | -------------------------------------------------------------------------------- /docs/rules/no-mutable-exports.md: -------------------------------------------------------------------------------- 1 | # import-x/no-mutable-exports 2 | 3 | 4 | 5 | Forbids the use of mutable exports with `var` or `let`. 6 | 7 | ## Rule Details 8 | 9 | Valid: 10 | 11 | ```js 12 | export const count = 1 13 | export function getCount() {} 14 | export class Counter {} 15 | ``` 16 | 17 | ...whereas here exports will be reported: 18 | 19 | ```js 20 | export let count = 2 21 | export var count = 3 22 | 23 | let count = 4 24 | export { count } // reported here 25 | ``` 26 | 27 | ## Functions/Classes 28 | 29 | Note that exported function/class declaration identifiers may be reassigned, 30 | but are not flagged by this rule at this time. They may be in the future, if a 31 | reassignment is detected, i.e. 32 | 33 | ```js 34 | // possible future behavior! 35 | export class Counter {} // reported here: exported class is reassigned on line [x]. 36 | Counter = KitchenSink // not reported here unless you enable no-class-assign 37 | 38 | // this pre-declaration reassignment is valid on account of function hoisting 39 | getCount = function getDuke() {} // not reported here without no-func-assign 40 | export function getCount() {} // reported here: exported function is reassigned on line [x]. 41 | ``` 42 | 43 | To prevent general reassignment of these identifiers, exported or not, you may 44 | want to enable the following core ESLint rules: 45 | 46 | - [no-func-assign] 47 | - [no-class-assign] 48 | 49 | [no-func-assign]: https://eslint.org/docs/rules/no-func-assign 50 | [no-class-assign]: https://eslint.org/docs/rules/no-class-assign 51 | 52 | ## When Not To Use It 53 | 54 | If your environment correctly implements mutable export bindings. 55 | -------------------------------------------------------------------------------- /docs/rules/no-named-as-default-member.md: -------------------------------------------------------------------------------- 1 | # import-x/no-named-as-default-member 2 | 3 | ⚠️ This rule _warns_ in the following configs: ☑️ `recommended`, 🚸 `warnings`. 4 | 5 | 6 | 7 | Reports use of an exported name as a property on the default export. 8 | 9 | Rationale: Accessing a property that has a name that is shared by an exported 10 | name from the same module is likely to be a mistake. 11 | 12 | Named import syntax looks very similar to destructuring assignment. It's easy to 13 | make the (incorrect) assumption that named exports are also accessible as 14 | properties of the default export. 15 | 16 | Furthermore, [in Babel 5 this is actually how things worked][blog]. This was 17 | fixed in Babel 6. Before upgrading an existing codebase to Babel 6, it can be 18 | useful to run this lint rule. 19 | 20 | [blog]: https://kentcdodds.com/blog/misunderstanding-es6-modules-upgrading-babel-tears-and-a-solution 21 | 22 | ## Rule Details 23 | 24 | Given: 25 | 26 | ```js 27 | // foo.js 28 | export default 'foo' 29 | export const bar = 'baz' 30 | ``` 31 | 32 | ...this would be valid: 33 | 34 | ```js 35 | import foo, { bar } from './foo.js' 36 | ``` 37 | 38 | ...and the following would be reported: 39 | 40 | ```js 41 | // Caution: `foo` also has a named export `bar`. 42 | // Check if you meant to write `import {bar} from './foo.js'` instead. 43 | import foo from './foo.js' 44 | const bar = foo.bar 45 | ``` 46 | 47 | ```js 48 | // Caution: `foo` also has a named export `bar`. 49 | // Check if you meant to write `import {bar} from './foo.js'` instead. 50 | import foo from './foo.js' 51 | const { bar } = foo 52 | ``` 53 | -------------------------------------------------------------------------------- /docs/rules/no-named-as-default.md: -------------------------------------------------------------------------------- 1 | # import-x/no-named-as-default 2 | 3 | ⚠️ This rule _warns_ in the following configs: ☑️ `recommended`, 🚸 `warnings`. 4 | 5 | 6 | 7 | Reports use of an exported name as the locally imported name of a default export. 8 | 9 | Rationale: using an exported name as the name of the default export is likely... 10 | 11 | - _misleading_: others familiar with `foo.js` probably expect the name to be `foo` 12 | - _a mistake_: only needed to import `bar` and forgot the brackets (the case that is prompting this) 13 | 14 | ## Rule Details 15 | 16 | Given: 17 | 18 | ```js 19 | // foo.js 20 | export default 'foo' 21 | export const bar = 'baz' 22 | ``` 23 | 24 | ...this would be valid: 25 | 26 | ```js 27 | import foo from './foo.js' 28 | ``` 29 | 30 | ...and this would be reported: 31 | 32 | ```js 33 | // message: Using exported name 'bar' as identifier for default export. 34 | import bar from './foo.js' 35 | ``` 36 | 37 | For post-ES2015 `export` extensions, this also prevents exporting the default from a referenced module as a name within that module, for the same reasons: 38 | 39 | ```js 40 | // valid: 41 | export foo from './foo.js' 42 | 43 | // message: Using exported name 'bar' as identifier for default export. 44 | export bar from './foo.js' 45 | ``` 46 | 47 | ## Further Reading 48 | 49 | - ECMAScript Proposal: [export ns from] 50 | - ECMAScript Proposal: [export default from] 51 | 52 | [export ns from]: https://github.com/leebyron/ecmascript-export-ns-from 53 | [export default from]: https://github.com/leebyron/ecmascript-export-default-from 54 | -------------------------------------------------------------------------------- /docs/rules/no-named-default.md: -------------------------------------------------------------------------------- 1 | # import-x/no-named-default 2 | 3 | 4 | 5 | Reports use of a default export as a locally named import. 6 | 7 | Rationale: the syntax exists to import default exports expressively, let's use it. 8 | 9 | Note that type imports, as used by [Flow], are always ignored. 10 | 11 | [Flow]: https://flow.org/ 12 | 13 | ## Rule Details 14 | 15 | Given: 16 | 17 | ```js 18 | // foo.js 19 | export default 'foo' 20 | export const bar = 'baz' 21 | ``` 22 | 23 | ...these would be valid: 24 | 25 | ```js 26 | import foo from './foo.js' 27 | import foo, { bar } from './foo.js' 28 | ``` 29 | 30 | ...and these would be reported: 31 | 32 | ```js 33 | // message: Using exported name 'bar' as identifier for default export. 34 | import { default as foo } from './foo.js' 35 | import { default as foo, bar } from './foo.js' 36 | ``` 37 | -------------------------------------------------------------------------------- /docs/rules/no-named-export.md: -------------------------------------------------------------------------------- 1 | # import-x/no-named-export 2 | 3 | 4 | 5 | Prohibit named exports. Mostly an inverse of [`no-default-export`]. 6 | 7 | [`no-default-export`]: ./no-default-export.md 8 | 9 | ## Rule Details 10 | 11 | The following patterns are considered warnings: 12 | 13 | ```javascript 14 | // bad1.js 15 | 16 | // There is only a single module export and it's a named export. 17 | export const foo = 'foo' 18 | ``` 19 | 20 | ```javascript 21 | // bad2.js 22 | 23 | // There is more than one named export in the module. 24 | export const foo = 'foo' 25 | export const bar = 'bar' 26 | ``` 27 | 28 | ```javascript 29 | // bad3.js 30 | 31 | // There is more than one named export in the module. 32 | const foo = 'foo' 33 | const bar = 'bar' 34 | export { foo, bar } 35 | ``` 36 | 37 | ```javascript 38 | // bad4.js 39 | 40 | // There is more than one named export in the module. 41 | export * from './other-module' 42 | ``` 43 | 44 | ```javascript 45 | // bad5.js 46 | 47 | // There is a default and a named export. 48 | export const foo = 'foo' 49 | const bar = 'bar' 50 | export default 'bar' 51 | ``` 52 | 53 | The following patterns are not warnings: 54 | 55 | ```javascript 56 | // good1.js 57 | 58 | // There is only a single module export and it's a default export. 59 | export default 'bar' 60 | ``` 61 | 62 | ```javascript 63 | // good2.js 64 | 65 | // There is only a single module export and it's a default export. 66 | const foo = 'foo' 67 | export { foo as default } 68 | ``` 69 | 70 | ```javascript 71 | // good3.js 72 | 73 | // There is only a single module export and it's a default export. 74 | export default from './other-module' 75 | ``` 76 | 77 | ## When Not To Use It 78 | 79 | If you don't care if named imports are used, or if you prefer named imports over default imports. 80 | -------------------------------------------------------------------------------- /docs/rules/no-namespace.md: -------------------------------------------------------------------------------- 1 | # import-x/no-namespace 2 | 3 | 🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix). 4 | 5 | 6 | 7 | Enforce a convention of not using namespace (a.k.a. "wildcard" `*`) imports. 8 | 9 | The rule is auto-fixable when the namespace object is only used for direct member access, e.g. `namespace.a`. 10 | 11 | ## Options 12 | 13 | This rule supports the following options: 14 | 15 | - `ignore`: array of glob strings for modules that should be ignored by the rule. 16 | 17 | ## Rule Details 18 | 19 | Valid: 20 | 21 | ```js 22 | import defaultExport from './foo' 23 | import { a, b } from './bar' 24 | import defaultExport, { a, b } from './foobar' 25 | ``` 26 | 27 | ```js 28 | /* eslint import-x/no-namespace: ["error", {ignore: ['*.ext']}] */ 29 | import * as bar from './ignored-module.ext' 30 | ``` 31 | 32 | Invalid: 33 | 34 | ```js 35 | import * as foo from 'foo' 36 | ``` 37 | 38 | ```js 39 | import defaultExport, * as foo from 'foo' 40 | ``` 41 | 42 | ## When Not To Use It 43 | 44 | If you want to use namespaces, you don't want to use this rule. 45 | -------------------------------------------------------------------------------- /docs/rules/no-nodejs-modules.md: -------------------------------------------------------------------------------- 1 | # import-x/no-nodejs-modules 2 | 3 | 4 | 5 | Forbid the use of Node.js builtin modules. Can be useful for client-side web projects that do not have access to those modules. 6 | 7 | ## Options 8 | 9 | This rule supports the following options: 10 | 11 | - `allow`: Array of names of allowed modules. Defaults to an empty array. 12 | 13 | ## Rule Details 14 | 15 | ### Fail 16 | 17 | ```js 18 | import fs from 'fs' 19 | import path from 'path' 20 | 21 | var fs = require('fs') 22 | var path = require('path') 23 | ``` 24 | 25 | ### Pass 26 | 27 | ```js 28 | import _ from 'lodash' 29 | import foo from 'foo' 30 | import foo from './foo' 31 | 32 | var _ = require('lodash') 33 | var foo = require('foo') 34 | var foo = require('./foo') 35 | 36 | /* eslint import-x/no-nodejs-modules: ["error", {"allow": ["path"]}] */ 37 | import path from 'path' 38 | ``` 39 | 40 | ## When Not To Use It 41 | 42 | If you have a project that is run mainly or partially using Node.js. 43 | -------------------------------------------------------------------------------- /docs/rules/no-relative-packages.md: -------------------------------------------------------------------------------- 1 | # import-x/no-relative-packages 2 | 3 | 🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix). 4 | 5 | 6 | 7 | Use this rule to prevent importing packages through relative paths. 8 | 9 | It's useful in Yarn/Lerna workspaces, were it's possible to import a sibling 10 | package using `../package` relative path, while direct `package` is the correct one. 11 | 12 | ## Examples 13 | 14 | Given the following folder structure: 15 | 16 | ```pt 17 | my-project 18 | ├── packages 19 | │ ├── foo 20 | │ │ ├── index.js 21 | │ │ └── package.json 22 | │ └── bar 23 | │ ├── index.js 24 | │ └── package.json 25 | └── entry.js 26 | ``` 27 | 28 | And the .eslintrc file: 29 | 30 | ```json 31 | { 32 | ... 33 | "rules": { 34 | "import-x/no-relative-packages": "error" 35 | } 36 | } 37 | ``` 38 | 39 | The following patterns are considered problems: 40 | 41 | ```js 42 | /** 43 | * in my-project/packages/foo.js 44 | */ 45 | 46 | import bar from '../bar' // Import sibling package using relative path 47 | import entry from '../../entry.js' // Import from parent package using relative path 48 | 49 | /** 50 | * in my-project/entry.js 51 | */ 52 | 53 | import bar from './packages/bar' // Import child package using relative path 54 | ``` 55 | 56 | The following patterns are NOT considered problems: 57 | 58 | ```js 59 | /** 60 | * in my-project/packages/foo.js 61 | */ 62 | 63 | import bar from 'bar' // Import sibling package using package name 64 | 65 | /** 66 | * in my-project/entry.js 67 | */ 68 | 69 | import bar from 'bar' // Import sibling package using package name 70 | ``` 71 | -------------------------------------------------------------------------------- /docs/rules/no-self-import.md: -------------------------------------------------------------------------------- 1 | # import-x/no-self-import 2 | 3 | 4 | 5 | Forbid a module from importing itself. This can sometimes happen during refactoring. 6 | 7 | ## Rule Details 8 | 9 | ### Fail 10 | 11 | ```js 12 | // foo.js 13 | import foo from './foo' 14 | 15 | const foo = require('./foo') 16 | ``` 17 | 18 | ```js 19 | // index.js 20 | import index from '.' 21 | 22 | const index = require('.') 23 | ``` 24 | 25 | ### Pass 26 | 27 | ```js 28 | // foo.js 29 | import bar from './bar' 30 | 31 | const bar = require('./bar') 32 | ``` 33 | -------------------------------------------------------------------------------- /docs/rules/no-unassigned-import.md: -------------------------------------------------------------------------------- 1 | # import-x/no-unassigned-import 2 | 3 | 4 | 5 | With both CommonJS' `require` and the ES6 modules' `import` syntax, it is possible to import a module but not to use its result. This can be done explicitly by not assigning the module to as variable. Doing so can mean either of the following things: 6 | 7 | - The module is imported but not used 8 | - The module has side-effects (like [`should`](https://www.npmjs.com/package/should)). Having side-effects, makes it hard to know whether the module is actually used or can be removed. It can also make it harder to test or mock parts of your application. 9 | 10 | This rule aims to remove modules with side-effects by reporting when a module is imported but not assigned. 11 | 12 | ## Options 13 | 14 | This rule supports the following option: 15 | 16 | `allow`: An Array of globs. The files that match any of these patterns would be ignored/allowed by the linter. This can be useful for some build environments (e.g. css-loader in webpack). 17 | 18 | Note that the globs start from the where the linter is executed (usually project root), but not from each file that includes the source. Learn more in both the pass and fail examples below. 19 | 20 | ## Fail 21 | 22 | ```js 23 | import 'should' 24 | require('should') 25 | 26 | // In /src/app.js 27 | import '../styles/app.css' 28 | // {"allow": ["styles/*.css"]} 29 | ``` 30 | 31 | ## Pass 32 | 33 | ```js 34 | import _ from 'foo' 35 | import _, { foo } from 'foo' 36 | import _, { foo as bar } from 'foo' 37 | import { foo as bar } from 'foo' 38 | import * as _ from 'foo' 39 | 40 | const _ = require('foo') 41 | const { foo } = require('foo') 42 | const { foo: bar } = require('foo') 43 | const [a, b] = require('foo') 44 | const _ = require('foo') 45 | 46 | // Module is not assigned, but it is used 47 | bar(require('foo')) 48 | require('foo').bar 49 | require('foo').bar() 50 | require('foo')() 51 | 52 | // With allow option set 53 | import './style.css' // {"allow": ["**/*.css"]} 54 | import 'babel-register' // {"allow": ["babel-register"]} 55 | 56 | // In /src/app.js 57 | import './styles/app.css' 58 | import '../scripts/register.js' 59 | // {"allow": ["src/styles/**", "**/scripts/*.js"]} 60 | ``` 61 | -------------------------------------------------------------------------------- /docs/rules/no-webpack-loader-syntax.md: -------------------------------------------------------------------------------- 1 | # import-x/no-webpack-loader-syntax 2 | 3 | 4 | 5 | Forbid Webpack loader syntax in imports. 6 | 7 | [Webpack](https://webpack.js.org) allows specifying the [loaders](https://webpack.js.org/concepts/loaders/) to use in the import source string using a special syntax like this: 8 | 9 | ```js 10 | var moduleWithOneLoader = require('my-loader!./my-awesome-module') 11 | ``` 12 | 13 | This syntax is non-standard, so it couples the code to Webpack. The recommended way to specify Webpack loader configuration is in a [Webpack configuration file](https://webpack.js.org/concepts/loaders/#configuration). 14 | 15 | ## Rule Details 16 | 17 | ### Fail 18 | 19 | ```js 20 | import myModule from 'my-loader!my-module' 21 | import theme from 'style!css!./theme.css' 22 | 23 | var myModule = require('my-loader!./my-module') 24 | var theme = require('style!css!./theme.css') 25 | ``` 26 | 27 | ### Pass 28 | 29 | ```js 30 | import myModule from 'my-module' 31 | import theme from './theme.css' 32 | 33 | var myModule = require('my-module') 34 | var theme = require('./theme.css') 35 | ``` 36 | 37 | ## When Not To Use It 38 | 39 | If you have a project that doesn't use Webpack you can safely disable this rule. 40 | -------------------------------------------------------------------------------- /docs/rules/unambiguous.md: -------------------------------------------------------------------------------- 1 | # import-x/unambiguous 2 | 3 | 4 | 5 | Warn if a `module` could be mistakenly parsed as a `script` by a consumer leveraging 6 | [Unambiguous JavaScript Grammar] to determine correct parsing goal. 7 | 8 | Will respect the [`parserOptions.sourceType`] from ESLint config, i.e. files parsed 9 | as `script` per that setting will not be reported. 10 | 11 | This plugin uses [Unambiguous JavaScript Grammar] internally to decide whether 12 | dependencies should be parsed as modules and searched for exports matching the 13 | `import`ed names, so it may be beneficial to keep this rule on even if your application 14 | will run in an explicit `module`-only environment. 15 | 16 | ## Rule Details 17 | 18 | For files parsed as `module` by ESLint, the following are valid: 19 | 20 | ```js 21 | import 'foo' 22 | function x() { 23 | return 42 24 | } 25 | ``` 26 | 27 | ```js 28 | export function x() { 29 | return 42 30 | } 31 | ``` 32 | 33 | ```js 34 | ;(function x() { 35 | return 42 36 | })() 37 | export {} // simple way to mark side-effects-only file as 'module' without any imports/exports 38 | ``` 39 | 40 | ...whereas the following file would be reported: 41 | 42 | ```js 43 | ;(function x() { 44 | return 42 45 | })() 46 | ``` 47 | 48 | ## When Not To Use It 49 | 50 | If your application environment will always know via [some other means](https://github.com/nodejs/node-eps/issues/13) 51 | how to parse, regardless of syntax, you may not need this rule. 52 | 53 | Remember, though, that this plugin uses this strategy internally, so if you were 54 | to `import` from a module with no `import`s or `export`s, this plugin would not 55 | report it as it would not be clear whether it should be considered a `script` or 56 | a `module`. 57 | 58 | ## Further Reading 59 | 60 | - [Unambiguous JavaScript Grammar] 61 | - [`parserOptions.sourceType`] 62 | - [node-eps#13](https://github.com/nodejs/node-eps/issues/13) 63 | 64 | [`parserOptions.sourceType`]: https://eslint.org/docs/user-guide/configuring#specifying-parser-options 65 | [Unambiguous JavaScript Grammar]: https://github.com/nodejs/node-eps/blob/HEAD/002-es-modules.md#32-determining-if-source-is-an-es-module 66 | -------------------------------------------------------------------------------- /jest.config.ts: -------------------------------------------------------------------------------- 1 | import type { Options as SwcOptions } from '@swc/core' 2 | import type { Config } from 'jest' 3 | 4 | const testCompiled = process.env.TEST_COMPILED === '1' 5 | 6 | const srcDir = testCompiled ? 'lib' : 'src' 7 | 8 | export default { 9 | collectCoverage: !testCompiled, 10 | modulePathIgnorePatterns: ['/test/fixtures/with-syntax-error'], 11 | moduleNameMapper: { 12 | '^eslint-plugin-import-x$': `/${srcDir}`, 13 | '^eslint-plugin-import-x/package.json$': `/package.json`, 14 | '^eslint-plugin-import-x/(.+)$': `/${srcDir}/$1`, 15 | }, 16 | testMatch: ['/test/**/*.spec.ts'], 17 | transform: { 18 | '^.+\\.(t|j)sx?$': ['@swc-node/jest', {} satisfies SwcOptions], 19 | }, 20 | } satisfies Config 21 | -------------------------------------------------------------------------------- /patches/@typescript-eslint+utils+5.62.0.patch: -------------------------------------------------------------------------------- 1 | diff --git a/node_modules/@typescript-eslint/utils/dist/ts-eslint/Rule.d.ts b/node_modules/@typescript-eslint/utils/dist/ts-eslint/Rule.d.ts 2 | index 9a3a1fd..c6ed412 100644 3 | --- a/node_modules/@typescript-eslint/utils/dist/ts-eslint/Rule.d.ts 4 | +++ b/node_modules/@typescript-eslint/utils/dist/ts-eslint/Rule.d.ts 5 | @@ -6,6 +6,10 @@ import type { Scope } from './Scope'; 6 | import type { SourceCode } from './SourceCode'; 7 | export type RuleRecommendation = 'error' | 'strict' | 'warn' | false; 8 | interface RuleMetaDataDocs { 9 | + /** 10 | + * The category the rule falls under 11 | + */ 12 | + category?: string; 13 | /** 14 | * Concise description of the rule 15 | */ 16 | @@ -15,7 +19,7 @@ interface RuleMetaDataDocs { 17 | * Used by the build tools to generate the recommended and strict configs. 18 | * Set to false to not include it as a recommendation 19 | */ 20 | - recommended: 'error' | 'strict' | 'warn' | false; 21 | + recommended?: 'error' | 'strict' | 'warn' | boolean; 22 | /** 23 | * The URL of the rule's docs 24 | */ 25 | diff --git a/node_modules/@typescript-eslint/utils/dist/ts-eslint/RuleTester.d.ts b/node_modules/@typescript-eslint/utils/dist/ts-eslint/RuleTester.d.ts 26 | index c8afefe..d629d04 100644 27 | --- a/node_modules/@typescript-eslint/utils/dist/ts-eslint/RuleTester.d.ts 28 | +++ b/node_modules/@typescript-eslint/utils/dist/ts-eslint/RuleTester.d.ts 29 | @@ -115,7 +115,7 @@ interface RunTests[]; 31 | } 32 | interface RuleTesterConfig extends Linter.Config { 33 | - readonly parser: string; 34 | + readonly parser?: string; 35 | readonly parserOptions?: Readonly; 36 | } 37 | declare class RuleTesterBase { 38 | -------------------------------------------------------------------------------- /src/config/electron.ts: -------------------------------------------------------------------------------- 1 | import type { PluginConfig } from '../types' 2 | 3 | /** 4 | * Default settings for Electron applications. 5 | */ 6 | export = { 7 | settings: { 8 | 'import-x/core-modules': ['electron'], 9 | }, 10 | } satisfies PluginConfig 11 | -------------------------------------------------------------------------------- /src/config/errors.ts: -------------------------------------------------------------------------------- 1 | import type { PluginConfig } from '../types' 2 | 3 | /** 4 | * unopinionated config. just the things that are necessarily runtime errors 5 | * waiting to happen. 6 | */ 7 | export = { 8 | plugins: ['import-x'], 9 | rules: { 10 | 'import-x/no-unresolved': 2, 11 | 'import-x/named': 2, 12 | 'import-x/namespace': 2, 13 | 'import-x/default': 2, 14 | 'import-x/export': 2, 15 | }, 16 | } satisfies PluginConfig 17 | -------------------------------------------------------------------------------- /src/config/react-native.ts: -------------------------------------------------------------------------------- 1 | import type { PluginConfig } from '../types' 2 | 3 | /** 4 | * adds platform extensions to Node resolver 5 | */ 6 | export = { 7 | settings: { 8 | 'import-x/resolver': { 9 | node: { 10 | // Note: will not complain if only _one_ of these files exists. 11 | extensions: ['.js', '.web.js', '.ios.js', '.android.js'], 12 | }, 13 | }, 14 | }, 15 | } satisfies PluginConfig 16 | -------------------------------------------------------------------------------- /src/config/react.ts: -------------------------------------------------------------------------------- 1 | import type { PluginConfig } from '../types' 2 | 3 | /** 4 | * Adds `.jsx` as an extension, and enables JSX parsing. 5 | * 6 | * Even if _you_ aren't using JSX (or .jsx) directly, if your dependencies 7 | * define jsnext:main and have JSX internally, you may run into problems 8 | * if you don't enable these settings at the top level. 9 | */ 10 | export = { 11 | settings: { 12 | 'import-x/extensions': ['.js', '.jsx'], 13 | }, 14 | parserOptions: { 15 | ecmaFeatures: { 16 | jsx: true, 17 | }, 18 | }, 19 | } satisfies PluginConfig 20 | -------------------------------------------------------------------------------- /src/config/recommended.ts: -------------------------------------------------------------------------------- 1 | import type { PluginConfig } from '../types' 2 | 3 | /** 4 | * The basics. 5 | */ 6 | export = { 7 | plugins: ['import-x'], 8 | 9 | rules: { 10 | // analysis/correctness 11 | 'import-x/no-unresolved': 'error', 12 | 'import-x/named': 'error', 13 | 'import-x/namespace': 'error', 14 | 'import-x/default': 'error', 15 | 'import-x/export': 'error', 16 | 17 | // red flags (thus, warnings) 18 | 'import-x/no-named-as-default': 'warn', 19 | 'import-x/no-named-as-default-member': 'warn', 20 | 'import-x/no-duplicates': 'warn', 21 | }, 22 | 23 | // need all these for parsing dependencies (even if _your_ code doesn't need 24 | // all of them) 25 | parserOptions: { 26 | sourceType: 'module', 27 | ecmaVersion: 2018, 28 | }, 29 | } satisfies PluginConfig 30 | -------------------------------------------------------------------------------- /src/config/stage-0.ts: -------------------------------------------------------------------------------- 1 | import type { PluginConfig } from '../types' 2 | 3 | /** 4 | * Rules in progress. 5 | * 6 | * Do not expect these to adhere to semver across releases. 7 | */ 8 | export = { 9 | plugins: ['import-x'], 10 | rules: { 11 | 'import-x/no-deprecated': 1, 12 | }, 13 | } as PluginConfig 14 | -------------------------------------------------------------------------------- /src/config/typescript.ts: -------------------------------------------------------------------------------- 1 | import type { PluginConfig } from '../types' 2 | 3 | /** 4 | * This config: 5 | * 1) adds `.jsx`, `.ts`, `.cts`, `.mts`, and `.tsx` as an extension 6 | * 2) enables JSX/TSX parsing 7 | */ 8 | 9 | // Omit `.d.ts` because 1) TypeScript compilation already confirms that 10 | // types are resolved, and 2) it would mask an unresolved 11 | // `.ts`/`.tsx`/`.js`/`.jsx` implementation. 12 | const typeScriptExtensions = ['.ts', '.tsx'] as const 13 | 14 | const allExtensions = [...typeScriptExtensions, '.js', '.jsx'] as const 15 | 16 | export = { 17 | settings: { 18 | 'import-x/extensions': allExtensions, 19 | 'import-x/external-module-folders': ['node_modules', 'node_modules/@types'], 20 | 'import-x/parsers': { 21 | '@typescript-eslint/parser': [...typeScriptExtensions, '.cts', '.mts'], 22 | }, 23 | 'import-x/resolver': { 24 | node: { 25 | extensions: allExtensions, 26 | }, 27 | }, 28 | }, 29 | rules: { 30 | // analysis/correctness 31 | 32 | // TypeScript compilation already ensures that named imports exist in the referenced module 33 | 'import-x/named': 'off', 34 | }, 35 | } satisfies PluginConfig 36 | -------------------------------------------------------------------------------- /src/config/warnings.ts: -------------------------------------------------------------------------------- 1 | import type { PluginConfig } from '../types' 2 | 3 | /** 4 | * more opinionated config. 5 | */ 6 | export = { 7 | plugins: ['import-x'], 8 | rules: { 9 | 'import-x/no-named-as-default': 1, 10 | 'import-x/no-named-as-default-member': 1, 11 | 'import-x/no-duplicates': 1, 12 | }, 13 | } satisfies PluginConfig 14 | -------------------------------------------------------------------------------- /src/global.d.ts: -------------------------------------------------------------------------------- 1 | import '@total-typescript/ts-reset' 2 | -------------------------------------------------------------------------------- /src/rules/default.ts: -------------------------------------------------------------------------------- 1 | import type { TSESTree } from '@typescript-eslint/utils' 2 | 3 | import { ExportMap, createRule } from '../utils' 4 | 5 | type MessageId = 'noDefaultExport' 6 | 7 | export = createRule<[], MessageId>({ 8 | name: 'default', 9 | meta: { 10 | type: 'problem', 11 | docs: { 12 | category: 'Static analysis', 13 | description: 14 | 'Ensure a default export is present, given a default import.', 15 | }, 16 | schema: [], 17 | messages: { 18 | noDefaultExport: 19 | 'No default export found in imported module "{{module}}".', 20 | }, 21 | }, 22 | defaultOptions: [], 23 | create(context) { 24 | function checkDefault( 25 | specifierType: 'ImportDefaultSpecifier' | 'ExportDefaultSpecifier', 26 | node: TSESTree.ImportDeclaration | TSESTree.ExportNamedDeclaration, 27 | ) { 28 | const defaultSpecifier = ( 29 | node.specifiers as Array< 30 | TSESTree.ImportClause | TSESTree.ExportSpecifier 31 | > 32 | ).find(specifier => specifier.type === specifierType) 33 | 34 | if (!defaultSpecifier) { 35 | return 36 | } 37 | const imports = ExportMap.get(node.source!.value, context) 38 | if (imports == null) { 39 | return 40 | } 41 | 42 | if (imports.errors.length > 0) { 43 | imports.reportErrors(context, node) 44 | } else if (imports.get('default') === undefined) { 45 | context.report({ 46 | node: defaultSpecifier, 47 | messageId: 'noDefaultExport', 48 | data: { 49 | module: node.source!.value, 50 | }, 51 | }) 52 | } 53 | } 54 | 55 | return { 56 | ImportDeclaration: checkDefault.bind(null, 'ImportDefaultSpecifier'), 57 | ExportNamedDeclaration: checkDefault.bind(null, 'ExportDefaultSpecifier'), 58 | } 59 | }, 60 | }) 61 | -------------------------------------------------------------------------------- /src/rules/exports-last.ts: -------------------------------------------------------------------------------- 1 | import type { TSESTree } from '@typescript-eslint/utils' 2 | 3 | import { createRule } from '../utils' 4 | 5 | const findLastIndex = (array: T[], predicate: (item: T) => boolean) => { 6 | let i = array.length - 1 7 | while (i >= 0) { 8 | if (predicate(array[i])) { 9 | return i 10 | } 11 | i-- 12 | } 13 | return -1 14 | } 15 | 16 | function isNonExportStatement({ type }: TSESTree.Node) { 17 | return ( 18 | type !== 'ExportDefaultDeclaration' && 19 | type !== 'ExportNamedDeclaration' && 20 | type !== 'ExportAllDeclaration' 21 | ) 22 | } 23 | 24 | export = createRule({ 25 | name: 'exports-last', 26 | meta: { 27 | type: 'suggestion', 28 | docs: { 29 | category: 'Style guide', 30 | description: 'Ensure all exports appear after other statements.', 31 | }, 32 | schema: [], 33 | messages: { 34 | end: 'Export statements should appear at the end of the file', 35 | }, 36 | }, 37 | defaultOptions: [], 38 | create(context) { 39 | return { 40 | Program({ body }) { 41 | const lastNonExportStatementIndex = findLastIndex( 42 | body, 43 | isNonExportStatement, 44 | ) 45 | 46 | if (lastNonExportStatementIndex !== -1) { 47 | for (const node of body.slice(0, lastNonExportStatementIndex)) { 48 | if (!isNonExportStatement(node)) { 49 | context.report({ 50 | node, 51 | messageId: 'end', 52 | }) 53 | } 54 | } 55 | } 56 | }, 57 | } 58 | }, 59 | }) 60 | -------------------------------------------------------------------------------- /src/rules/imports-first.ts: -------------------------------------------------------------------------------- 1 | import { ESLintUtils } from '@typescript-eslint/utils' 2 | 3 | import { docsUrl } from '../utils/docs-url' 4 | 5 | import first from './first' 6 | 7 | const createRule = ESLintUtils.RuleCreator(ruleName => 8 | docsUrl(ruleName, '7b25c1cb95ee18acc1531002fd343e1e6031f9ed'), 9 | ) 10 | 11 | export = createRule({ 12 | ...first, 13 | name: 'imports-first', 14 | meta: { 15 | ...first.meta, 16 | deprecated: true, 17 | docs: { 18 | category: 'Style guide', 19 | description: 'Replaced by `import-x/first`.', 20 | }, 21 | }, 22 | }) 23 | -------------------------------------------------------------------------------- /src/rules/max-dependencies.ts: -------------------------------------------------------------------------------- 1 | import type { TSESTree } from '@typescript-eslint/utils' 2 | 3 | import { createRule, moduleVisitor } from '../utils' 4 | 5 | type Options = { 6 | ignoreTypeImports?: boolean 7 | max?: number 8 | } 9 | 10 | type MessageId = 'max' 11 | 12 | export = createRule<[Options?], MessageId>({ 13 | name: 'max-dependencies', 14 | meta: { 15 | type: 'suggestion', 16 | docs: { 17 | category: 'Style guide', 18 | description: 19 | 'Enforce the maximum number of dependencies a module can have.', 20 | }, 21 | schema: [ 22 | { 23 | type: 'object', 24 | properties: { 25 | max: { type: 'number' }, 26 | ignoreTypeImports: { type: 'boolean' }, 27 | }, 28 | additionalProperties: false, 29 | }, 30 | ], 31 | messages: { 32 | max: 'Maximum number of dependencies ({{max}}) exceeded.', 33 | }, 34 | }, 35 | defaultOptions: [], 36 | create(context) { 37 | const { ignoreTypeImports } = context.options[0] || {} 38 | 39 | const dependencies = new Set() // keep track of dependencies 40 | 41 | let lastNode: TSESTree.StringLiteral // keep track of the last node to report on 42 | 43 | return { 44 | 'Program:exit'() { 45 | const { max = 10 } = context.options[0] || {} 46 | 47 | if (dependencies.size <= max) { 48 | return 49 | } 50 | 51 | context.report({ 52 | node: lastNode, 53 | messageId: 'max', 54 | data: { 55 | max, 56 | }, 57 | }) 58 | }, 59 | ...moduleVisitor( 60 | (source, node) => { 61 | if ( 62 | ('importKind' in node && node.importKind !== 'type') || 63 | !ignoreTypeImports 64 | ) { 65 | dependencies.add(source.value) 66 | } 67 | lastNode = source 68 | }, 69 | { commonjs: true }, 70 | ), 71 | } 72 | }, 73 | }) 74 | -------------------------------------------------------------------------------- /src/rules/no-absolute-path.ts: -------------------------------------------------------------------------------- 1 | import path from 'node:path' 2 | 3 | import { 4 | isAbsolute, 5 | createRule, 6 | moduleVisitor, 7 | makeOptionsSchema, 8 | } from '../utils' 9 | import type { ModuleOptions } from '../utils' 10 | 11 | type MessageId = 'absolute' 12 | 13 | export = createRule<[ModuleOptions?], MessageId>({ 14 | name: 'no-absolute-path', 15 | meta: { 16 | type: 'suggestion', 17 | docs: { 18 | category: 'Static analysis', 19 | description: 'Forbid import of modules using absolute paths.', 20 | }, 21 | fixable: 'code', 22 | schema: [makeOptionsSchema()], 23 | messages: { 24 | absolute: 'Do not import modules using an absolute path', 25 | }, 26 | }, 27 | defaultOptions: [], 28 | create(context) { 29 | const options = { esmodule: true, commonjs: true, ...context.options[0] } 30 | return moduleVisitor(source => { 31 | if (!isAbsolute(source.value)) { 32 | return 33 | } 34 | context.report({ 35 | node: source, 36 | messageId: 'absolute', 37 | fix(fixer) { 38 | const resolvedContext = context.getPhysicalFilename 39 | ? context.getPhysicalFilename() 40 | : context.getFilename() 41 | // node.js and web imports work with posix style paths ("/") 42 | let relativePath = path.posix.relative( 43 | path.dirname(resolvedContext), 44 | source.value, 45 | ) 46 | if (!relativePath.startsWith('.')) { 47 | relativePath = `./${relativePath}` 48 | } 49 | return fixer.replaceText(source, JSON.stringify(relativePath)) 50 | }, 51 | }) 52 | }, options) 53 | }, 54 | }) 55 | -------------------------------------------------------------------------------- /src/rules/no-amd.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Rule to prefer imports to AMD 3 | */ 4 | 5 | import { createRule } from '../utils' 6 | 7 | type MessageId = 'amd' 8 | 9 | export = createRule<[], MessageId>({ 10 | name: 'no-amd', 11 | meta: { 12 | type: 'suggestion', 13 | docs: { 14 | category: 'Module systems', 15 | description: 'Forbid AMD `require` and `define` calls.', 16 | }, 17 | schema: [], 18 | messages: { 19 | amd: 'Expected imports instead of AMD {{type}}().', 20 | }, 21 | }, 22 | defaultOptions: [], 23 | create(context) { 24 | return { 25 | CallExpression(node) { 26 | if (context.getScope().type !== 'module') { 27 | return 28 | } 29 | 30 | if (node.callee.type !== 'Identifier') { 31 | return 32 | } 33 | 34 | if (node.callee.name !== 'require' && node.callee.name !== 'define') { 35 | return 36 | } 37 | 38 | // todo: capture define((require, module, exports) => {}) form? 39 | if (node.arguments.length !== 2) { 40 | return 41 | } 42 | 43 | const modules = node.arguments[0] 44 | 45 | if (modules.type !== 'ArrayExpression') { 46 | return 47 | } 48 | 49 | // todo: check second arg type? (identifier or callback) 50 | 51 | context.report({ 52 | node, 53 | messageId: 'amd', 54 | data: { 55 | type: node.callee.name, 56 | }, 57 | }) 58 | }, 59 | } 60 | }, 61 | }) 62 | -------------------------------------------------------------------------------- /src/rules/no-default-export.ts: -------------------------------------------------------------------------------- 1 | import { createRule } from '../utils' 2 | 3 | export = createRule({ 4 | name: 'no-default-export', 5 | meta: { 6 | type: 'suggestion', 7 | docs: { 8 | category: 'Style guide', 9 | description: 'Forbid default exports.', 10 | }, 11 | schema: [], 12 | messages: { 13 | preferNamed: 'Prefer named exports.', 14 | noAliasDefault: 15 | 'Do not alias `{{local}}` as `default`. Just export `{{local}}` itself instead.', 16 | }, 17 | }, 18 | defaultOptions: [], 19 | create(context) { 20 | // ignore non-modules 21 | if (context.parserOptions.sourceType !== 'module') { 22 | return {} 23 | } 24 | 25 | return { 26 | ExportDefaultDeclaration(node) { 27 | const { loc } = context.getSourceCode().getFirstTokens(node)[1] || {} 28 | context.report({ 29 | node, 30 | messageId: 'preferNamed', 31 | loc, 32 | }) 33 | }, 34 | 35 | ExportNamedDeclaration(node) { 36 | for (const specifier of node.specifiers.filter( 37 | specifier => 38 | (specifier.exported.name || 39 | ('value' in specifier.exported && specifier.exported.value)) === 40 | 'default', 41 | )) { 42 | const { loc } = context.getSourceCode().getFirstTokens(node)[1] || {} 43 | // @ts-expect-error - legacy parser type 44 | if (specifier.type === 'ExportDefaultSpecifier') { 45 | context.report({ 46 | node, 47 | messageId: 'preferNamed', 48 | loc, 49 | }) 50 | } else if (specifier.type === 'ExportSpecifier') { 51 | context.report({ 52 | node, 53 | messageId: 'noAliasDefault', 54 | data: { 55 | local: specifier.local.name, 56 | }, 57 | loc, 58 | }) 59 | } 60 | } 61 | }, 62 | } 63 | }, 64 | }) 65 | -------------------------------------------------------------------------------- /src/rules/no-dynamic-require.ts: -------------------------------------------------------------------------------- 1 | import type { TSESTree } from '@typescript-eslint/utils' 2 | 3 | import { createRule } from '../utils' 4 | 5 | function isRequire(node: TSESTree.CallExpression) { 6 | return ( 7 | node && 8 | node.callee && 9 | node.callee.type === 'Identifier' && 10 | node.callee.name === 'require' && 11 | node.arguments.length > 0 12 | ) 13 | } 14 | 15 | function isDynamicImport(node: TSESTree.CallExpression) { 16 | return ( 17 | node && 18 | node.callee && 19 | // @ts-expect-error - legacy parser type 20 | node.callee.type === 'Import' 21 | ) 22 | } 23 | 24 | function isStaticValue( 25 | node: TSESTree.Node, 26 | ): node is TSESTree.Literal | TSESTree.TemplateLiteral { 27 | return ( 28 | node.type === 'Literal' || 29 | (node.type === 'TemplateLiteral' && node.expressions.length === 0) 30 | ) 31 | } 32 | 33 | type Options = { 34 | esmodule?: boolean 35 | } 36 | 37 | type MessageId = 'import' | 'require' 38 | 39 | export = createRule<[Options?], MessageId>({ 40 | name: 'no-dynamic-require', 41 | meta: { 42 | type: 'suggestion', 43 | docs: { 44 | category: 'Static analysis', 45 | description: 'Forbid `require()` calls with expressions.', 46 | }, 47 | schema: [ 48 | { 49 | type: 'object', 50 | properties: { 51 | esmodule: { 52 | type: 'boolean', 53 | }, 54 | }, 55 | additionalProperties: false, 56 | }, 57 | ], 58 | messages: { 59 | import: 'Calls to import() should use string literals', 60 | require: 'Calls to require() should use string literals', 61 | }, 62 | }, 63 | defaultOptions: [], 64 | create(context) { 65 | const options = context.options[0] || {} 66 | 67 | return { 68 | CallExpression(node) { 69 | if (!node.arguments[0] || isStaticValue(node.arguments[0])) { 70 | return 71 | } 72 | if (isRequire(node)) { 73 | return context.report({ 74 | node, 75 | messageId: 'require', 76 | }) 77 | } 78 | if (options.esmodule && isDynamicImport(node)) { 79 | return context.report({ 80 | node, 81 | messageId: 'import', 82 | }) 83 | } 84 | }, 85 | ImportExpression(node) { 86 | if (!options.esmodule || isStaticValue(node.source)) { 87 | return 88 | } 89 | return context.report({ 90 | node, 91 | messageId: 'import', 92 | }) 93 | }, 94 | } 95 | }, 96 | }) 97 | -------------------------------------------------------------------------------- /src/rules/no-mutable-exports.ts: -------------------------------------------------------------------------------- 1 | import type { TSESLint, TSESTree } from '@typescript-eslint/utils' 2 | 3 | import { createRule } from '../utils' 4 | 5 | type MessageId = 'noMutable' 6 | 7 | export = createRule<[], MessageId>({ 8 | name: 'no-mutable-exports', 9 | meta: { 10 | type: 'suggestion', 11 | docs: { 12 | category: 'Helpful warnings', 13 | description: 'Forbid the use of mutable exports with `var` or `let`.', 14 | }, 15 | schema: [], 16 | messages: { 17 | noMutable: "Exporting mutable '{{kind}}' binding, use 'const' instead.", 18 | }, 19 | }, 20 | defaultOptions: [], 21 | create(context) { 22 | function checkDeclaration(node: TSESTree.NamedExportDeclarations) { 23 | if ('kind' in node && (node.kind === 'var' || node.kind === 'let')) { 24 | context.report({ 25 | node, 26 | messageId: 'noMutable', 27 | data: { 28 | kind: node.kind, 29 | }, 30 | }) 31 | } 32 | } 33 | 34 | function checkDeclarationsInScope( 35 | { variables }: TSESLint.Scope.Scope, 36 | name: string, 37 | ) { 38 | for (const variable of variables) { 39 | if (variable.name === name) { 40 | for (const def of variable.defs) { 41 | if (def.type === 'Variable' && def.parent) { 42 | checkDeclaration(def.parent) 43 | } 44 | } 45 | } 46 | } 47 | } 48 | 49 | return { 50 | ExportDefaultDeclaration(node) { 51 | const scope = context.getScope() 52 | 53 | if ('name' in node.declaration) { 54 | checkDeclarationsInScope(scope, node.declaration.name) 55 | } 56 | }, 57 | ExportNamedDeclaration(node) { 58 | const scope = context.getScope() 59 | 60 | if (node.declaration) { 61 | checkDeclaration(node.declaration) 62 | } else if (!node.source) { 63 | for (const specifier of node.specifiers) { 64 | checkDeclarationsInScope(scope, specifier.local.name) 65 | } 66 | } 67 | }, 68 | } 69 | }, 70 | }) 71 | -------------------------------------------------------------------------------- /src/rules/no-named-as-default.ts: -------------------------------------------------------------------------------- 1 | import type { TSESTree } from '@typescript-eslint/utils' 2 | 3 | import { importDeclaration, ExportMap, createRule } from '../utils' 4 | 5 | type MessageId = 'default' 6 | 7 | export = createRule<[], MessageId>({ 8 | name: 'no-named-as-default', 9 | meta: { 10 | type: 'problem', 11 | docs: { 12 | category: 'Helpful warnings', 13 | description: 14 | 'Forbid use of exported name as identifier of default export.', 15 | }, 16 | schema: [], 17 | messages: { 18 | default: 19 | "Using exported name '{{name}}' as identifier for default export.", 20 | }, 21 | }, 22 | defaultOptions: [], 23 | create(context) { 24 | function checkDefault( 25 | nameKey: 'local' | 'exported', 26 | defaultSpecifier: TSESTree.ImportDefaultSpecifier, 27 | // | TSESTree.ExportDefaultSpecifier, 28 | ) { 29 | // #566: default is a valid specifier 30 | // @ts-expect-error - ExportDefaultSpecifier is unavailable yet 31 | const nameValue = defaultSpecifier[nameKey].name as string 32 | 33 | if (nameValue === 'default') { 34 | return 35 | } 36 | 37 | const declaration = importDeclaration(context) 38 | 39 | const imports = ExportMap.get(declaration.source.value, context) 40 | if (imports == null) { 41 | return 42 | } 43 | 44 | if (imports.errors.length > 0) { 45 | imports.reportErrors(context, declaration) 46 | return 47 | } 48 | 49 | if (imports.has('default') && imports.has(nameValue)) { 50 | context.report({ 51 | node: defaultSpecifier, 52 | messageId: 'default', 53 | data: { 54 | name: nameValue, 55 | }, 56 | }) 57 | } 58 | } 59 | return { 60 | ImportDefaultSpecifier: checkDefault.bind(null, 'local'), 61 | ExportDefaultSpecifier: checkDefault.bind(null, 'exported'), 62 | } 63 | }, 64 | }) 65 | -------------------------------------------------------------------------------- /src/rules/no-named-default.ts: -------------------------------------------------------------------------------- 1 | import { createRule } from '../utils' 2 | 3 | type MessageId = 'default' 4 | 5 | export = createRule<[], MessageId>({ 6 | name: 'no-named-default', 7 | meta: { 8 | type: 'suggestion', 9 | docs: { 10 | category: 'Style guide', 11 | description: 'Forbid named default exports.', 12 | }, 13 | schema: [], 14 | messages: { 15 | default: `Use default import syntax to import '{{importName}}'.`, 16 | }, 17 | }, 18 | defaultOptions: [], 19 | create(context) { 20 | return { 21 | ImportDeclaration(node) { 22 | for (const im of node.specifiers) { 23 | if ( 24 | 'importKind' in im && 25 | (im.importKind === 'type' || 26 | // @ts-expect-error - flow type 27 | im.importKind === 'typeof') 28 | ) { 29 | continue 30 | } 31 | 32 | if ( 33 | im.type === 'ImportSpecifier' && 34 | (im.imported.name || 35 | // @ts-expect-error - legacy parser type 36 | im.imported.value) === 'default' 37 | ) { 38 | context.report({ 39 | node: im.local, 40 | messageId: 'default', 41 | data: { 42 | importName: im.local.name, 43 | }, 44 | }) 45 | } 46 | } 47 | }, 48 | } 49 | }, 50 | }) 51 | -------------------------------------------------------------------------------- /src/rules/no-named-export.ts: -------------------------------------------------------------------------------- 1 | import { createRule } from '../utils' 2 | 3 | export = createRule({ 4 | name: 'no-named-export', 5 | meta: { 6 | type: 'suggestion', 7 | docs: { 8 | category: 'Style guide', 9 | description: 'Forbid named exports.', 10 | }, 11 | schema: [], 12 | messages: { 13 | noAllowed: 'Named exports are not allowed.', 14 | }, 15 | }, 16 | defaultOptions: [], 17 | create(context) { 18 | // ignore non-modules 19 | if (context.parserOptions.sourceType !== 'module') { 20 | return {} 21 | } 22 | 23 | return { 24 | ExportAllDeclaration(node) { 25 | context.report({ node, messageId: 'noAllowed' }) 26 | }, 27 | 28 | ExportNamedDeclaration(node) { 29 | if (node.specifiers.length === 0) { 30 | return context.report({ node, messageId: 'noAllowed' }) 31 | } 32 | 33 | const someNamed = node.specifiers.some( 34 | specifier => 35 | (specifier.exported.name || 36 | ('value' in specifier.exported && specifier.exported.value)) !== 37 | 'default', 38 | ) 39 | if (someNamed) { 40 | context.report({ node, messageId: 'noAllowed' }) 41 | } 42 | }, 43 | } 44 | }, 45 | }) 46 | -------------------------------------------------------------------------------- /src/rules/no-nodejs-modules.ts: -------------------------------------------------------------------------------- 1 | import { importType, createRule, moduleVisitor } from '../utils' 2 | 3 | type Options = { 4 | allow?: string[] 5 | } 6 | 7 | type MessageId = 'builtin' 8 | 9 | export = createRule<[Options?], MessageId>({ 10 | name: 'no-nodejs-modules', 11 | meta: { 12 | type: 'suggestion', 13 | docs: { 14 | category: 'Module systems', 15 | description: 'Forbid Node.js builtin modules.', 16 | }, 17 | schema: [ 18 | { 19 | type: 'object', 20 | properties: { 21 | allow: { 22 | type: 'array', 23 | uniqueItems: true, 24 | items: { 25 | type: 'string', 26 | }, 27 | }, 28 | }, 29 | additionalProperties: false, 30 | }, 31 | ], 32 | messages: { 33 | builtin: 'Do not import Node.js builtin module "{{moduleName}}"', 34 | }, 35 | }, 36 | defaultOptions: [], 37 | create(context) { 38 | const options = context.options[0] || {} 39 | const allowed = options.allow || [] 40 | 41 | return moduleVisitor( 42 | (source, node) => { 43 | const moduleName = source.value 44 | if ( 45 | !allowed.includes(moduleName) && 46 | importType(moduleName, context) === 'builtin' 47 | ) { 48 | context.report({ 49 | node, 50 | messageId: 'builtin', 51 | data: { 52 | moduleName, 53 | }, 54 | }) 55 | } 56 | }, 57 | { commonjs: true }, 58 | ) 59 | }, 60 | }) 61 | -------------------------------------------------------------------------------- /src/rules/no-relative-parent-imports.ts: -------------------------------------------------------------------------------- 1 | import path from 'node:path' 2 | 3 | import type { ModuleOptions } from '../utils' 4 | import { 5 | importType, 6 | createRule, 7 | moduleVisitor, 8 | makeOptionsSchema, 9 | resolve, 10 | } from '../utils' 11 | 12 | type MessageId = 'noAllowed' 13 | 14 | export = createRule<[ModuleOptions?], MessageId>({ 15 | name: 'no-relative-parent-imports', 16 | meta: { 17 | type: 'suggestion', 18 | docs: { 19 | category: 'Static analysis', 20 | description: 'Forbid importing modules from parent directories.', 21 | }, 22 | schema: [makeOptionsSchema()], 23 | messages: { 24 | noAllowed: 25 | "Relative imports from parent directories are not allowed. Please either pass what you're importing through at runtime (dependency injection), move `{{filename}}` to same directory as `{{depPath}}` or consider making `{{depPath}}` a package.", 26 | }, 27 | }, 28 | defaultOptions: [], 29 | create(context) { 30 | const filename = context.getPhysicalFilename 31 | ? context.getPhysicalFilename() 32 | : context.getFilename() 33 | 34 | if (filename === '') { 35 | return {} 36 | } // can't check a non-file 37 | 38 | return moduleVisitor(sourceNode => { 39 | const depPath = sourceNode.value 40 | 41 | if (importType(depPath, context) === 'external') { 42 | // ignore packages 43 | return 44 | } 45 | 46 | const absDepPath = resolve(depPath, context) 47 | 48 | if (!absDepPath) { 49 | // unable to resolve path 50 | return 51 | } 52 | 53 | const relDepPath = path.relative(path.dirname(filename), absDepPath) 54 | 55 | if (importType(relDepPath, context) === 'parent') { 56 | context.report({ 57 | node: sourceNode, 58 | messageId: 'noAllowed', 59 | data: { 60 | filename: path.basename(filename), 61 | depPath, 62 | }, 63 | }) 64 | } 65 | }, context.options[0]) 66 | }, 67 | }) 68 | -------------------------------------------------------------------------------- /src/rules/no-self-import.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Forbids a module from importing itself 3 | */ 4 | 5 | import type { TSESTree } from '@typescript-eslint/utils' 6 | 7 | import type { RuleContext } from '../types' 8 | import { createRule, moduleVisitor, resolve } from '../utils' 9 | 10 | type MessageId = 'self' 11 | 12 | function isImportingSelf( 13 | context: RuleContext, 14 | node: TSESTree.Node, 15 | requireName: string, 16 | ) { 17 | const filePath = context.getPhysicalFilename 18 | ? context.getPhysicalFilename() 19 | : context.getFilename() 20 | 21 | // If the input is from stdin, this test can't fail 22 | if (filePath !== '' && filePath === resolve(requireName, context)) { 23 | context.report({ 24 | node, 25 | messageId: 'self', 26 | }) 27 | } 28 | } 29 | 30 | export = createRule<[], MessageId>({ 31 | name: 'no-self-import', 32 | meta: { 33 | type: 'problem', 34 | docs: { 35 | category: 'Static analysis', 36 | description: 'Forbid a module from importing itself.', 37 | recommended: true, 38 | }, 39 | schema: [], 40 | messages: { 41 | self: 'Module imports itself.', 42 | }, 43 | }, 44 | defaultOptions: [], 45 | create(context) { 46 | return moduleVisitor( 47 | (source, node) => { 48 | isImportingSelf(context, node, source.value) 49 | }, 50 | { commonjs: true }, 51 | ) 52 | }, 53 | }) 54 | -------------------------------------------------------------------------------- /src/rules/no-unresolved.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Ensures that an imported path exists, given resolution rules. 3 | */ 4 | 5 | import type { ModuleOptions } from '../utils' 6 | import { 7 | createRule, 8 | makeOptionsSchema, 9 | moduleVisitor, 10 | CASE_SENSITIVE_FS, 11 | fileExistsWithCaseSync, 12 | resolve, 13 | ModuleCache, 14 | } from '../utils' 15 | 16 | type Options = ModuleOptions & { 17 | caseSensitive?: boolean 18 | caseSensitiveStrict?: boolean 19 | } 20 | 21 | type MessageId = 'unresolved' | 'casingMismatch' 22 | 23 | export = createRule<[Options?], MessageId>({ 24 | name: 'no-unresolved', 25 | meta: { 26 | type: 'problem', 27 | docs: { 28 | category: 'Static analysis', 29 | description: 30 | 'Ensure imports point to a file/module that can be resolved.', 31 | }, 32 | schema: [ 33 | makeOptionsSchema({ 34 | caseSensitive: { type: 'boolean', default: true }, 35 | caseSensitiveStrict: { type: 'boolean' }, 36 | }), 37 | ], 38 | messages: { 39 | unresolved: "Unable to resolve path to module '{{module}}'.", 40 | casingMismatch: 41 | 'Casing of {{module}} does not match the underlying filesystem.', 42 | }, 43 | }, 44 | defaultOptions: [], 45 | create(context) { 46 | const options = context.options[0] || {} 47 | 48 | return moduleVisitor(function checkSourceValue(source, node) { 49 | // ignore type-only imports and exports 50 | if ( 51 | ('importKind' in node && node.importKind === 'type') || 52 | ('exportKind' in node && node.exportKind === 'type') 53 | ) { 54 | return 55 | } 56 | 57 | const caseSensitive = 58 | !CASE_SENSITIVE_FS && options.caseSensitive !== false 59 | const caseSensitiveStrict = 60 | !CASE_SENSITIVE_FS && options.caseSensitiveStrict 61 | 62 | const resolvedPath = resolve(source.value, context) 63 | 64 | if (resolvedPath === undefined) { 65 | context.report({ 66 | node: source, 67 | messageId: 'unresolved', 68 | data: { 69 | module: source.value, 70 | }, 71 | }) 72 | } else if (caseSensitive || caseSensitiveStrict) { 73 | const cacheSettings = ModuleCache.getSettings(context.settings) 74 | if ( 75 | !fileExistsWithCaseSync( 76 | resolvedPath, 77 | cacheSettings, 78 | caseSensitiveStrict, 79 | ) 80 | ) { 81 | context.report({ 82 | node: source, 83 | messageId: 'casingMismatch', 84 | data: { 85 | module: source.value, 86 | }, 87 | }) 88 | } 89 | } 90 | }, options) 91 | }, 92 | }) 93 | -------------------------------------------------------------------------------- /src/rules/no-webpack-loader-syntax.ts: -------------------------------------------------------------------------------- 1 | import { createRule, moduleVisitor } from '../utils' 2 | 3 | export = createRule({ 4 | name: 'no-webpack-loader-syntax', 5 | meta: { 6 | type: 'problem', 7 | docs: { 8 | category: 'Static analysis', 9 | description: 'Forbid webpack loader syntax in imports.', 10 | }, 11 | schema: [], 12 | messages: { 13 | unexpected: 14 | "Unexpected '!' in '{{name}}'. Do not use import syntax to configure webpack loaders.", 15 | }, 16 | }, 17 | defaultOptions: [], 18 | create(context) { 19 | return moduleVisitor( 20 | (source, node) => { 21 | if (source.value?.includes('!')) { 22 | context.report({ 23 | node, 24 | messageId: 'unexpected', 25 | data: { 26 | name: source.value, 27 | }, 28 | }) 29 | } 30 | }, 31 | { commonjs: true }, 32 | ) 33 | }, 34 | }) 35 | -------------------------------------------------------------------------------- /src/rules/unambiguous.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Report modules that could parse incorrectly as scripts. 3 | */ 4 | 5 | import { createRule, isUnambiguousModule } from '../utils' 6 | 7 | export = createRule({ 8 | name: 'unambiguous', 9 | meta: { 10 | type: 'suggestion', 11 | docs: { 12 | category: 'Module systems', 13 | description: 14 | 'Forbid potentially ambiguous parse goal (`script` vs. `module`).', 15 | }, 16 | schema: [], 17 | messages: { 18 | module: 'This module could be parsed as a valid script.', 19 | }, 20 | }, 21 | defaultOptions: [], 22 | create(context) { 23 | // ignore non-modules 24 | if (context.parserOptions.sourceType !== 'module') { 25 | return {} 26 | } 27 | 28 | return { 29 | Program(ast) { 30 | if (!isUnambiguousModule(ast)) { 31 | context.report({ 32 | node: ast, 33 | messageId: 'module', 34 | }) 35 | } 36 | }, 37 | } 38 | }, 39 | }) 40 | -------------------------------------------------------------------------------- /src/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.base", 3 | "compilerOptions": { 4 | "rootDir": ".", 5 | "outDir": "../lib" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/utils/constants.ts: -------------------------------------------------------------------------------- 1 | export const pluginName = 'import-x' 2 | 3 | export type PluginName = typeof pluginName 4 | -------------------------------------------------------------------------------- /src/utils/create-rule.ts: -------------------------------------------------------------------------------- 1 | import { ESLintUtils } from '@typescript-eslint/utils' 2 | 3 | import { docsUrl } from './docs-url' 4 | 5 | export const createRule = ESLintUtils.RuleCreator(docsUrl) 6 | -------------------------------------------------------------------------------- /src/utils/declared-scope.ts: -------------------------------------------------------------------------------- 1 | import type { RuleContext } from '../types' 2 | 3 | export function declaredScope(context: RuleContext, name: string) { 4 | const references = context.getScope().references 5 | const reference = references.find(x => x.identifier.name === name) 6 | if (!reference || !reference.resolved) { 7 | return 8 | } 9 | return reference.resolved.scope.type 10 | } 11 | -------------------------------------------------------------------------------- /src/utils/docs-url.ts: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment 2 | // @ts-ignore - The structures of `lib` and `src` are same 3 | import pkg from '../../package.json' 4 | 5 | const repoUrl = 'https://github.com/un-ts/eslint-plugin-import-x' 6 | 7 | export const docsUrl = (ruleName: string, commitish = `v${pkg.version}`) => 8 | `${repoUrl}/blob/${commitish}/docs/rules/${ruleName}.md` 9 | -------------------------------------------------------------------------------- /src/utils/hash.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * utilities for hashing config objects. 3 | * basically iteratively updates hash with a JSON-like format 4 | */ 5 | 6 | import type { Hash } from 'node:crypto' 7 | import { createHash } from 'node:crypto' 8 | 9 | export function hashify(value?: unknown, hash?: Hash) { 10 | hash ??= createHash('sha256') 11 | 12 | if (Array.isArray(value)) { 13 | hashArray(value, hash) 14 | } else if (value instanceof Object) { 15 | hashObject(value, hash) 16 | } else { 17 | hash.update(JSON.stringify(value) || 'undefined') 18 | } 19 | 20 | return hash 21 | } 22 | 23 | export function hashArray(array: unknown[], hash?: Hash) { 24 | hash ??= createHash('sha256') 25 | 26 | hash.update('[') 27 | 28 | for (const element of array) { 29 | hashify(element, hash) 30 | hash.update(',') 31 | } 32 | 33 | hash.update(']') 34 | 35 | return hash 36 | } 37 | 38 | export function hashObject(object: T, hash?: Hash) { 39 | hash ??= createHash('sha256') 40 | 41 | hash.update('{') 42 | 43 | for (const key of Object.keys(object).sort()) { 44 | hash.update(JSON.stringify(key)) 45 | hash.update(':') 46 | hashify(object[key as keyof T], hash) 47 | hash.update(',') 48 | } 49 | 50 | hash.update('}') 51 | 52 | return hash 53 | } 54 | -------------------------------------------------------------------------------- /src/utils/ignore.ts: -------------------------------------------------------------------------------- 1 | import path from 'node:path' 2 | 3 | import debug from 'debug' 4 | 5 | import type { 6 | ChildContext, 7 | FileExtension, 8 | PluginSettings, 9 | RuleContext, 10 | } from '../types' 11 | 12 | const log = debug('eslint-plugin-import-x:utils:ignore') 13 | 14 | // one-shot memoized 15 | let cachedSet: Set 16 | let lastSettings: PluginSettings 17 | 18 | function validExtensions(context: ChildContext | RuleContext) { 19 | if (cachedSet && context.settings === lastSettings) { 20 | return cachedSet 21 | } 22 | 23 | lastSettings = context.settings 24 | cachedSet = getFileExtensions(context.settings) 25 | return cachedSet 26 | } 27 | 28 | export function getFileExtensions(settings: PluginSettings) { 29 | // start with explicit JS-parsed extensions 30 | const exts = new Set( 31 | settings['import-x/extensions'] || ['.js'], 32 | ) 33 | 34 | // all alternate parser extensions are also valid 35 | if ('import-x/parsers' in settings) { 36 | for (const parser in settings['import-x/parsers']) { 37 | const parserSettings = settings['import-x/parsers'][parser] 38 | if (!Array.isArray(parserSettings)) { 39 | throw new TypeError(`"settings" for ${parser} must be an array`) 40 | } 41 | for (const ext of parserSettings) exts.add(ext) 42 | } 43 | } 44 | 45 | return exts 46 | } 47 | 48 | export function ignore(filepath: string, context: ChildContext | RuleContext) { 49 | // check extension whitelist first (cheap) 50 | if (!hasValidExtension(filepath, context)) { 51 | return true 52 | } 53 | 54 | const ignoreStrings = context.settings['import-x/ignore'] 55 | 56 | if (!ignoreStrings?.length) { 57 | return false 58 | } 59 | 60 | for (const ignoreString of ignoreStrings) { 61 | const regex = new RegExp(ignoreString) 62 | if (regex.test(filepath)) { 63 | log(`ignoring ${filepath}, matched pattern /${ignoreString}/`) 64 | return true 65 | } 66 | } 67 | 68 | return false 69 | } 70 | 71 | export function hasValidExtension( 72 | filepath: string, 73 | context: ChildContext | RuleContext, 74 | ): filepath is `${string}${FileExtension}` { 75 | return validExtensions(context).has(path.extname(filepath) as FileExtension) 76 | } 77 | -------------------------------------------------------------------------------- /src/utils/import-declaration.ts: -------------------------------------------------------------------------------- 1 | import type { TSESTree } from '@typescript-eslint/utils' 2 | 3 | import type { RuleContext } from '../types' 4 | 5 | export const importDeclaration = (context: RuleContext) => { 6 | const ancestors = context.getAncestors() 7 | return ancestors[ancestors.length - 1] as TSESTree.ImportDeclaration 8 | } 9 | -------------------------------------------------------------------------------- /src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './constants' 2 | export * from './create-rule' 3 | export * from './declared-scope' 4 | export * from './docs-url' 5 | export * from './export-map' 6 | export * from './hash' 7 | export * from './ignore' 8 | export * from './import-declaration' 9 | export * from './import-type' 10 | export * from './module-cache' 11 | export * from './module-require' 12 | export * from './module-visitor' 13 | export * from './package-path' 14 | export * from './parse' 15 | export * from './pkg-dir' 16 | export * from './pkg-up' 17 | export * from './read-pkg-up' 18 | export * from './resolve' 19 | export * from './static-require' 20 | export * from './unambiguous' 21 | export * from './visit' 22 | -------------------------------------------------------------------------------- /src/utils/module-cache.ts: -------------------------------------------------------------------------------- 1 | import debug from 'debug' 2 | 3 | import type { ImportSettings, PluginSettings } from '../types' 4 | 5 | const log = debug('eslint-plugin-import-x:utils:ModuleCache') 6 | 7 | export type CacheKey = unknown 8 | 9 | export type CacheObject = { 10 | result: unknown 11 | lastSeen: ReturnType 12 | } 13 | 14 | export class ModuleCache { 15 | constructor(public map: Map = new Map()) {} 16 | 17 | set(cacheKey: CacheKey, result: unknown) { 18 | this.map.set(cacheKey, { 19 | result, 20 | lastSeen: process.hrtime(), 21 | }) 22 | log('setting entry for', cacheKey) 23 | return result 24 | } 25 | 26 | get(cacheKey: CacheKey, settings: ImportSettings['cache']): T | undefined { 27 | if (this.map.has(cacheKey)) { 28 | const f = this.map.get(cacheKey) 29 | // check freshness 30 | // @ts-expect-error TS can't narrow properly from `has` and `get` 31 | if (process.hrtime(f.lastSeen)[0] < settings.lifetime) { 32 | return f!.result as T 33 | } 34 | } else { 35 | log('cache miss for', cacheKey) 36 | } 37 | // cache miss 38 | } 39 | 40 | static getSettings(settings: PluginSettings) { 41 | const cacheSettings = { 42 | lifetime: 30, // seconds 43 | ...settings['import-x/cache'], 44 | } 45 | 46 | // parse infinity 47 | if ( 48 | (['∞', 'Infinity'] as const).includes( 49 | // @ts-expect-error - TS can't narrow properly from `includes` 50 | cacheSettings.lifetime, 51 | ) 52 | ) { 53 | cacheSettings.lifetime = Number.POSITIVE_INFINITY 54 | } 55 | 56 | return cacheSettings as ImportSettings['cache'] & { 57 | lifetime: number 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/utils/module-require.ts: -------------------------------------------------------------------------------- 1 | import Module from 'node:module' 2 | import path from 'node:path' 3 | 4 | // borrowed from @babel/eslint-parser 5 | function createModule(filename: string) { 6 | const mod = new Module(filename) 7 | mod.filename = filename 8 | // @ts-expect-error _nodeModulesPaths are undocumented 9 | mod.paths = Module._nodeModulePaths(path.dirname(filename)) 10 | return mod 11 | } 12 | 13 | export function moduleRequire(p: string): T { 14 | try { 15 | // attempt to get espree relative to eslint 16 | const eslintPath = require.resolve('eslint') 17 | const eslintModule = createModule(eslintPath) 18 | // @ts-expect-error _resolveFilename is undocumented 19 | return require(Module._resolveFilename(p, eslintModule)) 20 | } catch { 21 | // 22 | } 23 | 24 | try { 25 | // try relative to entry point 26 | return require.main!.require(p) 27 | } catch { 28 | // 29 | } 30 | 31 | // finally, try from here 32 | return require(p) 33 | } 34 | -------------------------------------------------------------------------------- /src/utils/package-path.ts: -------------------------------------------------------------------------------- 1 | import path from 'node:path' 2 | 3 | import type { RuleContext } from '../types' 4 | 5 | import { pkgUp } from './pkg-up' 6 | import { readPkgUp } from './read-pkg-up' 7 | 8 | export function getContextPackagePath(context: RuleContext) { 9 | return getFilePackagePath( 10 | context.getPhysicalFilename 11 | ? context.getPhysicalFilename() 12 | : context.getFilename(), 13 | ) 14 | } 15 | 16 | export function getFilePackagePath(filePath: string) { 17 | return path.dirname(pkgUp({ cwd: filePath })!) 18 | } 19 | 20 | export function getFilePackageName(filePath: string): string | null { 21 | const { pkg, path: pkgPath } = readPkgUp({ cwd: filePath }) 22 | if (pkg) { 23 | // recursion in case of intermediate esm package.json without name found 24 | return pkg.name || getFilePackageName(path.resolve(pkgPath, '../..')) 25 | } 26 | return null 27 | } 28 | -------------------------------------------------------------------------------- /src/utils/pkg-dir.ts: -------------------------------------------------------------------------------- 1 | import path from 'node:path' 2 | 3 | import { pkgUp } from './pkg-up' 4 | 5 | export function pkgDir(cwd: string) { 6 | const fp = pkgUp({ cwd }) 7 | return fp ? path.dirname(fp) : null 8 | } 9 | -------------------------------------------------------------------------------- /src/utils/pkg-up.ts: -------------------------------------------------------------------------------- 1 | import fs from 'node:fs' 2 | import path from 'node:path' 3 | 4 | function findUp(filename: string | string[], cwd?: string): string | null { 5 | let dir = path.resolve(cwd || '') 6 | const root = path.parse(dir).root 7 | 8 | const filenames = [filename].flat() 9 | 10 | // eslint-disable-next-line no-constant-condition 11 | while (true) { 12 | const file = filenames.find(el => fs.existsSync(path.resolve(dir, el))) 13 | 14 | if (file) { 15 | return path.resolve(dir, file) 16 | } 17 | if (dir === root) { 18 | return null 19 | } 20 | 21 | dir = path.dirname(dir) 22 | } 23 | } 24 | 25 | export function pkgUp(opts?: { cwd?: string }) { 26 | return findUp('package.json', opts && opts.cwd) 27 | } 28 | -------------------------------------------------------------------------------- /src/utils/read-pkg-up.ts: -------------------------------------------------------------------------------- 1 | import fs from 'node:fs' 2 | 3 | import type { PackageJson } from 'type-fest' 4 | 5 | import { pkgUp } from './pkg-up' 6 | 7 | function stripBOM(str: string) { 8 | return str.replace(/^\uFEFF/, '') 9 | } 10 | 11 | // eslint-disable-next-line eslint-plugin/require-meta-docs-description, eslint-plugin/require-meta-type, eslint-plugin/prefer-message-ids, eslint-plugin/prefer-object-rule, eslint-plugin/require-meta-schema 12 | export function readPkgUp(opts?: { cwd?: string }) { 13 | const fp = pkgUp(opts) 14 | 15 | if (!fp) { 16 | return {} 17 | } 18 | 19 | try { 20 | return { 21 | pkg: JSON.parse( 22 | stripBOM(fs.readFileSync(fp, { encoding: 'utf8' })), 23 | ) as PackageJson & { 24 | name: string 25 | }, 26 | path: fp, 27 | } 28 | } catch { 29 | return {} 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/utils/static-require.ts: -------------------------------------------------------------------------------- 1 | import type { TSESTree } from '@typescript-eslint/utils' 2 | 3 | // todo: merge with module visitor 4 | export function isStaticRequire(node: TSESTree.CallExpression) { 5 | return ( 6 | node && 7 | node.callee && 8 | node.callee.type === 'Identifier' && 9 | node.callee.name === 'require' && 10 | node.arguments.length === 1 && 11 | node.arguments[0].type === 'Literal' && 12 | typeof node.arguments[0].value === 'string' 13 | ) 14 | } 15 | -------------------------------------------------------------------------------- /src/utils/unambiguous.ts: -------------------------------------------------------------------------------- 1 | import type { TSESTree } from '@typescript-eslint/utils' 2 | 3 | const pattern = /(^|;)\s*(export|import)((\s+\w)|(\s*[*={]))|import\(/m 4 | /** 5 | * detect possible imports/exports without a full parse. 6 | * 7 | * A negative test means that a file is definitely _not_ a module. 8 | * A positive test means it _could_ be. 9 | * 10 | * Not perfect, just a fast way to disqualify large non-ES6 modules and 11 | * avoid a parse. 12 | */ 13 | export function isMaybeUnambiguousModule(content: string) { 14 | return pattern.test(content) 15 | } 16 | 17 | // future-/Babel-proof at the expense of being a little loose 18 | const unambiguousNodeType = 19 | /^(?:(?:Exp|Imp)ort.*Declaration|TSExportAssignment)$/ 20 | 21 | /** 22 | * Given an AST, return true if the AST unambiguously represents a module. 23 | */ 24 | export function isUnambiguousModule(ast: TSESTree.Program) { 25 | return ast.body && ast.body.some(node => unambiguousNodeType.test(node.type)) 26 | } 27 | -------------------------------------------------------------------------------- /src/utils/visit.ts: -------------------------------------------------------------------------------- 1 | import type { TSESTree } from '@typescript-eslint/utils' 2 | 3 | export function visit( 4 | node: TSESTree.Node, 5 | keys: { [k in TSESTree.Node['type']]?: Array } | null, 6 | visitorSpec: { 7 | [k in TSESTree.Node['type'] | `${TSESTree.Node['type']}:Exit`]?: ( 8 | node: TSESTree.Node, 9 | ) => void 10 | }, 11 | ) { 12 | if (!node || !keys) { 13 | return 14 | } 15 | 16 | const type = node.type 17 | const visitor = visitorSpec[type] 18 | if (typeof visitor === 'function') { 19 | visitor(node) 20 | } 21 | 22 | const childFields = keys[type] 23 | if (!childFields) { 24 | return 25 | } 26 | 27 | for (const fieldName of childFields) { 28 | for (const item of [node[fieldName]].flat()) { 29 | if (!item || typeof item !== 'object' || !('type' in item)) { 30 | continue 31 | } 32 | visit(item, keys, visitorSpec) 33 | } 34 | } 35 | 36 | const exit = visitorSpec[`${type}:Exit`] 37 | 38 | if (typeof exit === 'function') { 39 | exit(node) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /test/config/typescript.spec.ts: -------------------------------------------------------------------------------- 1 | import config from 'eslint-plugin-import-x/config/typescript' 2 | 3 | describe('config typescript', () => { 4 | // https://github.com/import-js/eslint-plugin-import/issues/1525 5 | it('should mark @types paths as external', () => { 6 | const externalModuleFolders = 7 | config.settings['import-x/external-module-folders'] 8 | expect(externalModuleFolders).toBeDefined() 9 | expect(externalModuleFolders).toContain('node_modules') 10 | expect(externalModuleFolders).toContain('node_modules/@types') 11 | }) 12 | }) 13 | -------------------------------------------------------------------------------- /test/fixtures/@importType/index.js: -------------------------------------------------------------------------------- 1 | /* for importType test, just needs to exist */ 2 | -------------------------------------------------------------------------------- /test/fixtures/@my-alias/fn.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/eslint-plugin-import-x/4dac1cb2ef94e6357f4ae84185358f69f626cfb7/test/fixtures/@my-alias/fn.js -------------------------------------------------------------------------------- /test/fixtures/CaseyKasem.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/eslint-plugin-import-x/4dac1cb2ef94e6357f4ae84185358f69f626cfb7/test/fixtures/CaseyKasem.js -------------------------------------------------------------------------------- /test/fixtures/alternate-root/in-alternate-root.js: -------------------------------------------------------------------------------- 1 | export const DEEP = 'RISING' 2 | -------------------------------------------------------------------------------- /test/fixtures/bar.coffee: -------------------------------------------------------------------------------- 1 | console.log 'bar' 2 | -------------------------------------------------------------------------------- /test/fixtures/bar.js: -------------------------------------------------------------------------------- 1 | export default 'bar' 2 | export function foo() { 3 | return 'foo' 4 | } 5 | -------------------------------------------------------------------------------- /test/fixtures/bar.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /test/fixtures/bar.jsx: -------------------------------------------------------------------------------- 1 | export default null 2 | -------------------------------------------------------------------------------- /test/fixtures/bar/index.js: -------------------------------------------------------------------------------- 1 | export default 4 2 | -------------------------------------------------------------------------------- /test/fixtures/broken-trampoline.js: -------------------------------------------------------------------------------- 1 | export default from './named-exports' 2 | 3 | export baz from './named-exports' 4 | -------------------------------------------------------------------------------- /test/fixtures/bundled-dependencies/as-array-bundle-deps/node_modules/@generated/bar/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/eslint-plugin-import-x/4dac1cb2ef94e6357f4ae84185358f69f626cfb7/test/fixtures/bundled-dependencies/as-array-bundle-deps/node_modules/@generated/bar/index.js -------------------------------------------------------------------------------- /test/fixtures/bundled-dependencies/as-array-bundle-deps/node_modules/@generated/foo/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/eslint-plugin-import-x/4dac1cb2ef94e6357f4ae84185358f69f626cfb7/test/fixtures/bundled-dependencies/as-array-bundle-deps/node_modules/@generated/foo/index.js -------------------------------------------------------------------------------- /test/fixtures/bundled-dependencies/as-array-bundle-deps/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "bundleDependencies": [ 3 | "@generated/foo" 4 | ], 5 | "dummy": true 6 | } 7 | -------------------------------------------------------------------------------- /test/fixtures/bundled-dependencies/as-object/node_modules/@generated/bar/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/eslint-plugin-import-x/4dac1cb2ef94e6357f4ae84185358f69f626cfb7/test/fixtures/bundled-dependencies/as-object/node_modules/@generated/bar/index.js -------------------------------------------------------------------------------- /test/fixtures/bundled-dependencies/as-object/node_modules/@generated/foo/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/eslint-plugin-import-x/4dac1cb2ef94e6357f4ae84185358f69f626cfb7/test/fixtures/bundled-dependencies/as-object/node_modules/@generated/foo/index.js -------------------------------------------------------------------------------- /test/fixtures/bundled-dependencies/as-object/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "bundledDependencies": { 3 | "@generated/foo": "latest" 4 | }, 5 | "dummy": true 6 | } 7 | -------------------------------------------------------------------------------- /test/fixtures/bundled-dependencies/race-condition/node_modules/@generated/bar/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/eslint-plugin-import-x/4dac1cb2ef94e6357f4ae84185358f69f626cfb7/test/fixtures/bundled-dependencies/race-condition/node_modules/@generated/bar/index.js -------------------------------------------------------------------------------- /test/fixtures/bundled-dependencies/race-condition/node_modules/@generated/foo/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/eslint-plugin-import-x/4dac1cb2ef94e6357f4ae84185358f69f626cfb7/test/fixtures/bundled-dependencies/race-condition/node_modules/@generated/foo/index.js -------------------------------------------------------------------------------- /test/fixtures/bundled-dependencies/race-condition/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "bundledDependencies": { 3 | "@generated/bar": "latest" 4 | }, 5 | "bundleDependencies": [ 6 | "@generated/foo" 7 | ], 8 | "dummy": true 9 | } 10 | -------------------------------------------------------------------------------- /test/fixtures/color.js: -------------------------------------------------------------------------------- 1 | export const example = 'example' 2 | -------------------------------------------------------------------------------- /test/fixtures/common-module.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | a: 1, 3 | b: 2, 4 | c: function () { 5 | return 3 6 | }, 7 | } 8 | -------------------------------------------------------------------------------- /test/fixtures/common.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | a: 1, 3 | b: 2, 4 | } 5 | 6 | var c = 3 7 | 8 | exports.d = c 9 | -------------------------------------------------------------------------------- /test/fixtures/commonjs-namespace/a.js: -------------------------------------------------------------------------------- 1 | export { default as b } from './b' 2 | -------------------------------------------------------------------------------- /test/fixtures/commonjs-namespace/b.js: -------------------------------------------------------------------------------- 1 | module.exports = {} 2 | -------------------------------------------------------------------------------- /test/fixtures/constants/index.js: -------------------------------------------------------------------------------- 1 | export const FOO = 'FOO' 2 | -------------------------------------------------------------------------------- /test/fixtures/cycles/depth-zero.js: -------------------------------------------------------------------------------- 1 | // export function foo() {} 2 | -------------------------------------------------------------------------------- /test/fixtures/cycles/es6/depth-one-dynamic.js: -------------------------------------------------------------------------------- 1 | export const bar = () => import('../depth-zero').then(({ foo }) => foo) 2 | -------------------------------------------------------------------------------- /test/fixtures/cycles/es6/depth-one-reexport.js: -------------------------------------------------------------------------------- 1 | export { foo } from '../depth-zero' 2 | -------------------------------------------------------------------------------- /test/fixtures/cycles/es6/depth-one.js: -------------------------------------------------------------------------------- 1 | import foo from '../depth-zero' 2 | export { foo } 3 | -------------------------------------------------------------------------------- /test/fixtures/cycles/es6/depth-three-indirect.js: -------------------------------------------------------------------------------- 1 | import './depth-two' 2 | 3 | export function bar() { 4 | return 'side effects???' 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/cycles/es6/depth-three-star.js: -------------------------------------------------------------------------------- 1 | import * as two from './depth-two' 2 | export { two } 3 | -------------------------------------------------------------------------------- /test/fixtures/cycles/es6/depth-two.js: -------------------------------------------------------------------------------- 1 | import { foo } from './depth-one' 2 | export { foo } 3 | -------------------------------------------------------------------------------- /test/fixtures/cycles/external-depth-two.js: -------------------------------------------------------------------------------- 1 | import { foo } from 'cycles/external/depth-one' 2 | export { foo } 3 | -------------------------------------------------------------------------------- /test/fixtures/cycles/external/depth-one.js: -------------------------------------------------------------------------------- 1 | import foo from '../depth-zero' 2 | export { foo } 3 | -------------------------------------------------------------------------------- /test/fixtures/cycles/flow-typeof.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import typeof Foo from './depth-zero' 3 | import { typeof Bar } from './depth-zero' 4 | // import typeof { Bar } from './depth-zero'; 5 | -------------------------------------------------------------------------------- /test/fixtures/cycles/flow-types-depth-one.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import type { FooType } from './flow-types-depth-two' 4 | import { type BarType, bar } from './flow-types-depth-two' 5 | 6 | export { bar } 7 | -------------------------------------------------------------------------------- /test/fixtures/cycles/flow-types-depth-two.js: -------------------------------------------------------------------------------- 1 | import { foo } from './es6/depth-one' 2 | -------------------------------------------------------------------------------- /test/fixtures/cycles/flow-types-only-importing-multiple-types.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import { type FooType, type BarType } from './depth-zero' 4 | -------------------------------------------------------------------------------- /test/fixtures/cycles/flow-types-only-importing-type.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import type { FooType } from './depth-zero' 4 | -------------------------------------------------------------------------------- /test/fixtures/cycles/flow-types-some-type-imports.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import { foo, type BarType } from './depth-zero' 4 | -------------------------------------------------------------------------------- /test/fixtures/cycles/flow-types.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import type { FooType } from './flow-types-depth-two' 4 | import { type BarType } from './flow-types-depth-two' 5 | 6 | export const bar = 1 7 | -------------------------------------------------------------------------------- /test/fixtures/cycles/ignore/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "import-x/no-cycle": 0 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/cycles/ignore/index.js: -------------------------------------------------------------------------------- 1 | import { foo } from '../depth-zero' 2 | export { foo } 3 | -------------------------------------------------------------------------------- /test/fixtures/cycles/intermediate-ignore.js: -------------------------------------------------------------------------------- 1 | import foo from './ignore' 2 | export { foo } 3 | -------------------------------------------------------------------------------- /test/fixtures/data.json: -------------------------------------------------------------------------------- 1 | { 2 | "foo": "bar" 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/deep-deprecated.js: -------------------------------------------------------------------------------- 1 | import * as deepDep from './deprecated' 2 | export { deepDep } 3 | -------------------------------------------------------------------------------- /test/fixtures/deep-es7/a.js: -------------------------------------------------------------------------------- 1 | export * as b from './b' 2 | -------------------------------------------------------------------------------- /test/fixtures/deep-es7/b.js: -------------------------------------------------------------------------------- 1 | export * as c from './c' 2 | export default 'b' 3 | -------------------------------------------------------------------------------- /test/fixtures/deep-es7/c.js: -------------------------------------------------------------------------------- 1 | export * as d from './d' 2 | -------------------------------------------------------------------------------- /test/fixtures/deep-es7/d.js: -------------------------------------------------------------------------------- 1 | export const e = 'e' 2 | -------------------------------------------------------------------------------- /test/fixtures/deep/a.js: -------------------------------------------------------------------------------- 1 | import * as b from './b' 2 | export { b } 3 | -------------------------------------------------------------------------------- /test/fixtures/deep/b.js: -------------------------------------------------------------------------------- 1 | import * as c from './c' 2 | export { c } 3 | export default 'b' 4 | -------------------------------------------------------------------------------- /test/fixtures/deep/c.js: -------------------------------------------------------------------------------- 1 | import * as d from './d' 2 | export { d } 3 | -------------------------------------------------------------------------------- /test/fixtures/deep/cache-1.js: -------------------------------------------------------------------------------- 1 | import * as b from './cache-2' 2 | export { b } 3 | -------------------------------------------------------------------------------- /test/fixtures/deep/cache-2a.js: -------------------------------------------------------------------------------- 1 | import * as c from './c' 2 | export { c } 3 | -------------------------------------------------------------------------------- /test/fixtures/deep/cache-2b.js: -------------------------------------------------------------------------------- 1 | import * as c from './c' 2 | // export { c } 3 | -------------------------------------------------------------------------------- /test/fixtures/deep/d.js: -------------------------------------------------------------------------------- 1 | export const e = 'e' 2 | -------------------------------------------------------------------------------- /test/fixtures/deep/default.js: -------------------------------------------------------------------------------- 1 | import * as b from './b' 2 | export default b 3 | -------------------------------------------------------------------------------- /test/fixtures/default-class.js: -------------------------------------------------------------------------------- 1 | export default class EDClass {} 2 | -------------------------------------------------------------------------------- /test/fixtures/default-export-default-property.js: -------------------------------------------------------------------------------- 1 | export default { 2 | default: 'baz', 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/default-export-from-ignored.js: -------------------------------------------------------------------------------- 1 | export { foo as default } from './common.js' 2 | -------------------------------------------------------------------------------- /test/fixtures/default-export-from-named.js: -------------------------------------------------------------------------------- 1 | export { d as default } from './named-exports.js' 2 | -------------------------------------------------------------------------------- /test/fixtures/default-export-from.js: -------------------------------------------------------------------------------- 1 | export default from './bar' 2 | -------------------------------------------------------------------------------- /test/fixtures/default-export-namespace-string.js: -------------------------------------------------------------------------------- 1 | export * as 'default' from './named-exports' 2 | -------------------------------------------------------------------------------- /test/fixtures/default-export-string.js: -------------------------------------------------------------------------------- 1 | function foo() { 2 | return 'bar' 3 | } 4 | 5 | export { foo as 'default' } 6 | -------------------------------------------------------------------------------- /test/fixtures/default-export.js: -------------------------------------------------------------------------------- 1 | export default function foo() { 2 | return 'bar' 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/deprecated-file.js: -------------------------------------------------------------------------------- 1 | /** 2 | * ugh! 3 | * @module some/deprecated 4 | * @deprecated this module is the worst. 5 | */ 6 | 7 | /** 8 | * this class is great 9 | */ 10 | export default class Thing {} 11 | 12 | // some other comment 13 | -------------------------------------------------------------------------------- /test/fixtures/deprecated.js: -------------------------------------------------------------------------------- 1 | // some line comment 2 | /** 3 | * this function is terrible 4 | * @deprecated please use 'x' instead. 5 | * @return null 6 | */ 7 | // another line comment 8 | // with two lines 9 | export function fn() { 10 | return null 11 | } 12 | 13 | /** 14 | * so terrible 15 | * @deprecated this is awful, use NotAsBadClass. 16 | */ 17 | export default class TerribleClass {} 18 | 19 | /** 20 | * some flux action type maybe 21 | * @deprecated please stop sending/handling this action type. 22 | * @type {String} 23 | */ 24 | export const MY_TERRIBLE_ACTION = 'ugh' 25 | 26 | /** 27 | * @deprecated this chain is awful 28 | * @type {String} 29 | */ 30 | export const CHAIN_A = 'a', 31 | /** 32 | * @deprecated so awful 33 | * @type {String} 34 | */ 35 | CHAIN_B = 'b', 36 | /** 37 | * @deprecated still terrible 38 | * @type {String} 39 | */ 40 | CHAIN_C = 'C' 41 | 42 | /** 43 | * this one is fine 44 | * @return {String} - great! 45 | */ 46 | export function fine() { 47 | return 'great!' 48 | } 49 | 50 | export function _undocumented() { 51 | return 'sneaky!' 52 | } 53 | -------------------------------------------------------------------------------- /test/fixtures/dynamic-import-in-commonjs.js: -------------------------------------------------------------------------------- 1 | async function doSomething() { 2 | await import('./bar.js') 3 | } 4 | 5 | exports.something = 'hello' 6 | -------------------------------------------------------------------------------- /test/fixtures/empty-folder/anchor.txt: -------------------------------------------------------------------------------- 1 | no js here! -------------------------------------------------------------------------------- /test/fixtures/empty-named-blocks.js: -------------------------------------------------------------------------------- 1 | import {} from './bar.js' 2 | -------------------------------------------------------------------------------- /test/fixtures/empty/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "foo", 3 | "version": "1.0.0" 4 | } 5 | -------------------------------------------------------------------------------- /test/fixtures/export-all.js: -------------------------------------------------------------------------------- 1 | import { foo } from './sibling-with-names' // ensure importing exported name doesn't block 2 | export * from './sibling-with-names' 3 | -------------------------------------------------------------------------------- /test/fixtures/export-default-string-and-named.js: -------------------------------------------------------------------------------- 1 | const bar = 'bar' 2 | export function foo() {} 3 | 4 | export { bar as 'default' } 5 | -------------------------------------------------------------------------------- /test/fixtures/export-props.js: -------------------------------------------------------------------------------- 1 | exports.x = 'y' 2 | exports.y = 'z' 3 | -------------------------------------------------------------------------------- /test/fixtures/export-star-2/middle.js: -------------------------------------------------------------------------------- 1 | export * as myName from './upstream' 2 | -------------------------------------------------------------------------------- /test/fixtures/export-star-2/upstream.js: -------------------------------------------------------------------------------- 1 | export const a = 1 2 | -------------------------------------------------------------------------------- /test/fixtures/export-star-3/b.ts: -------------------------------------------------------------------------------- 1 | export * as b from './c' 2 | -------------------------------------------------------------------------------- /test/fixtures/export-star-3/c.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/eslint-plugin-import-x/4dac1cb2ef94e6357f4ae84185358f69f626cfb7/test/fixtures/export-star-3/c.ts -------------------------------------------------------------------------------- /test/fixtures/export-star-4/module/feature.jsx: -------------------------------------------------------------------------------- 1 | export function func() { 2 | console.log('Hello world') 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/export-star-4/module/index.ts: -------------------------------------------------------------------------------- 1 | export * from './feature' 2 | -------------------------------------------------------------------------------- /test/fixtures/export-star/extfield.js: -------------------------------------------------------------------------------- 1 | export default 42 2 | -------------------------------------------------------------------------------- /test/fixtures/export-star/extfield2.js: -------------------------------------------------------------------------------- 1 | export default NaN 2 | -------------------------------------------------------------------------------- /test/fixtures/export-star/models.js: -------------------------------------------------------------------------------- 1 | export * as ExtfieldModel from './extfield' 2 | export * as Extfield2Model from './extfield2' 3 | -------------------------------------------------------------------------------- /test/fixtures/exports-calc-keys.js: -------------------------------------------------------------------------------- 1 | exports['x'] = 'y' 2 | exports['foo' + 'bar'] = 'baz' 3 | -------------------------------------------------------------------------------- /test/fixtures/exports-missing.js: -------------------------------------------------------------------------------- 1 | export { foo as bar } from './does-not-exist' 2 | export * from './does-not-exist' 3 | -------------------------------------------------------------------------------- /test/fixtures/file.with.dot.js: -------------------------------------------------------------------------------- 1 | export default null 2 | -------------------------------------------------------------------------------- /test/fixtures/flowtypes.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | // requires @babel/eslint-parser or flow plugin 3 | // https://flowtype.org/blog/2015/02/18/Import-Types.html 4 | export type MyType = { 5 | id: number, 6 | firstName: string, 7 | lastName: string, 8 | } 9 | 10 | export interface MyInterface {} 11 | 12 | export class MyClass {} 13 | 14 | export opaque type MyOpaqueType: string = string 15 | -------------------------------------------------------------------------------- /test/fixtures/foo-bar-resolver-invalid.js: -------------------------------------------------------------------------------- 1 | exports = {} 2 | -------------------------------------------------------------------------------- /test/fixtures/foo-bar-resolver-no-version.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | 3 | exports.resolveImport = function (modulePath, sourceFile, config) { 4 | var sourceFileName = path.basename(sourceFile) 5 | if (sourceFileName === 'foo.js') { 6 | return path.join(__dirname, 'bar.jsx') 7 | } 8 | if (sourceFileName === 'exception.js') { 9 | throw new Error('foo-bar-resolver-v1 resolveImport test exception') 10 | } 11 | return undefined 12 | } 13 | -------------------------------------------------------------------------------- /test/fixtures/foo-bar-resolver-v1.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | 3 | exports.resolveImport = function (modulePath, sourceFile, config) { 4 | var sourceFileName = path.basename(sourceFile) 5 | if (sourceFileName === 'foo.js') { 6 | return path.join(__dirname, 'bar.jsx') 7 | } 8 | if (sourceFileName === 'exception.js') { 9 | throw new Error('foo-bar-resolver-v1 resolveImport test exception') 10 | } 11 | return undefined 12 | } 13 | 14 | exports.interfaceVersion = 1 15 | -------------------------------------------------------------------------------- /test/fixtures/foo-bar-resolver-v2.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | 3 | exports.resolve = function (modulePath, sourceFile, config) { 4 | var sourceFileName = path.basename(sourceFile) 5 | if (sourceFileName === 'foo.js') { 6 | return { found: true, path: path.join(__dirname, 'bar.jsx') } 7 | } 8 | if (sourceFileName === 'exception.js') { 9 | throw new Error('foo-bar-resolver-v2 resolve test exception') 10 | } 11 | return { found: false } 12 | } 13 | 14 | exports.interfaceVersion = 2 15 | -------------------------------------------------------------------------------- /test/fixtures/foobar.json: -------------------------------------------------------------------------------- 1 | { 2 | "action": "set", 3 | "node": { 4 | "key": "/foo", 5 | "value": "foo", 6 | "modifiedIndex": 1438, 7 | "createdIndex": 1438 8 | }, 9 | "prevNode": { 10 | "key": "/foo", 11 | "value": "bar", 12 | "modifiedIndex": 1437, 13 | "createdIndex": 1437 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /test/fixtures/ignore.invalid.extension: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/eslint-plugin-import-x/4dac1cb2ef94e6357f4ae84185358f69f626cfb7/test/fixtures/ignore.invalid.extension -------------------------------------------------------------------------------- /test/fixtures/importType/index.js: -------------------------------------------------------------------------------- 1 | /* for importType test, just needs to exist */ 2 | -------------------------------------------------------------------------------- /test/fixtures/index.js: -------------------------------------------------------------------------------- 1 | // Used in `no-self-import` tests 2 | -------------------------------------------------------------------------------- /test/fixtures/internal-modules/api/service/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/eslint-plugin-import-x/4dac1cb2ef94e6357f4ae84185358f69f626cfb7/test/fixtures/internal-modules/api/service/index.js -------------------------------------------------------------------------------- /test/fixtures/internal-modules/package.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /test/fixtures/internal-modules/plugins/plugin.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/eslint-plugin-import-x/4dac1cb2ef94e6357f4ae84185358f69f626cfb7/test/fixtures/internal-modules/plugins/plugin.js -------------------------------------------------------------------------------- /test/fixtures/internal-modules/plugins/plugin2/app/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/eslint-plugin-import-x/4dac1cb2ef94e6357f4ae84185358f69f626cfb7/test/fixtures/internal-modules/plugins/plugin2/app/index.js -------------------------------------------------------------------------------- /test/fixtures/internal-modules/plugins/plugin2/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/eslint-plugin-import-x/4dac1cb2ef94e6357f4ae84185358f69f626cfb7/test/fixtures/internal-modules/plugins/plugin2/index.js -------------------------------------------------------------------------------- /test/fixtures/internal-modules/plugins/plugin2/internal.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/eslint-plugin-import-x/4dac1cb2ef94e6357f4ae84185358f69f626cfb7/test/fixtures/internal-modules/plugins/plugin2/internal.js -------------------------------------------------------------------------------- /test/fixtures/internal-modules/test.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/eslint-plugin-import-x/4dac1cb2ef94e6357f4ae84185358f69f626cfb7/test/fixtures/internal-modules/test.js -------------------------------------------------------------------------------- /test/fixtures/internal-modules/typescript/plugin2/app/index.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/eslint-plugin-import-x/4dac1cb2ef94e6357f4ae84185358f69f626cfb7/test/fixtures/internal-modules/typescript/plugin2/app/index.ts -------------------------------------------------------------------------------- /test/fixtures/internal-modules/typescript/plugin2/index.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/eslint-plugin-import-x/4dac1cb2ef94e6357f4ae84185358f69f626cfb7/test/fixtures/internal-modules/typescript/plugin2/index.ts -------------------------------------------------------------------------------- /test/fixtures/internal-modules/typescript/plugin2/internal.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/eslint-plugin-import-x/4dac1cb2ef94e6357f4ae84185358f69f626cfb7/test/fixtures/internal-modules/typescript/plugin2/internal.ts -------------------------------------------------------------------------------- /test/fixtures/internal-modules/typescript/plugins.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/eslint-plugin-import-x/4dac1cb2ef94e6357f4ae84185358f69f626cfb7/test/fixtures/internal-modules/typescript/plugins.ts -------------------------------------------------------------------------------- /test/fixtures/issue-195/Bookings.js: -------------------------------------------------------------------------------- 1 | export default 'Bookings' 2 | -------------------------------------------------------------------------------- /test/fixtures/issue-195/Endpoints.js: -------------------------------------------------------------------------------- 1 | export Bookings from './Bookings' 2 | export Users from './Users' 3 | -------------------------------------------------------------------------------- /test/fixtures/issue-195/Users.js: -------------------------------------------------------------------------------- 1 | export default 'Users' 2 | -------------------------------------------------------------------------------- /test/fixtures/issue-370-commonjs-namespace/bar.js: -------------------------------------------------------------------------------- 1 | // bar.js 2 | export { default as foo } from './foo' 3 | -------------------------------------------------------------------------------- /test/fixtures/issue-370-commonjs-namespace/foo.js: -------------------------------------------------------------------------------- 1 | // foo.js 2 | module.exports = { foo: 'foo' } 3 | -------------------------------------------------------------------------------- /test/fixtures/issue210.config.js: -------------------------------------------------------------------------------- 1 | exports.parserOptions = { 2 | sourceType: 'module', 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/issue210.js: -------------------------------------------------------------------------------- 1 | export { test } from './issue210.js' 2 | -------------------------------------------------------------------------------- /test/fixtures/jsx.js: -------------------------------------------------------------------------------- 1 | export const jsx =
2 | -------------------------------------------------------------------------------- /test/fixtures/jsx/AnotherComponent.jsx: -------------------------------------------------------------------------------- 1 | export * from './named' 2 | -------------------------------------------------------------------------------- /test/fixtures/jsx/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | 3 | // class App extends Component { 4 | // render() { 5 | // return
hello, JSX
6 | // } 7 | // } 8 | 9 | export default connect()(App) 10 | -------------------------------------------------------------------------------- /test/fixtures/jsx/FooES7.js: -------------------------------------------------------------------------------- 1 | // see issue #36 2 | 3 | // Foo.jsx 4 | class Foo { 5 | // ES7 static members 6 | static bar = true 7 | } 8 | 9 | export default Foo 10 | 11 | export class Bar { 12 | static baz = false 13 | 14 | render() { 15 | let { a, ...rest } = { a: 1, b: 2, c: 3 } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /test/fixtures/jsx/MyCoolComponent.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | export default class MyCoolComponent extends React.Component { 4 | render() { 5 | return
too cool for school
6 | } 7 | } 8 | -------------------------------------------------------------------------------- /test/fixtures/jsx/MyUnCoolComponent.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | export default class MyCoolComponent extends React.Component { 4 | render() { 5 | return
too cool for school
6 | } 7 | } 8 | -------------------------------------------------------------------------------- /test/fixtures/jsx/bar/baz.jsx: -------------------------------------------------------------------------------- 1 | export function Baz1() { 2 | return
3 | } 4 | 5 | // Fragment Syntax 6 | export function Baz2() { 7 | return ( 8 |
9 | Baz2 10 |
11 | ) 12 | } 13 | -------------------------------------------------------------------------------- /test/fixtures/jsx/bar/index.js: -------------------------------------------------------------------------------- 1 | export * from './baz.jsx' 2 | export { Qux1, Qux2 } from './qux.jsx' 3 | -------------------------------------------------------------------------------- /test/fixtures/jsx/bar/qux.jsx: -------------------------------------------------------------------------------- 1 | export function Qux1() { 2 | return ( 3 |
4 |

Qux1

5 |
6 | ) 7 | } 8 | 9 | export function Qux2() { 10 | return ( 11 |
12 |

Qux1

13 |
14 | ) 15 | } 16 | -------------------------------------------------------------------------------- /test/fixtures/jsx/named.jsx: -------------------------------------------------------------------------------- 1 | export const jsxFoo = 'foo' 2 | export const jsxBar = 'bar' 3 | -------------------------------------------------------------------------------- /test/fixtures/jsx/re-export.js: -------------------------------------------------------------------------------- 1 | export * from './named.jsx' 2 | -------------------------------------------------------------------------------- /test/fixtures/just-json-files/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "plugins": [ 4 | "import-x", 5 | "json" 6 | ], 7 | "rules": { 8 | "import-x/no-unused-modules": [ 9 | "error", 10 | { 11 | "missingExports": false, 12 | "unusedExports": true 13 | } 14 | ] 15 | }, 16 | "overrides": [ 17 | { 18 | "files": "*.json", 19 | "extends": "plugin:json/recommended" 20 | } 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /test/fixtures/just-json-files/invalid.json: -------------------------------------------------------------------------------- 1 | , 2 | -------------------------------------------------------------------------------- /test/fixtures/load-error-resolver.js: -------------------------------------------------------------------------------- 1 | throw new SyntaxError('TEST SYNTAX ERROR') 2 | -------------------------------------------------------------------------------- /test/fixtures/malformed.js: -------------------------------------------------------------------------------- 1 | return foo from fnuction () { 2 | 3 | export {} 4 | -------------------------------------------------------------------------------- /test/fixtures/missing-entrypoint/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "bin": "./cli.js" 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/mixed-exports.js: -------------------------------------------------------------------------------- 1 | export default function () { 2 | return 'foo' 3 | } 4 | 5 | export function bar() { 6 | return 'bar' 7 | } 8 | -------------------------------------------------------------------------------- /test/fixtures/monorepo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "dependencies": { 4 | "right-pad": "^1.0.1" 5 | }, 6 | "devDependencies": { 7 | "left-pad": "^1.2.0" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/fixtures/monorepo/packages/nested-package/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nested-monorepo-pkg", 3 | "dependencies": { 4 | "react": "^16.0.0" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/fixtures/mutator.js: -------------------------------------------------------------------------------- 1 | export const mutant = 'logan' 2 | -------------------------------------------------------------------------------- /test/fixtures/named-default-export.js: -------------------------------------------------------------------------------- 1 | const foo = 'foo' 2 | 3 | export { foo as default } 4 | -------------------------------------------------------------------------------- /test/fixtures/named-export-collision/a.js: -------------------------------------------------------------------------------- 1 | export const FOO = 'a-foobar' 2 | -------------------------------------------------------------------------------- /test/fixtures/named-export-collision/b.js: -------------------------------------------------------------------------------- 1 | export const FOO = 'b-foobar' 2 | -------------------------------------------------------------------------------- /test/fixtures/named-exports.js: -------------------------------------------------------------------------------- 1 | var a = 1 2 | var b = 2 3 | 4 | export { a, b } 5 | 6 | var c = 3 7 | export { c as d } 8 | 9 | export class ExportedClass {} 10 | 11 | // destructuring exports 12 | 13 | export var { destructuredProp, ...restProps } = {}, 14 | { destructingAssign = null } = {}, 15 | { destructingAssign: destructingRenamedAssign = null } = {}, 16 | [arrayKeyProp, ...arrayRestKeyProps] = [], 17 | [{ deepProp }] = [], 18 | { 19 | arr: [, , deepSparseElement], 20 | } = {} 21 | -------------------------------------------------------------------------------- /test/fixtures/named-trampoline.js: -------------------------------------------------------------------------------- 1 | export bar from './bar' 2 | export foo from './default-export' 3 | -------------------------------------------------------------------------------- /test/fixtures/narcissist.js: -------------------------------------------------------------------------------- 1 | export const me = 'awesome' 2 | export { me as soGreat } from './narcissist' 3 | -------------------------------------------------------------------------------- /test/fixtures/nested-common.js: -------------------------------------------------------------------------------- 1 | ;(function () { 2 | exports.x = 'foo' 3 | })() 4 | -------------------------------------------------------------------------------- /test/fixtures/no-self-import-folder/index.js: -------------------------------------------------------------------------------- 1 | // Used in `no-self-import` tests 2 | -------------------------------------------------------------------------------- /test/fixtures/no-self-import.js: -------------------------------------------------------------------------------- 1 | // Used in `no-self-import` tests 2 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/arbitrary-module-namespace-identifier-name-a.js: -------------------------------------------------------------------------------- 1 | const foo = 333 2 | export { foo as 'foo' } 3 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/arbitrary-module-namespace-identifier-name-b.js: -------------------------------------------------------------------------------- 1 | import { 'foo' as foo } from './arbitrary-module-namespace-identifier-name-a.js' 2 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/arbitrary-module-namespace-identifier-name-c.js: -------------------------------------------------------------------------------- 1 | const foo = 333 2 | export { foo as 'foo' } 3 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/bin.js: -------------------------------------------------------------------------------- 1 | export const bin = 'bin' 2 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/binObject/index.js: -------------------------------------------------------------------------------- 1 | export const binObject = 'binObject' 2 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/binObject/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": false, 3 | "bin": { 4 | "binObject": "./index.js" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/browser.js: -------------------------------------------------------------------------------- 1 | export const browser = 'browser' 2 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/browserObject/index.js: -------------------------------------------------------------------------------- 1 | export const browserObject = 'browserObject' 2 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/browserObject/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "browser": { 3 | "browserObject": "./index.js", 4 | "an-ignored-module": false 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/cjs.js: -------------------------------------------------------------------------------- 1 | // Simple import extracted from 'redux-starter-kit' compiled file 2 | 3 | function isPlain(val) { 4 | return true 5 | } 6 | 7 | exports.isPlain = isPlain 8 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/destructuring-a.js: -------------------------------------------------------------------------------- 1 | import { a, b } from './destructuring-b' 2 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/destructuring-b.js: -------------------------------------------------------------------------------- 1 | const obj = { a: 1, dummy: { b: 2 } } 2 | export const { 3 | a, 4 | dummy: { b }, 5 | } = obj 6 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/dynamic-import-js-2.js: -------------------------------------------------------------------------------- 1 | const importPath = './exports-for-dynamic-js' 2 | class A { 3 | method() { 4 | const c = import(importPath) 5 | } 6 | } 7 | 8 | class B { 9 | method() { 10 | const c = import('i-do-not-exist') 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/dynamic-import-js.js: -------------------------------------------------------------------------------- 1 | class A { 2 | method() { 3 | const c = import('./exports-for-dynamic-js') 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/empty_file.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/eslint-plugin-import-x/4dac1cb2ef94e6357f4ae84185358f69f626cfb7/test/fixtures/no-unused-modules/empty_file.js -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/exports-for-dynamic-js-2.js: -------------------------------------------------------------------------------- 1 | export const a = 10 2 | export const b = 20 3 | export const c = 30 4 | const d = 40 5 | export default d 6 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/exports-for-dynamic-js.js: -------------------------------------------------------------------------------- 1 | export const a = 10 2 | export const b = 20 3 | export const c = 30 4 | const d = 40 5 | export default d 6 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/file-0.js: -------------------------------------------------------------------------------- 1 | import eslint from 'eslint' 2 | import fileA from './file-a' 3 | import { b } from './file-b' 4 | import { c1, c2 } from './file-c' 5 | import { d } from './file-d' 6 | import { e } from './file-e' 7 | import { e2 } from './file-e' 8 | import { h2 } from './file-h' 9 | import * as l from './file-l' 10 | import { q } from './file-q' 11 | export * from './file-n' 12 | export { default, o0, o3 } from './file-o' 13 | export { p } from './file-p' 14 | import s from './file-s' 15 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/file-a.js: -------------------------------------------------------------------------------- 1 | import { o2 } from './file-o' 2 | export default () => 1 3 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/file-b.js: -------------------------------------------------------------------------------- 1 | export const b = 2 2 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/file-c.js: -------------------------------------------------------------------------------- 1 | const c1 = 3 2 | 3 | function c2() { 4 | return 3 5 | } 6 | 7 | export { c1, c2 } 8 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/file-d.js: -------------------------------------------------------------------------------- 1 | export function d() { 2 | return 4 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/file-destructured-1.js: -------------------------------------------------------------------------------- 1 | export const { destructured } = {} 2 | export const { destructured2 } = {} 3 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/file-destructured-2.js: -------------------------------------------------------------------------------- 1 | import { destructured } from './file-destructured-1' 2 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/file-e.js: -------------------------------------------------------------------------------- 1 | const e0 = 5 2 | 3 | export { e0 as e } 4 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/file-f.js: -------------------------------------------------------------------------------- 1 | export default () => 1 2 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/file-g.js: -------------------------------------------------------------------------------- 1 | export const g = 2 2 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/file-h.js: -------------------------------------------------------------------------------- 1 | const h1 = 3 2 | 3 | function h2() { 4 | return 3 5 | } 6 | 7 | const h3 = true 8 | 9 | export { h1, h2, h3 } 10 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/file-i.js: -------------------------------------------------------------------------------- 1 | const i1 = 3 2 | 3 | function i2() { 4 | return 3 5 | } 6 | 7 | export { i1, i2 } 8 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/file-ignored-a.js: -------------------------------------------------------------------------------- 1 | export default () => 1 2 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/file-ignored-b.js: -------------------------------------------------------------------------------- 1 | export const b = 2 2 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/file-ignored-c.js: -------------------------------------------------------------------------------- 1 | const c1 = 3 2 | 3 | function c2() { 4 | return 3 5 | } 6 | 7 | export { c1, c2 } 8 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/file-ignored-d.js: -------------------------------------------------------------------------------- 1 | export function d() { 2 | return 4 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/file-ignored-e.js: -------------------------------------------------------------------------------- 1 | const e0 = 5 2 | 3 | export { e0 as e } 4 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/file-ignored-l.js: -------------------------------------------------------------------------------- 1 | const l0 = 5 2 | const l = 10 3 | 4 | export { l0 as l1, l } 5 | 6 | export default () => {} 7 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/file-j.js: -------------------------------------------------------------------------------- 1 | export function j() { 2 | return 4 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/file-k.js: -------------------------------------------------------------------------------- 1 | const k0 = 5 2 | 3 | export { k0 as k } 4 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/file-l.js: -------------------------------------------------------------------------------- 1 | const l0 = 5 2 | const l = 10 3 | 4 | export { l0 as l1, l } 5 | 6 | export default () => {} 7 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/file-m.js: -------------------------------------------------------------------------------- 1 | const m0 = 5 2 | const m = 10 3 | 4 | export { m0 as m1, m } 5 | 6 | export default () => {} 7 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/file-n.js: -------------------------------------------------------------------------------- 1 | const n0 = 'n0' 2 | const n1 = 42 3 | 4 | export { n0, n1 } 5 | 6 | export default () => {} 7 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/file-o.js: -------------------------------------------------------------------------------- 1 | const o0 = 0 2 | const o1 = 1 3 | 4 | export { o0, o1 as o2 } 5 | 6 | export default () => {} 7 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/file-p.js: -------------------------------------------------------------------------------- 1 | import { h3 as h0 } from './file-h' 2 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/file-q.js: -------------------------------------------------------------------------------- 1 | export class q { 2 | q0() {} 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/file-s.js: -------------------------------------------------------------------------------- 1 | export { default } from './file-o' 2 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/filte-r.js: -------------------------------------------------------------------------------- 1 | export * from './cjs' 2 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/flow/flow-0.js: -------------------------------------------------------------------------------- 1 | import { type FooType, type FooInterface } from './flow-2' 2 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/flow/flow-1.js: -------------------------------------------------------------------------------- 1 | // @flow strict 2 | export type Bar = number 3 | export interface BarInterface {} 4 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/flow/flow-2.js: -------------------------------------------------------------------------------- 1 | // @flow strict 2 | export type FooType = string 3 | export interface FooInterface {} 4 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/flow/flow-3.js: -------------------------------------------------------------------------------- 1 | import type { FooType, FooInterface } from './flow-4' 2 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/flow/flow-4.js: -------------------------------------------------------------------------------- 1 | // @flow strict 2 | export type FooType = string 3 | export interface FooInterface {} 4 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/import-export-1.js: -------------------------------------------------------------------------------- 1 | export const a = 5 2 | export const b = 'b' 3 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/import-export-2.js: -------------------------------------------------------------------------------- 1 | import { a } from './import-export-1' 2 | export { b } from './import-export-1' 3 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/jsx/file-jsx-a.jsx: -------------------------------------------------------------------------------- 1 | import { b } from './file-jsx-b' 2 | 3 | export const a = b + 1 4 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/jsx/file-jsx-b.jsx: -------------------------------------------------------------------------------- 1 | export const b = 2 2 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/main/index.js: -------------------------------------------------------------------------------- 1 | export const main = 'main' 2 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/node_modules.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/eslint-plugin-import-x/4dac1cb2ef94e6357f4ae84185358f69f626cfb7/test/fixtures/no-unused-modules/node_modules.js -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "bin": "./bin.js", 3 | "main": "./main/index.js", 4 | "browser": "./browser.js" 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/prefix-child.js: -------------------------------------------------------------------------------- 1 | export const foo = 1 2 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/prefix-parent-bom.js: -------------------------------------------------------------------------------- 1 | import { foo } from './prefix-child.js' 2 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/prefix-parent-bomhashbang.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | import { foo } from './prefix-child.js' 3 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/prefix-parent-hashbang.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | import { foo } from './prefix-child.js' 3 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/prefix-parent.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | import { foo } from './prefix-child.js' 3 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/privatePkg/index.js: -------------------------------------------------------------------------------- 1 | export const privatePkg = 'privatePkg' 2 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/privatePkg/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "main": "./index.js" 4 | } 5 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/renameDefault-2/ComponentA.js: -------------------------------------------------------------------------------- 1 | export default function ComponentA() {} 2 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/renameDefault-2/ComponentB.js: -------------------------------------------------------------------------------- 1 | export default function ComponentB() {} 2 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/renameDefault-2/components.js: -------------------------------------------------------------------------------- 1 | export { default as ComponentA } from './ComponentA' 2 | export { default as ComponentB } from './ComponentB' 3 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/renameDefault-2/usage.js: -------------------------------------------------------------------------------- 1 | import { ComponentA, ComponentB } from './components' 2 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/renameDefault/Component.js: -------------------------------------------------------------------------------- 1 | export default function Component() {} 2 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/renameDefault/components.js: -------------------------------------------------------------------------------- 1 | export { default as Component } from './Component' 2 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/renameDefault/usage.js: -------------------------------------------------------------------------------- 1 | import { Component } from './components' 2 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/typescript/dynamic-import-ts.ts: -------------------------------------------------------------------------------- 1 | class A { 2 | method() { 3 | const c = import('./exports-for-dynamic-ts') 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/typescript/exports-for-dynamic-ts.ts: -------------------------------------------------------------------------------- 1 | export const ts_a = 10 2 | export const ts_b = 20 3 | export const ts_c = 30 4 | const ts_d = 40 5 | export default ts_d 6 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/typescript/file-ts-a-import-type.ts: -------------------------------------------------------------------------------- 1 | import type { b } from './file-ts-b-used-as-type' 2 | import type { c } from './file-ts-c-used-as-type' 3 | import type { d } from './file-ts-d-used-as-type' 4 | import type { e } from './file-ts-e-used-as-type' 5 | 6 | const a: typeof b = 2 7 | const a2: c = {} 8 | const a3: d = {} 9 | const a4: typeof e = undefined 10 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/typescript/file-ts-a.ts: -------------------------------------------------------------------------------- 1 | import { b } from './file-ts-b' 2 | import { c } from './file-ts-c' 3 | import { d } from './file-ts-d' 4 | import { e } from './file-ts-e' 5 | 6 | const a = b + 1 + e.f 7 | const a2: c = {} 8 | const a3: d = {} 9 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/typescript/file-ts-b-unused.ts: -------------------------------------------------------------------------------- 1 | export const b = 2 2 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/typescript/file-ts-b-used-as-type.ts: -------------------------------------------------------------------------------- 1 | export const b = 2 2 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/typescript/file-ts-b.ts: -------------------------------------------------------------------------------- 1 | export const b = 2 2 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/typescript/file-ts-c-unused.ts: -------------------------------------------------------------------------------- 1 | export interface c {} 2 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/typescript/file-ts-c-used-as-type.ts: -------------------------------------------------------------------------------- 1 | export interface c {} 2 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/typescript/file-ts-c.ts: -------------------------------------------------------------------------------- 1 | export interface c {} 2 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/typescript/file-ts-d-unused.ts: -------------------------------------------------------------------------------- 1 | export type d = {} 2 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/typescript/file-ts-d-used-as-type.ts: -------------------------------------------------------------------------------- 1 | export type d = {} 2 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/typescript/file-ts-d.ts: -------------------------------------------------------------------------------- 1 | export type d = {} 2 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/typescript/file-ts-e-unused.ts: -------------------------------------------------------------------------------- 1 | export enum e { 2 | f, 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/typescript/file-ts-e-used-as-type.ts: -------------------------------------------------------------------------------- 1 | export enum e { 2 | f, 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/typescript/file-ts-e.ts: -------------------------------------------------------------------------------- 1 | export enum e { 2 | f, 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/typescript/file-ts-f-import-type.ts: -------------------------------------------------------------------------------- 1 | import type { g } from './file-ts-g-used-as-type' 2 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/typescript/file-ts-f.ts: -------------------------------------------------------------------------------- 1 | import { g } from './file-ts-g' 2 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/typescript/file-ts-g-used-as-type.ts: -------------------------------------------------------------------------------- 1 | export interface g {} 2 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-modules/typescript/file-ts-g.ts: -------------------------------------------------------------------------------- 1 | export interface g {} 2 | -------------------------------------------------------------------------------- /test/fixtures/node_modules/@generated/bar/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/eslint-plugin-import-x/4dac1cb2ef94e6357f4ae84185358f69f626cfb7/test/fixtures/node_modules/@generated/bar/index.js -------------------------------------------------------------------------------- /test/fixtures/node_modules/@generated/bar/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@generated/bar" 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/node_modules/@generated/foo/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/eslint-plugin-import-x/4dac1cb2ef94e6357f4ae84185358f69f626cfb7/test/fixtures/node_modules/@generated/foo/index.js -------------------------------------------------------------------------------- /test/fixtures/node_modules/@generated/foo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@generated/foo" 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/node_modules/@org/not-a-dependency/foo.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/eslint-plugin-import-x/4dac1cb2ef94e6357f4ae84185358f69f626cfb7/test/fixtures/node_modules/@org/not-a-dependency/foo.js -------------------------------------------------------------------------------- /test/fixtures/node_modules/@org/not-a-dependency/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/eslint-plugin-import-x/4dac1cb2ef94e6357f4ae84185358f69f626cfb7/test/fixtures/node_modules/@org/not-a-dependency/index.js -------------------------------------------------------------------------------- /test/fixtures/node_modules/@org/not-a-dependency/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@org/not-a-dependency" 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/node_modules/@org/package/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/eslint-plugin-import-x/4dac1cb2ef94e6357f4ae84185358f69f626cfb7/test/fixtures/node_modules/@org/package/index.js -------------------------------------------------------------------------------- /test/fixtures/node_modules/@org/package/internal.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/eslint-plugin-import-x/4dac1cb2ef94e6357f4ae84185358f69f626cfb7/test/fixtures/node_modules/@org/package/internal.js -------------------------------------------------------------------------------- /test/fixtures/node_modules/@org/package/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@org/package" 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/node_modules/a/index.js: -------------------------------------------------------------------------------- 1 | exports.foo = 'bar' 2 | -------------------------------------------------------------------------------- /test/fixtures/node_modules/a/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "a" 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/node_modules/es6-module/index.js: -------------------------------------------------------------------------------- 1 | export const foo = 'bar' -------------------------------------------------------------------------------- /test/fixtures/node_modules/es6-module/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "es6-module" 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/node_modules/eslint-import-resolver-foo/index.js: -------------------------------------------------------------------------------- 1 | ../../foo-bar-resolver-v2.js -------------------------------------------------------------------------------- /test/fixtures/node_modules/eslint-import-resolver-foo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "eslint-import-resolver-foo" 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/node_modules/esm-package-not-in-pkg-json/esm-module/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/eslint-plugin-import-x/4dac1cb2ef94e6357f4ae84185358f69f626cfb7/test/fixtures/node_modules/esm-package-not-in-pkg-json/esm-module/index.js -------------------------------------------------------------------------------- /test/fixtures/node_modules/esm-package-not-in-pkg-json/esm-module/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "sideEffects": false, 3 | "module": "./index.js" 4 | } 5 | -------------------------------------------------------------------------------- /test/fixtures/node_modules/esm-package-not-in-pkg-json/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/eslint-plugin-import-x/4dac1cb2ef94e6357f4ae84185358f69f626cfb7/test/fixtures/node_modules/esm-package-not-in-pkg-json/index.js -------------------------------------------------------------------------------- /test/fixtures/node_modules/esm-package-not-in-pkg-json/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "esm-package-not-in-pkg-json", 3 | "main": "index.js", 4 | "version": "1.0.0" 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/node_modules/esm-package/esm-module/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/eslint-plugin-import-x/4dac1cb2ef94e6357f4ae84185358f69f626cfb7/test/fixtures/node_modules/esm-package/esm-module/index.js -------------------------------------------------------------------------------- /test/fixtures/node_modules/esm-package/esm-module/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "sideEffects": false, 3 | "module": "./index.js" 4 | } 5 | -------------------------------------------------------------------------------- /test/fixtures/node_modules/esm-package/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/eslint-plugin-import-x/4dac1cb2ef94e6357f4ae84185358f69f626cfb7/test/fixtures/node_modules/esm-package/index.js -------------------------------------------------------------------------------- /test/fixtures/node_modules/esm-package/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "esm-package", 3 | "main": "index.js", 4 | "version": "1.0.0" 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/node_modules/exceljs/excel.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/eslint-plugin-import-x/4dac1cb2ef94e6357f4ae84185358f69f626cfb7/test/fixtures/node_modules/exceljs/excel.js -------------------------------------------------------------------------------- /test/fixtures/node_modules/exceljs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "exceljs", 3 | "main": "./excel.js" 4 | } 5 | -------------------------------------------------------------------------------- /test/fixtures/node_modules/jest/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/eslint-plugin-import-x/4dac1cb2ef94e6357f4ae84185358f69f626cfb7/test/fixtures/node_modules/jest/index.js -------------------------------------------------------------------------------- /test/fixtures/node_modules/jest/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jest" 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/node_modules/jquery/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery" 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/node_modules/jsx-module/foo.jsx: -------------------------------------------------------------------------------- 1 | export const foo = "bar"; 2 | -------------------------------------------------------------------------------- /test/fixtures/node_modules/jsx-module/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jsx-module" 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/node_modules/left-pad/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/eslint-plugin-import-x/4dac1cb2ef94e6357f4ae84185358f69f626cfb7/test/fixtures/node_modules/left-pad/index.js -------------------------------------------------------------------------------- /test/fixtures/node_modules/left-pad/not-a-dependency: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/eslint-plugin-import-x/4dac1cb2ef94e6357f4ae84185358f69f626cfb7/test/fixtures/node_modules/left-pad/not-a-dependency -------------------------------------------------------------------------------- /test/fixtures/node_modules/left-pad/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "left-pad" 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/node_modules/not-a-dependency/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/eslint-plugin-import-x/4dac1cb2ef94e6357f4ae84185358f69f626cfb7/test/fixtures/node_modules/not-a-dependency/index.js -------------------------------------------------------------------------------- /test/fixtures/node_modules/not-a-dependency/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "not-a-dependency" 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/node_modules/react/index.js: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /test/fixtures/node_modules/react/not-a-dependency: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/eslint-plugin-import-x/4dac1cb2ef94e6357f4ae84185358f69f626cfb7/test/fixtures/node_modules/react/not-a-dependency -------------------------------------------------------------------------------- /test/fixtures/node_modules/react/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react" 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/node_modules/rxjs/index.js: -------------------------------------------------------------------------------- 1 | export default function () {} 2 | -------------------------------------------------------------------------------- /test/fixtures/node_modules/rxjs/operators/index.js: -------------------------------------------------------------------------------- 1 | export default function () {} 2 | -------------------------------------------------------------------------------- /test/fixtures/node_modules/rxjs/operators/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rxjs/operators", 3 | "version": "1.0.0", 4 | "main": "index.js" 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/node_modules/rxjs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rxjs", 3 | "version": "1.0.0", 4 | "main": "index.js" 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/order-redirect-scoped/module/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "order-redirect-module", 3 | "private": true, 4 | "main": "../other-module/file.js" 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/order-redirect-scoped/other-module/file.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/eslint-plugin-import-x/4dac1cb2ef94e6357f4ae84185358f69f626cfb7/test/fixtures/order-redirect-scoped/other-module/file.js -------------------------------------------------------------------------------- /test/fixtures/order-redirect-scoped/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@eslint/import-test-order-redirect-scoped", 3 | "version": "1.0.0", 4 | "private": true 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/order-redirect/module/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "order-redirect-module", 3 | "private": true, 4 | "main": "../other-module/file.js" 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/order-redirect/other-module/file.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/eslint-plugin-import-x/4dac1cb2ef94e6357f4ae84185358f69f626cfb7/test/fixtures/order-redirect/other-module/file.js -------------------------------------------------------------------------------- /test/fixtures/order-redirect/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "eslint-import-test-order-redirect", 3 | "version": "1.0.0", 4 | "private": true 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/package-named/index.js: -------------------------------------------------------------------------------- 1 | export default function () {} 2 | -------------------------------------------------------------------------------- /test/fixtures/package-named/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "package-named", 3 | "description": "Standard, named package", 4 | "main": "index.js" 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/package-scoped/index.js: -------------------------------------------------------------------------------- 1 | export default function () {} 2 | -------------------------------------------------------------------------------- /test/fixtures/package-scoped/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@scope/package-named", 3 | "description": "Scoped, named package", 4 | "main": "index.js" 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "bundledDependencies": [ 3 | "@generated/foo" 4 | ], 5 | "peerDependencies": { 6 | "eslint": "2.x" 7 | }, 8 | "dependencies": { 9 | "@org/package": "^1.0.0", 10 | "esm-package": "^1.0.0", 11 | "find-up": "^1.0.0", 12 | "jquery": "^3.1.0", 13 | "lodash.cond": "^4.3.0", 14 | "rxjs": "^1.0.0" 15 | }, 16 | "optionalDependencies": { 17 | "lodash": "^4.0.0" 18 | }, 19 | "devDependencies": { 20 | "eslint": "2.x", 21 | "glob": "1.0.0" 22 | }, 23 | "dummy": true 24 | } 25 | -------------------------------------------------------------------------------- /test/fixtures/package/index.js: -------------------------------------------------------------------------------- 1 | export default function () {} 2 | -------------------------------------------------------------------------------- /test/fixtures/package/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": "Unnamed package for reaching through main field - rxjs style", 3 | "main": "index.js" 4 | } 5 | -------------------------------------------------------------------------------- /test/fixtures/qc.js: -------------------------------------------------------------------------------- 1 | export const ActionTypes = { 2 | A: null, 3 | B: null, 4 | C: null, 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/re-export-common-star.js: -------------------------------------------------------------------------------- 1 | export * from './common' 2 | -------------------------------------------------------------------------------- /test/fixtures/re-export-common.js: -------------------------------------------------------------------------------- 1 | export { a as foo } from './common' 2 | -------------------------------------------------------------------------------- /test/fixtures/re-export-default.js: -------------------------------------------------------------------------------- 1 | export const baz = 'baz? really?' 2 | 3 | export { default as bar } from './default-export' 4 | export { default as foo } from './named-default-export' 5 | 6 | // should allow conversion from CJS to ES6 as follows: 7 | export { default as common } from './common' 8 | -------------------------------------------------------------------------------- /test/fixtures/re-export-names.js: -------------------------------------------------------------------------------- 1 | export { a as foo, b as bar } from './named-exports' 2 | 3 | export const baz = 'will it blend?' 4 | -------------------------------------------------------------------------------- /test/fixtures/re-export-node_modules.js: -------------------------------------------------------------------------------- 1 | export * from 'eslint' 2 | -------------------------------------------------------------------------------- /test/fixtures/re-export.js: -------------------------------------------------------------------------------- 1 | export const c = 'foo' 2 | 3 | export * from './named-exports' 4 | 5 | // #328: this exports only 'foo', not the default. 6 | export * from './bar' 7 | -------------------------------------------------------------------------------- /test/fixtures/redux.js: -------------------------------------------------------------------------------- 1 | // redux idiom 2 | export default connect()(App) 3 | -------------------------------------------------------------------------------- /test/fixtures/restricted-paths/client/a.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/eslint-plugin-import-x/4dac1cb2ef94e6357f4ae84185358f69f626cfb7/test/fixtures/restricted-paths/client/a.js -------------------------------------------------------------------------------- /test/fixtures/restricted-paths/client/one/a.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/eslint-plugin-import-x/4dac1cb2ef94e6357f4ae84185358f69f626cfb7/test/fixtures/restricted-paths/client/one/a.js -------------------------------------------------------------------------------- /test/fixtures/restricted-paths/server/b.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/eslint-plugin-import-x/4dac1cb2ef94e6357f4ae84185358f69f626cfb7/test/fixtures/restricted-paths/server/b.js -------------------------------------------------------------------------------- /test/fixtures/restricted-paths/server/c.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/eslint-plugin-import-x/4dac1cb2ef94e6357f4ae84185358f69f626cfb7/test/fixtures/restricted-paths/server/c.js -------------------------------------------------------------------------------- /test/fixtures/restricted-paths/server/c.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/eslint-plugin-import-x/4dac1cb2ef94e6357f4ae84185358f69f626cfb7/test/fixtures/restricted-paths/server/c.ts -------------------------------------------------------------------------------- /test/fixtures/restricted-paths/server/one/a.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/eslint-plugin-import-x/4dac1cb2ef94e6357f4ae84185358f69f626cfb7/test/fixtures/restricted-paths/server/one/a.js -------------------------------------------------------------------------------- /test/fixtures/restricted-paths/server/one/b.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/eslint-plugin-import-x/4dac1cb2ef94e6357f4ae84185358f69f626cfb7/test/fixtures/restricted-paths/server/one/b.js -------------------------------------------------------------------------------- /test/fixtures/restricted-paths/server/three/a.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/eslint-plugin-import-x/4dac1cb2ef94e6357f4ae84185358f69f626cfb7/test/fixtures/restricted-paths/server/three/a.js -------------------------------------------------------------------------------- /test/fixtures/restricted-paths/server/two-new/a.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/eslint-plugin-import-x/4dac1cb2ef94e6357f4ae84185358f69f626cfb7/test/fixtures/restricted-paths/server/two-new/a.js -------------------------------------------------------------------------------- /test/fixtures/restricted-paths/server/two/a.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/eslint-plugin-import-x/4dac1cb2ef94e6357f4ae84185358f69f626cfb7/test/fixtures/restricted-paths/server/two/a.js -------------------------------------------------------------------------------- /test/fixtures/sibling-with-names.js: -------------------------------------------------------------------------------- 1 | export const foo = 'foo' 2 | -------------------------------------------------------------------------------- /test/fixtures/src-root/src-bar.js: -------------------------------------------------------------------------------- 1 | export const bar = 'BAR' 2 | -------------------------------------------------------------------------------- /test/fixtures/symlinked-module/index.js: -------------------------------------------------------------------------------- 1 | export default {} 2 | -------------------------------------------------------------------------------- /test/fixtures/symlinked-module/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@test-scope/some-module", 3 | "version": "1.0.0", 4 | "private": true 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/test-module/index.js: -------------------------------------------------------------------------------- 1 | export function someThing() {} 2 | -------------------------------------------------------------------------------- /test/fixtures/test.coffee: -------------------------------------------------------------------------------- 1 | exports.a = (foo) -> "bar" 2 | -------------------------------------------------------------------------------- /test/fixtures/test.giffy: -------------------------------------------------------------------------------- 1 | boo! -------------------------------------------------------------------------------- /test/fixtures/tomdoc-deprecated.js: -------------------------------------------------------------------------------- 1 | // Deprecated: This function is terrible. 2 | // 3 | // With another line comment in description. 4 | export function fn() { 5 | return null 6 | } 7 | 8 | // Deprecated: this is awful, 9 | // use NotAsBadClass. 10 | // 11 | // Some other description text. 12 | export default class TerribleClass {} 13 | 14 | // Deprecated: Please stop sending/handling this action type. 15 | export const MY_TERRIBLE_ACTION = 'ugh' 16 | 17 | // Public: This one is fine. 18 | // 19 | // Returns a String "great!" 20 | export function fine() { 21 | return 'great!' 22 | } 23 | 24 | export function _undocumented() { 25 | return 'sneaky!' 26 | } 27 | -------------------------------------------------------------------------------- /test/fixtures/trampoline.js: -------------------------------------------------------------------------------- 1 | export default from './default-export' 2 | -------------------------------------------------------------------------------- /test/fixtures/ts-deprecated.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * this is what you get when you trust a mouse talk show 3 | * @deprecated don't use this! 4 | * @returns {string} nonsense 5 | */ 6 | export function foo() { 7 | return 'bar' 8 | } 9 | -------------------------------------------------------------------------------- /test/fixtures/typescript-d-ts/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "overrides": [ 3 | { 4 | "files": "**.ts", 5 | "parser": "@typescript-eslint/parser", 6 | "extends": "../../../lib/config/typescript", 7 | "rules": { 8 | "import-x/export": "error" 9 | } 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /test/fixtures/typescript-d-ts/file1.ts: -------------------------------------------------------------------------------- 1 | declare namespace ts { 2 | const x: string 3 | export { x } 4 | } 5 | 6 | export = ts 7 | -------------------------------------------------------------------------------- /test/fixtures/typescript-d-ts/file2.ts: -------------------------------------------------------------------------------- 1 | export * from './file1.ts' 2 | -------------------------------------------------------------------------------- /test/fixtures/typescript-declare-interface.d.ts: -------------------------------------------------------------------------------- 1 | declare interface foo { 2 | a: string 3 | } 4 | 5 | declare namespace SomeNamespace { 6 | type foobar = foo & { 7 | b: string 8 | } 9 | } 10 | 11 | export = SomeNamespace 12 | -------------------------------------------------------------------------------- /test/fixtures/typescript-declare-module.ts: -------------------------------------------------------------------------------- 1 | declare module 'typescript-declare-module-foo' { 2 | export const foo: string 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/typescript-declare-nested.d.ts: -------------------------------------------------------------------------------- 1 | declare namespace foo { 2 | interface SomeInterface { 3 | a: string 4 | } 5 | } 6 | 7 | declare namespace foo.bar { 8 | interface SomeOtherInterface { 9 | b: string 10 | } 11 | 12 | function MyFunction() 13 | } 14 | 15 | export = foo 16 | -------------------------------------------------------------------------------- /test/fixtures/typescript-declare.d.ts: -------------------------------------------------------------------------------- 1 | export declare type MyType = string 2 | export declare enum MyEnum { 3 | Foo, 4 | Bar, 5 | Baz, 6 | } 7 | export declare interface Foo { 8 | native: string | number 9 | typedef: MyType 10 | enum: MyEnum 11 | } 12 | 13 | export declare abstract class Bar { 14 | abstract foo(): Foo 15 | 16 | method() 17 | } 18 | 19 | export declare function getFoo(): MyType 20 | 21 | export declare module MyModule { 22 | export function ModuleFunction() 23 | } 24 | 25 | export declare namespace MyNamespace { 26 | export function NamespaceFunction() 27 | 28 | export module NSModule { 29 | export function NSModuleFunction() 30 | } 31 | } 32 | 33 | interface NotExported {} 34 | -------------------------------------------------------------------------------- /test/fixtures/typescript-default.ts: -------------------------------------------------------------------------------- 1 | export default function foobar() {} 2 | -------------------------------------------------------------------------------- /test/fixtures/typescript-export-as-default-namespace/index.d.ts: -------------------------------------------------------------------------------- 1 | export as namespace Foo 2 | 3 | export function bar(): void 4 | -------------------------------------------------------------------------------- /test/fixtures/typescript-export-as-default-namespace/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "esModuleInterop": true 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/typescript-export-assign-default-namespace/index.d.ts: -------------------------------------------------------------------------------- 1 | export = FooBar 2 | 3 | declare namespace FooBar {} 4 | -------------------------------------------------------------------------------- /test/fixtures/typescript-export-assign-default-namespace/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "esModuleInterop": true 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/typescript-export-assign-default-reexport.ts: -------------------------------------------------------------------------------- 1 | import { getFoo } from './typescript' 2 | export = getFoo 3 | -------------------------------------------------------------------------------- /test/fixtures/typescript-export-assign-default.d.ts: -------------------------------------------------------------------------------- 1 | export = foobar 2 | 3 | declare const foobar: number 4 | -------------------------------------------------------------------------------- /test/fixtures/typescript-export-assign-function.ts: -------------------------------------------------------------------------------- 1 | export = function foo() {} 2 | -------------------------------------------------------------------------------- /test/fixtures/typescript-export-assign-mixed.d.ts: -------------------------------------------------------------------------------- 1 | export = foobar 2 | 3 | declare function foobar(): void 4 | declare namespace foobar { 5 | type MyType = string 6 | enum MyEnum { 7 | Foo, 8 | Bar, 9 | Baz, 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /test/fixtures/typescript-export-assign-namespace-merged.d.ts: -------------------------------------------------------------------------------- 1 | export = AssignedNamespace 2 | 3 | declare namespace AssignedNamespace { 4 | type MyType = string 5 | enum MyEnum { 6 | Foo, 7 | Bar, 8 | Baz, 9 | } 10 | } 11 | 12 | declare namespace AssignedNamespace { 13 | interface Foo { 14 | native: string | number 15 | typedef: MyType 16 | enum: MyEnum 17 | } 18 | 19 | abstract class Bar { 20 | abstract foo(): Foo 21 | 22 | method() 23 | } 24 | 25 | export function getFoo(): MyType 26 | 27 | export module MyModule { 28 | export function ModuleFunction() 29 | } 30 | 31 | export namespace MyNamespace { 32 | export function NamespaceFunction() 33 | 34 | export module NSModule { 35 | export function NSModuleFunction() 36 | } 37 | } 38 | 39 | // Export-assignment exports all members in the namespace, explicitly exported or not. 40 | // interface NotExported {} 41 | } 42 | -------------------------------------------------------------------------------- /test/fixtures/typescript-export-assign-namespace.d.ts: -------------------------------------------------------------------------------- 1 | export = AssignedNamespace 2 | 3 | declare namespace AssignedNamespace { 4 | type MyType = string 5 | enum MyEnum { 6 | Foo, 7 | Bar, 8 | Baz, 9 | } 10 | 11 | interface Foo { 12 | native: string | number 13 | typedef: MyType 14 | enum: MyEnum 15 | } 16 | 17 | abstract class Bar { 18 | abstract foo(): Foo 19 | 20 | method() 21 | } 22 | 23 | export function getFoo(): MyType 24 | 25 | export module MyModule { 26 | export function ModuleFunction() 27 | } 28 | 29 | export namespace MyNamespace { 30 | export function NamespaceFunction() 31 | 32 | export module NSModule { 33 | export function NSModuleFunction() 34 | } 35 | } 36 | 37 | // Export-assignment exports all members in the namespace, explicitly exported or not. 38 | // interface NotExported {} 39 | } 40 | -------------------------------------------------------------------------------- /test/fixtures/typescript-export-assign-object/index.ts: -------------------------------------------------------------------------------- 1 | const someObj = { 2 | FooBar: 12, 3 | } 4 | 5 | export = someObj 6 | -------------------------------------------------------------------------------- /test/fixtures/typescript-export-assign-object/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "esModuleInterop": true 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/typescript-export-assign-property.ts: -------------------------------------------------------------------------------- 1 | const AnalyticsNode = { Analytics: {} } 2 | 3 | export = AnalyticsNode.Analytics 4 | -------------------------------------------------------------------------------- /test/fixtures/typescript-export-react-test-renderer/index.d.ts: -------------------------------------------------------------------------------- 1 | // case from @types/react-test-renderer 2 | 3 | export {} 4 | 5 | export interface ReactTestRendererJSON { 6 | type: string 7 | props: { [propName: string]: any } 8 | children: null | ReactTestRendererNode[] 9 | } 10 | export type ReactTestRendererNode = ReactTestRendererJSON | string 11 | export interface ReactTestRendererTree extends ReactTestRendererJSON { 12 | nodeType: 'component' | 'host' 13 | instance: any 14 | rendered: null | ReactTestRendererTree | ReactTestRendererTree[] 15 | } 16 | 17 | export function create(nextElement: any, options?: any): any 18 | 19 | export function act(callback: () => Promise): Promise 20 | -------------------------------------------------------------------------------- /test/fixtures/typescript-export-react-test-renderer/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "esModuleInterop": true 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/typescript-extended-config/index.d.ts: -------------------------------------------------------------------------------- 1 | export = FooBar 2 | 3 | declare namespace FooBar {} 4 | -------------------------------------------------------------------------------- /test/fixtures/typescript-extended-config/tsconfig.base.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "esModuleInterop": true 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/typescript-extended-config/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.base.json", 3 | "compilerOptions": {} 4 | } 5 | -------------------------------------------------------------------------------- /test/fixtures/typescript-no-compiler-options/index.d.ts: -------------------------------------------------------------------------------- 1 | export as namespace Foo 2 | 3 | export function bar(): void 4 | -------------------------------------------------------------------------------- /test/fixtures/typescript-no-compiler-options/tsconfig.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /test/fixtures/typescript.ts: -------------------------------------------------------------------------------- 1 | export type MyType = string 2 | export enum MyEnum { 3 | Foo, 4 | Bar, 5 | Baz, 6 | } 7 | export interface Foo { 8 | native: string | number 9 | typedef: MyType 10 | enum: MyEnum 11 | } 12 | 13 | export abstract class Bar { 14 | abstract foo(): Foo 15 | 16 | method() { 17 | return 'foo' 18 | } 19 | } 20 | 21 | export function getFoo(): MyType { 22 | return 'foo' 23 | } 24 | 25 | export module MyModule { 26 | export function ModuleFunction() {} 27 | } 28 | 29 | export namespace MyNamespace { 30 | export function NamespaceFunction() {} 31 | 32 | export module NSModule { 33 | export function NSModuleFunction() {} 34 | } 35 | } 36 | 37 | interface NotExported {} 38 | -------------------------------------------------------------------------------- /test/fixtures/umd.js: -------------------------------------------------------------------------------- 1 | ;(function (global, factory) { 2 | typeof exports === 'object' && typeof module !== 'undefined' 3 | ? (module.exports = factory()) 4 | : typeof define === 'function' && define.amd 5 | ? define(factory) 6 | : (global.Immutable = factory()) 7 | })(this, function () { 8 | return {} 9 | }) 10 | -------------------------------------------------------------------------------- /test/fixtures/unused-modules-reexport-crash/src/App.tsx: -------------------------------------------------------------------------------- 1 | import { hello } from './magic/test' 2 | 3 | hello() 4 | 5 | export default function App() {} 6 | -------------------------------------------------------------------------------- /test/fixtures/unused-modules-reexport-crash/src/index.tsx: -------------------------------------------------------------------------------- 1 | import App from './App' 2 | 3 | export const x = App 4 | -------------------------------------------------------------------------------- /test/fixtures/unused-modules-reexport-crash/src/magic/index.js: -------------------------------------------------------------------------------- 1 | export * from './test' 2 | -------------------------------------------------------------------------------- /test/fixtures/unused-modules-reexport-crash/src/magic/test.js: -------------------------------------------------------------------------------- 1 | export function hello() { 2 | console.log('hello!!') 3 | } 4 | 5 | export function unused() { 6 | console.log('im unused!!') 7 | } 8 | -------------------------------------------------------------------------------- /test/fixtures/webpack.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | resolve: { 3 | extensions: ['', '.js', '.jsx'], 4 | root: __dirname, 5 | alias: { 6 | 'alias/jest$': 'jest', // alias for no-extraneous-dependencies tests 7 | 'alias/esm-package': 'esm-package', // alias for no-extraneous-dependencies tests 8 | }, 9 | }, 10 | } 11 | -------------------------------------------------------------------------------- /test/fixtures/webpack.empty.config.js: -------------------------------------------------------------------------------- 1 | module.exports = {} 2 | -------------------------------------------------------------------------------- /test/fixtures/with-flow-typed/flow-typed/npm/myflowtyped_v1.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: ____ 2 | // flow-typed version: ____/myflowtyped_v1.x.x/flow_>=v0.33.x 3 | 4 | declare module 'myflowtyped' { 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/with-flow-typed/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": {} 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/with-syntax-error/package.json: -------------------------------------------------------------------------------- 1 | {{ "name": "with-syntax-error" } 2 | -------------------------------------------------------------------------------- /test/fixtures/with-typescript-dev-dependencies/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "devDependencies": { 3 | "a": "*" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | export * from './fixtures' 2 | -------------------------------------------------------------------------------- /test/package.spec.ts: -------------------------------------------------------------------------------- 1 | import fs from 'node:fs/promises' 2 | import path from 'node:path' 3 | 4 | import type { TSESLint } from '@typescript-eslint/utils' 5 | 6 | import { srcDir } from './utils' 7 | 8 | import { moduleRequire, pluginName } from 'eslint-plugin-import-x/utils' 9 | 10 | function isSourceFile(f: string) { 11 | const ext = path.extname(f) 12 | return ext === '.js' || (ext === '.ts' && !f.endsWith('.d.ts')) 13 | } 14 | 15 | function getRulePath(ruleName: string) { 16 | return path.resolve(srcDir, 'rules', ruleName) 17 | } 18 | 19 | describe('package', () => { 20 | const pkg = path.resolve(srcDir) 21 | 22 | const module = moduleRequire< 23 | TSESLint.Linter.Plugin & { 24 | rules: Record> 25 | } 26 | >(pkg) 27 | 28 | it('exists', () => { 29 | expect(module).toBeDefined() 30 | }) 31 | 32 | it('has every rule', async () => { 33 | const files = await fs.readdir(path.resolve(pkg, 'rules')) 34 | for (const f of files.filter(isSourceFile)) { 35 | expect(module.rules).toHaveProperty(path.basename(f, path.extname(f))) 36 | } 37 | }) 38 | 39 | it('exports all configs', async () => { 40 | const files = await fs.readdir(path.resolve(srcDir, 'config')) 41 | for (const file of files.filter(isSourceFile)) { 42 | expect(module.configs).toHaveProperty( 43 | path.basename(file, path.extname(file)), 44 | ) 45 | } 46 | }) 47 | 48 | it('has configs only for rules that exist', () => { 49 | const preamble = `${pluginName}/` 50 | for (const config of Object.values(module.configs!)) { 51 | if (!config.rules) { 52 | continue 53 | } 54 | for (const rule of Object.keys(config.rules)) { 55 | expect(() => 56 | require(getRulePath(rule.slice(preamble.length))), 57 | ).not.toThrow() 58 | } 59 | } 60 | }) 61 | 62 | it('marks deprecated rules in their metadata', () => { 63 | expect(module.rules!['imports-first'].meta.deprecated).toBe(true) 64 | expect(module.rules!.first.meta.deprecated).not.toBe(true) 65 | }) 66 | }) 67 | -------------------------------------------------------------------------------- /test/rules/no-amd.spec.ts: -------------------------------------------------------------------------------- 1 | import { TSESLint } from '@typescript-eslint/utils' 2 | 3 | import rule from 'eslint-plugin-import-x/rules/no-amd' 4 | 5 | const ruleTester = new TSESLint.RuleTester({ 6 | parserOptions: { ecmaVersion: 2015, sourceType: 'module' }, 7 | }) 8 | 9 | ruleTester.run('no-amd', rule, { 10 | valid: [ 11 | 'import "x";', 12 | 'import x from "x"', 13 | 'var x = require("x")', 14 | 15 | 'require("x")', 16 | // 2-args, not an array 17 | 'require("x", "y")', 18 | // random other function 19 | 'setTimeout(foo, 100)', 20 | // non-identifier callee 21 | '(a || b)(1, 2, 3)', 22 | 23 | // nested scope is fine 24 | 'function x() { define(["a"], function (a) {}) }', 25 | 'function x() { require(["a"], function (a) {}) }', 26 | 27 | // unmatched arg types/number 28 | 'define(0, 1, 2)', 29 | 'define("a")', 30 | ], 31 | 32 | invalid: [ 33 | { 34 | code: 'define([], function() {})', 35 | output: null, 36 | errors: [ 37 | { 38 | messageId: 'amd', 39 | data: { 40 | type: 'define', 41 | }, 42 | }, 43 | ], 44 | }, 45 | { 46 | code: 'define(["a"], function(a) { console.log(a); })', 47 | output: null, 48 | errors: [ 49 | { 50 | messageId: 'amd', 51 | data: { 52 | type: 'define', 53 | }, 54 | }, 55 | ], 56 | }, 57 | 58 | { 59 | code: 'require([], function() {})', 60 | output: null, 61 | errors: [ 62 | { 63 | messageId: 'amd', 64 | data: { 65 | type: 'require', 66 | }, 67 | }, 68 | ], 69 | }, 70 | { 71 | code: 'require(["a"], function(a) { console.log(a); })', 72 | output: null, 73 | errors: [ 74 | { 75 | messageId: 'amd', 76 | data: { 77 | type: 'require', 78 | }, 79 | }, 80 | ], 81 | }, 82 | ], 83 | }) 84 | -------------------------------------------------------------------------------- /test/rules/no-named-default.spec.ts: -------------------------------------------------------------------------------- 1 | import { TSESLint } from '@typescript-eslint/utils' 2 | 3 | import { test, testVersion, SYNTAX_CASES, parsers } from '../utils' 4 | 5 | import rule from 'eslint-plugin-import-x/rules/no-named-default' 6 | 7 | const ruleTester = new TSESLint.RuleTester() 8 | 9 | ruleTester.run('no-named-default', rule, { 10 | valid: [ 11 | test({ code: 'import bar from "./bar";' }), 12 | test({ code: 'import bar, { foo } from "./bar";' }), 13 | 14 | // Should ignore imported flow types 15 | test({ 16 | code: 'import { type default as Foo } from "./bar";', 17 | parser: parsers.BABEL, 18 | }), 19 | test({ 20 | code: 'import { typeof default as Foo } from "./bar";', 21 | parser: parsers.BABEL, 22 | }), 23 | 24 | ...SYNTAX_CASES, 25 | ], 26 | 27 | invalid: [ 28 | /*test({ 29 | code: 'import { default } from "./bar";', 30 | errors: [{ 31 | message: 'Use default import syntax to import \'default\'.', 32 | type: 'Identifier', 33 | }], 34 | parser: parsers.BABEL, 35 | }),*/ 36 | test({ 37 | code: 'import { default as bar } from "./bar";', 38 | errors: [ 39 | { 40 | message: "Use default import syntax to import 'bar'.", 41 | type: 'Identifier', 42 | }, 43 | ], 44 | }), 45 | test({ 46 | code: 'import { foo, default as bar } from "./bar";', 47 | errors: [ 48 | { 49 | message: "Use default import syntax to import 'bar'.", 50 | type: 'Identifier', 51 | }, 52 | ], 53 | }), 54 | 55 | // es2022: Arbitrary module namespace identifier names 56 | ...testVersion('>= 8.7', () => ({ 57 | code: 'import { "default" as bar } from "./bar";', 58 | errors: [ 59 | { 60 | message: "Use default import syntax to import 'bar'.", 61 | type: 'Identifier', 62 | }, 63 | ], 64 | parserOptions: { 65 | ecmaVersion: 2022, 66 | }, 67 | })), 68 | ], 69 | }) 70 | -------------------------------------------------------------------------------- /test/rules/unambiguous.spec.ts: -------------------------------------------------------------------------------- 1 | import { TSESLint } from '@typescript-eslint/utils' 2 | 3 | import { parsers } from '../utils' 4 | 5 | import rule from 'eslint-plugin-import-x/rules/unambiguous' 6 | 7 | const ruleTester = new TSESLint.RuleTester() 8 | 9 | ruleTester.run('unambiguous', rule, { 10 | valid: [ 11 | 'function x() {}', 12 | '"use strict"; function y() {}', 13 | 14 | { 15 | code: 'import y from "z"; function x() {}', 16 | parserOptions: { ecmaVersion: 2015, sourceType: 'module' }, 17 | }, 18 | { 19 | code: 'import * as y from "z"; function x() {}', 20 | parserOptions: { ecmaVersion: 2015, sourceType: 'module' }, 21 | }, 22 | { 23 | code: 'import { y } from "z"; function x() {}', 24 | parserOptions: { ecmaVersion: 2015, sourceType: 'module' }, 25 | }, 26 | { 27 | code: 'import z, { y } from "z"; function x() {}', 28 | parserOptions: { ecmaVersion: 2015, sourceType: 'module' }, 29 | }, 30 | { 31 | code: 'function x() {}; export {}', 32 | parserOptions: { ecmaVersion: 2015, sourceType: 'module' }, 33 | }, 34 | { 35 | code: 'function x() {}; export { x }', 36 | parserOptions: { ecmaVersion: 2015, sourceType: 'module' }, 37 | }, 38 | { 39 | code: 'function x() {}; export { y } from "z"', 40 | parserOptions: { ecmaVersion: 2015, sourceType: 'module' }, 41 | }, 42 | { 43 | code: 'function x() {}; export * as y from "z"', 44 | parser: parsers.BABEL, 45 | parserOptions: { ecmaVersion: 2015, sourceType: 'module' }, 46 | }, 47 | { 48 | code: 'export function x() {}', 49 | parserOptions: { ecmaVersion: 2015, sourceType: 'module' }, 50 | }, 51 | ], 52 | invalid: [ 53 | { 54 | code: 'function x() {}', 55 | parserOptions: { ecmaVersion: 2015, sourceType: 'module' }, 56 | output: null, 57 | errors: [ 58 | { 59 | messageId: 'module', 60 | }, 61 | ], 62 | }, 63 | ], 64 | }) 65 | -------------------------------------------------------------------------------- /test/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.base" 3 | } 4 | -------------------------------------------------------------------------------- /test/utils/docs-url.spec.ts: -------------------------------------------------------------------------------- 1 | import pkg from 'eslint-plugin-import-x/package.json' 2 | import { docsUrl } from 'eslint-plugin-import-x/utils' 3 | 4 | describe('docsUrl', () => { 5 | it('returns the rule documentation URL when given a rule name', () => { 6 | expect(docsUrl('foo')).toBe( 7 | `https://github.com/un-ts/eslint-plugin-import-x/blob/v${pkg.version}/docs/rules/foo.md`, 8 | ) 9 | }) 10 | 11 | it('supports an optional commit-ish parameter', () => { 12 | expect(docsUrl('foo', 'bar')).toBe( 13 | 'https://github.com/un-ts/eslint-plugin-import-x/blob/bar/docs/rules/foo.md', 14 | ) 15 | }) 16 | }) 17 | -------------------------------------------------------------------------------- /test/utils/eslint-parser.ts: -------------------------------------------------------------------------------- 1 | export = { 2 | parseForESLint() { 3 | return { 4 | ast: {}, 5 | } 6 | }, 7 | } 8 | -------------------------------------------------------------------------------- /test/utils/parse-stub-parser.ts: -------------------------------------------------------------------------------- 1 | // this stub must be in a separate file to require from parse via moduleRequire 2 | export = { 3 | parse() { 4 | // 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /tsconfig.base.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@1stg/tsconfig/node", 3 | "compilerOptions": { 4 | "lib": ["ES2022"], 5 | "paths": { 6 | "eslint-plugin-import-x": ["./src"], 7 | "eslint-plugin-import-x/package.json": ["./package.json"], 8 | "eslint-plugin-import-x/*": ["./src/*"] 9 | } 10 | }, 11 | "exclude": ["test/fixtures"] 12 | } 13 | --------------------------------------------------------------------------------