eslint-plugin-fast-import 1.0.0-beta2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/.prettierrc.json +6 -0
  2. package/.vscode/launch.json +39 -0
  3. package/LICENSE +21 -0
  4. package/README.md +3 -0
  5. package/dist/module/computeAnalyzedInfo.d.ts +3 -0
  6. package/dist/module/computeAnalyzedInfo.js +297 -0
  7. package/dist/module/computeAnalyzedInfo.js.map +1 -0
  8. package/dist/module/computeBaseInfo.d.ts +24 -0
  9. package/dist/module/computeBaseInfo.js +564 -0
  10. package/dist/module/computeBaseInfo.js.map +1 -0
  11. package/dist/module/computeResolvedInfo.d.ts +7 -0
  12. package/dist/module/computeResolvedInfo.js +361 -0
  13. package/dist/module/computeResolvedInfo.js.map +1 -0
  14. package/dist/module/module.d.ts +20 -0
  15. package/dist/module/module.js +224 -0
  16. package/dist/module/module.js.map +1 -0
  17. package/dist/module/util.d.ts +44 -0
  18. package/dist/module/util.js +67 -0
  19. package/dist/module/util.js.map +1 -0
  20. package/dist/plugin.d.ts +19 -0
  21. package/dist/plugin.js +57 -0
  22. package/dist/plugin.js.map +1 -0
  23. package/dist/rules/circular/circular.d.ts +2 -0
  24. package/dist/rules/circular/circular.js +107 -0
  25. package/dist/rules/circular/circular.js.map +1 -0
  26. package/dist/rules/entryPoint/entryPoint.d.ts +1 -0
  27. package/dist/rules/entryPoint/entryPoint.js +38 -0
  28. package/dist/rules/entryPoint/entryPoint.js.map +1 -0
  29. package/dist/rules/externalBarrelReexports/externalBarrelReexports.d.ts +1 -0
  30. package/dist/rules/externalBarrelReexports/externalBarrelReexports.js +41 -0
  31. package/dist/rules/externalBarrelReexports/externalBarrelReexports.js.map +1 -0
  32. package/dist/rules/missing/missing.d.ts +1 -0
  33. package/dist/rules/missing/missing.js +59 -0
  34. package/dist/rules/missing/missing.js.map +1 -0
  35. package/dist/rules/testInProd/testInProd.d.ts +1 -0
  36. package/dist/rules/testInProd/testInProd.js +42 -0
  37. package/dist/rules/testInProd/testInProd.js.map +1 -0
  38. package/dist/rules/unused/unused.d.ts +3 -0
  39. package/dist/rules/unused/unused.js +77 -0
  40. package/dist/rules/unused/unused.js.map +1 -0
  41. package/dist/rules/util.d.ts +11 -0
  42. package/dist/rules/util.js +107 -0
  43. package/dist/rules/util.js.map +1 -0
  44. package/dist/settings/settings.d.ts +12 -0
  45. package/dist/settings/settings.js +123 -0
  46. package/dist/settings/settings.js.map +1 -0
  47. package/dist/settings/typescript.d.ts +3 -0
  48. package/dist/settings/typescript.js +39 -0
  49. package/dist/settings/typescript.js.map +1 -0
  50. package/dist/settings/user.d.ts +45 -0
  51. package/dist/settings/user.js +52 -0
  52. package/dist/settings/user.js.map +1 -0
  53. package/dist/settings/util.d.ts +2 -0
  54. package/dist/settings/util.js +33 -0
  55. package/dist/settings/util.js.map +1 -0
  56. package/dist/types/analyzed.d.ts +120 -0
  57. package/dist/types/analyzed.js +2 -0
  58. package/dist/types/analyzed.js.map +1 -0
  59. package/dist/types/base.d.ts +230 -0
  60. package/dist/types/base.js +2 -0
  61. package/dist/types/base.js.map +1 -0
  62. package/dist/types/context.d.ts +2 -0
  63. package/dist/types/context.js +2 -0
  64. package/dist/types/context.js.map +1 -0
  65. package/dist/types/resolved.d.ts +60 -0
  66. package/dist/types/resolved.js +2 -0
  67. package/dist/types/resolved.js.map +1 -0
  68. package/dist/util/code.d.ts +1 -0
  69. package/dist/util/code.js +6 -0
  70. package/dist/util/code.js.map +1 -0
  71. package/dist/util/error.d.ts +14 -0
  72. package/dist/util/error.js +19 -0
  73. package/dist/util/error.js.map +1 -0
  74. package/dist/util/files.d.ts +10 -0
  75. package/dist/util/files.js +122 -0
  76. package/dist/util/files.js.map +1 -0
  77. package/dist/util/logging.d.ts +5 -0
  78. package/dist/util/logging.js +19 -0
  79. package/dist/util/logging.js.map +1 -0
  80. package/eslint.config.mjs +85 -0
  81. package/jest.config.ts +10 -0
  82. package/package.json +49 -0
  83. package/tsconfig.json +31 -0
@@ -0,0 +1,44 @@
1
+ import { TSESTree } from '@typescript-eslint/typescript-estree';
2
+ type ImportDeclaration = TSESTree.ImportDeclaration | TSESTree.ImportExpression;
3
+ export type ExportDeclaration = TSESTree.ExportDefaultDeclaration | TSESTree.ExportNamedDeclaration;
4
+ type ReexportDeclaration = TSESTree.ExportNamedDeclarationWithSource | TSESTree.ExportAllDeclaration;
5
+ /**
6
+ * Reads in a file specified by `filePath` and returns the raw string contents
7
+ * and the parsed AST.
8
+ */
9
+ export declare function parseFile(filePath: string): {
10
+ filePath: string;
11
+ fileContents: string;
12
+ ast: import("@typescript-eslint/typescript-estree").AST<{
13
+ loc: true;
14
+ range: true;
15
+ tokens: true;
16
+ jsx: boolean;
17
+ }>;
18
+ };
19
+ type WalkOptions = {
20
+ filePath: string;
21
+ fileContents: string;
22
+ ast: TSESTree.Program;
23
+ /**
24
+ * A callback to be called for all of the various import statement nodes,
25
+ * including dynamic import statements
26
+ */
27
+ importDeclaration: (node: ImportDeclaration) => void;
28
+ /**
29
+ * A callback to be called for all of the various export statement nodes.
30
+ *
31
+ * Note: this does _not_ include reexport nodes, even though sometimes the
32
+ * actual node is the same type as a reexport node.
33
+ */
34
+ exportDeclaration: (node: ExportDeclaration) => void;
35
+ /**
36
+ * A callback to be called for all of the various reexport statement nodes
37
+ */
38
+ reexportDeclaration: (node: ReexportDeclaration) => void;
39
+ };
40
+ /**
41
+ * This helper function makes traversing the AST of a file easier.
42
+ */
43
+ export declare function traverse({ ast, filePath, fileContents, importDeclaration, exportDeclaration, reexportDeclaration, }: WalkOptions): void;
44
+ export {};
@@ -0,0 +1,67 @@
1
+ import { InternalError } from '../util/error.js';
2
+ import { TSESTree } from '@typescript-eslint/typescript-estree';
3
+ import { parse, simpleTraverse } from '@typescript-eslint/typescript-estree';
4
+ import { readFileSync } from 'fs';
5
+ /**
6
+ * Reads in a file specified by `filePath` and returns the raw string contents
7
+ * and the parsed AST.
8
+ */
9
+ export function parseFile(filePath) {
10
+ const fileContents = readFileSync(filePath, 'utf-8');
11
+ const ast = parse(fileContents, {
12
+ loc: true,
13
+ range: true,
14
+ tokens: true,
15
+ // JSX is a proper superset of JavaScript, meaning JSX can appear in both .js and .jsx files. TSX is *not* a
16
+ // proper superset of TypeScript, however, and so JSX can only appear in .tsx files, not .ts files
17
+ jsx: !filePath.endsWith('.ts'),
18
+ });
19
+ return { filePath, fileContents, ast };
20
+ }
21
+ /**
22
+ * This helper function makes traversing the AST of a file easier.
23
+ */
24
+ export function traverse({ ast, filePath, fileContents, importDeclaration, exportDeclaration, reexportDeclaration, }) {
25
+ // For some reason, `simpleTraverse` only types `node` as `TSESTree.Node`, not
26
+ // the type of node specified by the function name. This helper function
27
+ // asserts the type and does a run-time check, just in case, to make
28
+ // TypeScript happy.
29
+ //
30
+ // This type parameter is actually necessary, since it's used in the assert
31
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters
32
+ function validateNodeType(node, nodeType) {
33
+ if (node.type !== nodeType) {
34
+ throw new InternalError(`simpleTraverse returned unexpected type ${node.type}`, { filePath, fileContents, node });
35
+ }
36
+ }
37
+ simpleTraverse(ast, {
38
+ visitors: {
39
+ ImportDeclaration(node) {
40
+ validateNodeType(node, TSESTree.AST_NODE_TYPES.ImportDeclaration);
41
+ importDeclaration(node);
42
+ },
43
+ ImportExpression(node) {
44
+ validateNodeType(node, TSESTree.AST_NODE_TYPES.ImportExpression);
45
+ importDeclaration(node);
46
+ },
47
+ ExportDefaultDeclaration(node) {
48
+ validateNodeType(node, TSESTree.AST_NODE_TYPES.ExportDefaultDeclaration);
49
+ exportDeclaration(node);
50
+ },
51
+ ExportAllDeclaration(node) {
52
+ validateNodeType(node, TSESTree.AST_NODE_TYPES.ExportAllDeclaration);
53
+ reexportDeclaration(node);
54
+ },
55
+ ExportNamedDeclaration(node) {
56
+ validateNodeType(node, TSESTree.AST_NODE_TYPES.ExportNamedDeclaration);
57
+ if (node.source) {
58
+ reexportDeclaration(node);
59
+ }
60
+ else {
61
+ exportDeclaration(node);
62
+ }
63
+ },
64
+ },
65
+ });
66
+ }
67
+ //# sourceMappingURL=util.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"util.js","sourceRoot":"","sources":["../../src/module/util.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,sCAAsC,CAAC;AAChE,OAAO,EAAE,KAAK,EAAE,cAAc,EAAE,MAAM,sCAAsC,CAAC;AAC7E,OAAO,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAelC;;;GAGG;AACH,MAAM,UAAU,SAAS,CAAC,QAAgB;IACxC,MAAM,YAAY,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACrD,MAAM,GAAG,GAAG,KAAK,CAAC,YAAY,EAAE;QAC9B,GAAG,EAAE,IAAI;QACT,KAAK,EAAE,IAAI;QACX,MAAM,EAAE,IAAI;QAEZ,4GAA4G;QAC5G,kGAAkG;QAClG,GAAG,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC;KAC/B,CAAC,CAAC;IACH,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,GAAG,EAAE,CAAC;AACzC,CAAC;AAyBD;;GAEG;AACH,MAAM,UAAU,QAAQ,CAAC,EACvB,GAAG,EACH,QAAQ,EACR,YAAY,EACZ,iBAAiB,EACjB,iBAAiB,EACjB,mBAAmB,GACP;IACZ,8EAA8E;IAC9E,wEAAwE;IACxE,oEAAoE;IACpE,oBAAoB;IACpB,EAAE;IACF,2EAA2E;IAC3E,6EAA6E;IAC7E,SAAS,gBAAgB,CACvB,IAAmB,EACnB,QAAiC;QAEjC,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC3B,MAAM,IAAI,aAAa,CACrB,2CAA2C,IAAI,CAAC,IAAI,EAAE,EACtD,EAAE,QAAQ,EAAE,YAAY,EAAE,IAAI,EAAE,CACjC,CAAC;QACJ,CAAC;IACH,CAAC;IAED,cAAc,CAAC,GAAG,EAAE;QAClB,QAAQ,EAAE;YACR,iBAAiB,CAAC,IAAI;gBACpB,gBAAgB,CACd,IAAI,EACJ,QAAQ,CAAC,cAAc,CAAC,iBAAiB,CAC1C,CAAC;gBACF,iBAAiB,CAAC,IAAI,CAAC,CAAC;YAC1B,CAAC;YACD,gBAAgB,CAAC,IAAI;gBACnB,gBAAgB,CACd,IAAI,EACJ,QAAQ,CAAC,cAAc,CAAC,gBAAgB,CACzC,CAAC;gBACF,iBAAiB,CAAC,IAAI,CAAC,CAAC;YAC1B,CAAC;YACD,wBAAwB,CAAC,IAAI;gBAC3B,gBAAgB,CACd,IAAI,EACJ,QAAQ,CAAC,cAAc,CAAC,wBAAwB,CACjD,CAAC;gBACF,iBAAiB,CAAC,IAAI,CAAC,CAAC;YAC1B,CAAC;YACD,oBAAoB,CAAC,IAAI;gBACvB,gBAAgB,CACd,IAAI,EACJ,QAAQ,CAAC,cAAc,CAAC,oBAAoB,CAC7C,CAAC;gBACF,mBAAmB,CAAC,IAAI,CAAC,CAAC;YAC5B,CAAC;YACD,sBAAsB,CAAC,IAAI;gBACzB,gBAAgB,CACd,IAAI,EACJ,QAAQ,CAAC,cAAc,CAAC,sBAAsB,CAC/C,CAAC;gBACF,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;oBAChB,mBAAmB,CAAC,IAAI,CAAC,CAAC;gBAC5B,CAAC;qBAAM,CAAC;oBACN,iBAAiB,CAAC,IAAI,CAAC,CAAC;gBAC1B,CAAC;YACH,CAAC;SACF;KACF,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,19 @@
1
+ declare const plugin: {
2
+ meta: {
3
+ name: string;
4
+ version: string;
5
+ };
6
+ configs: {};
7
+ rules: {
8
+ 'no-unused-exports': import("@typescript-eslint/utils/ts-eslint").RuleModule<"noUnusedExports" | "noTestOnlyImports", [{
9
+ allowNonTestTypeExports: boolean;
10
+ } | undefined], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
11
+ 'no-circular-imports': import("@typescript-eslint/utils/ts-eslint").RuleModule<"noCircularImports", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
12
+ 'no-entry-point-imports': import("@typescript-eslint/utils/ts-eslint").RuleModule<"noEntryPointImports", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
13
+ 'no-missing-imports': import("@typescript-eslint/utils/ts-eslint").RuleModule<"noMissingImports", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
14
+ 'no-external-barrel-reexports': import("@typescript-eslint/utils/ts-eslint").RuleModule<"noExternalBarrelReexports", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
15
+ 'no-test-imports-in-prod': import("@typescript-eslint/utils/ts-eslint").RuleModule<"noTestImports", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
16
+ };
17
+ processors: {};
18
+ };
19
+ export default plugin;
package/dist/plugin.js ADDED
@@ -0,0 +1,57 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { getDirname } from 'cross-dirname';
4
+ import { noUnusedExports } from './rules/unused/unused.js';
5
+ import { noCircularImports } from './rules/circular/circular.js';
6
+ import { noEntryPointImports } from './rules/entryPoint/entryPoint.js';
7
+ import { noMissingImports } from './rules/missing/missing.js';
8
+ import { noExternalBarrelReexports } from './rules/externalBarrelReexports/externalBarrelReexports.js';
9
+ import { noTestImportsInProd } from './rules/testInProd/testInProd.js';
10
+ const { name, version } = JSON.parse(readFileSync(join(getDirname(), '..', 'package.json'), 'utf8'));
11
+ const plugin = {
12
+ meta: {
13
+ name,
14
+ version,
15
+ },
16
+ configs: {},
17
+ rules: {
18
+ 'no-unused-exports': noUnusedExports,
19
+ 'no-circular-imports': noCircularImports,
20
+ 'no-entry-point-imports': noEntryPointImports,
21
+ 'no-missing-imports': noMissingImports,
22
+ 'no-external-barrel-reexports': noExternalBarrelReexports,
23
+ 'no-test-imports-in-prod': noTestImportsInProd,
24
+ },
25
+ processors: {},
26
+ };
27
+ // assign configs here so we can reference `plugin`
28
+ Object.assign(plugin.configs, {
29
+ recommended: {
30
+ plugins: {
31
+ 'fast-import': plugin,
32
+ },
33
+ rules: {
34
+ 'fast-import/no-unused-exports': 'error',
35
+ 'fast-import/no-circular-imports': 'error',
36
+ 'fast-import/no-entry-point-imports': 'error',
37
+ 'fast-import/no-missing-imports': 'error',
38
+ 'fast-import/no-external-barrel-reexports': 'error',
39
+ 'fast-import/no-test-imports-in-prod': 'error',
40
+ },
41
+ },
42
+ off: {
43
+ plugins: {
44
+ 'fast-import': plugin,
45
+ },
46
+ rules: {
47
+ 'fast-import/no-unused-exports': 'off',
48
+ 'fast-import/no-circular-imports': 'off',
49
+ 'fast-import/no-entry-point-imports': 'off',
50
+ 'fast-import/no-missing-imports': 'off',
51
+ 'fast-import/no-external-barrel-reexports': 'off',
52
+ 'fast-import/no-test-imports-in-prod': 'off',
53
+ },
54
+ },
55
+ });
56
+ export default plugin;
57
+ //# sourceMappingURL=plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,EAAE,yBAAyB,EAAE,MAAM,4DAA4D,CAAC;AACvG,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAEvE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC,KAAK,CAClC,YAAY,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE,IAAI,EAAE,cAAc,CAAC,EAAE,MAAM,CAAC,CAC1B,CAAC;AAEvC,MAAM,MAAM,GAAG;IACb,IAAI,EAAE;QACJ,IAAI;QACJ,OAAO;KACR;IACD,OAAO,EAAE,EAAE;IACX,KAAK,EAAE;QACL,mBAAmB,EAAE,eAAe;QACpC,qBAAqB,EAAE,iBAAiB;QACxC,wBAAwB,EAAE,mBAAmB;QAC7C,oBAAoB,EAAE,gBAAgB;QACtC,8BAA8B,EAAE,yBAAyB;QACzD,yBAAyB,EAAE,mBAAmB;KAC/C;IACD,UAAU,EAAE,EAAE;CACf,CAAC;AAEF,mDAAmD;AACnD,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE;IAC5B,WAAW,EAAE;QACX,OAAO,EAAE;YACP,aAAa,EAAE,MAAM;SACtB;QACD,KAAK,EAAE;YACL,+BAA+B,EAAE,OAAO;YACxC,iCAAiC,EAAE,OAAO;YAC1C,oCAAoC,EAAE,OAAO;YAC7C,gCAAgC,EAAE,OAAO;YACzC,0CAA0C,EAAE,OAAO;YACnD,qCAAqC,EAAE,OAAO;SAC/C;KACF;IACD,GAAG,EAAE;QACH,OAAO,EAAE;YACP,aAAa,EAAE,MAAM;SACtB;QACD,KAAK,EAAE;YACL,+BAA+B,EAAE,KAAK;YACtC,iCAAiC,EAAE,KAAK;YACxC,oCAAoC,EAAE,KAAK;YAC3C,gCAAgC,EAAE,KAAK;YACvC,0CAA0C,EAAE,KAAK;YACjD,qCAAqC,EAAE,KAAK;SAC7C;KACF;CACF,CAAC,CAAC;AAEH,eAAe,MAAM,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function _resetCircularMap(): void;
2
+ export declare const noCircularImports: import("@typescript-eslint/utils/ts-eslint").RuleModule<"noCircularImports", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
@@ -0,0 +1,107 @@
1
+ import { createRule, getESMInfo, registerUpdateListener } from '../util.js';
2
+ import { InternalError } from '../../util/error.js';
3
+ function checkFile(originalFilePath, currentFilePath, projectInfo, importStack, visitedFiles) {
4
+ const fileDetails = projectInfo.files.get(currentFilePath);
5
+ if (!fileDetails) {
6
+ throw new InternalError(`Could not get file info for "${currentFilePath}"`);
7
+ }
8
+ // Non-JS files by definition can't be circilar, since they can't import JS
9
+ if (fileDetails.fileType !== 'code') {
10
+ return false;
11
+ }
12
+ // Mark this file as visited
13
+ visitedFiles.push(currentFilePath);
14
+ // Now check if this file is part of a cycle
15
+ const firstInstanceIndex = importStack.indexOf(currentFilePath);
16
+ if (firstInstanceIndex !== -1) {
17
+ const filesInCycle = importStack.slice(firstInstanceIndex);
18
+ return filesInCycle.includes(originalFilePath);
19
+ }
20
+ // If this wasn't a cycle, then keep exploring
21
+ for (const importEntry of [
22
+ ...fileDetails.imports,
23
+ ...fileDetails.reexports,
24
+ ]) {
25
+ if (('isTypeImport' in importEntry && importEntry.isTypeImport) ||
26
+ ('isTypeReexport' in importEntry && importEntry.isTypeReexport) ||
27
+ importEntry.moduleType !== 'firstPartyCode' ||
28
+ visitedFiles.includes(importEntry.resolvedModulePath)) {
29
+ continue;
30
+ }
31
+ if (checkFile(originalFilePath, importEntry.resolvedModulePath, projectInfo, [...importStack, currentFilePath], visitedFiles)) {
32
+ return true;
33
+ }
34
+ }
35
+ return false;
36
+ }
37
+ // Map of filepaths to imports/reexports with circular dependencies
38
+ const circularImportMap = new Map();
39
+ registerUpdateListener(() => {
40
+ circularImportMap.clear();
41
+ });
42
+ // This is only used in tests, since update listeners aren't guaranteed to
43
+ // be called on each run
44
+ // eslint-disable-next-line fast-import/no-unused-exports
45
+ export function _resetCircularMap() {
46
+ circularImportMap.clear();
47
+ }
48
+ export const noCircularImports = createRule({
49
+ name: 'no-circular-imports',
50
+ meta: {
51
+ docs: {
52
+ description: 'Ensures that there are no circular imports',
53
+ },
54
+ schema: [],
55
+ fixable: undefined,
56
+ type: 'problem',
57
+ messages: {
58
+ noCircularImports: 'Imports cannot be circular',
59
+ },
60
+ },
61
+ defaultOptions: [],
62
+ create(context) {
63
+ const esmInfo = getESMInfo(context);
64
+ if (!esmInfo) {
65
+ return {};
66
+ }
67
+ const { fileInfo, projectInfo } = esmInfo;
68
+ if (fileInfo.fileType !== 'code') {
69
+ return {};
70
+ }
71
+ // If we recomputed on this run, then we need to recompute cycles
72
+ if (!circularImportMap.has(context.filename)) {
73
+ const importedFilesSearched = new Set();
74
+ const circularImportNodes = [];
75
+ for (const importEntry of [...fileInfo.imports, ...fileInfo.reexports]) {
76
+ if (!('resolvedModulePath' in importEntry) ||
77
+ !importEntry.resolvedModulePath ||
78
+ importedFilesSearched.has(importEntry.resolvedModulePath)) {
79
+ continue;
80
+ }
81
+ importedFilesSearched.add(importEntry.resolvedModulePath);
82
+ if (checkFile(context.filename, importEntry.resolvedModulePath, projectInfo, [context.filename], [])) {
83
+ circularImportNodes.push(importEntry.resolvedModulePath);
84
+ }
85
+ }
86
+ circularImportMap.set(context.filename, circularImportNodes);
87
+ }
88
+ const circularImports = circularImportMap.get(context.filename);
89
+ if (!circularImports) {
90
+ throw new InternalError(`Circular imports are undefined for ${context.filename}`);
91
+ }
92
+ for (const circularImport of circularImports) {
93
+ for (const importEntry of [...fileInfo.imports, ...fileInfo.reexports]) {
94
+ if (importEntry.moduleType === 'firstPartyCode' &&
95
+ importEntry.resolvedModulePath === circularImport) {
96
+ context.report({
97
+ messageId: 'noCircularImports',
98
+ node: importEntry.statementNode,
99
+ });
100
+ continue;
101
+ }
102
+ }
103
+ }
104
+ return {};
105
+ },
106
+ });
107
+ //# sourceMappingURL=circular.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"circular.js","sourceRoot":"","sources":["../../../src/rules/circular/circular.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export declare const noEntryPointImports: import("@typescript-eslint/utils/ts-eslint").RuleModule<"noEntryPointImports", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
@@ -0,0 +1,38 @@
1
+ import { createRule, getESMInfo } from '../util.js';
2
+ export const noEntryPointImports = createRule({
3
+ name: 'no-entry-point-imports',
4
+ meta: {
5
+ docs: {
6
+ description: 'Ensures that exports in entry point files are not imported',
7
+ },
8
+ schema: [],
9
+ fixable: undefined,
10
+ type: 'problem',
11
+ messages: {
12
+ noEntryPointImports: 'Entry point exports should be not imported',
13
+ },
14
+ },
15
+ defaultOptions: [],
16
+ create(context) {
17
+ const esmInfo = getESMInfo(context);
18
+ // No project info means this file wasn't found as part of the project, e.g.
19
+ // because it's ignored
20
+ if (!esmInfo) {
21
+ return {};
22
+ }
23
+ const { fileInfo } = esmInfo;
24
+ if (fileInfo.fileType !== 'code') {
25
+ return {};
26
+ }
27
+ for (const exportEntry of [...fileInfo.exports, ...fileInfo.reexports]) {
28
+ if (exportEntry.isEntryPoint && exportEntry.importedByFiles.length) {
29
+ context.report({
30
+ messageId: 'noEntryPointImports',
31
+ node: exportEntry.reportNode,
32
+ });
33
+ }
34
+ }
35
+ return {};
36
+ },
37
+ });
38
+ //# sourceMappingURL=entryPoint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entryPoint.js","sourceRoot":"","sources":["../../../src/rules/entryPoint/entryPoint.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAEpD,MAAM,CAAC,MAAM,mBAAmB,GAAG,UAAU,CAAC;IAC5C,IAAI,EAAE,wBAAwB;IAC9B,IAAI,EAAE;QACJ,IAAI,EAAE;YACJ,WAAW,EAAE,4DAA4D;SAC1E;QACD,MAAM,EAAE,EAAE;QACV,OAAO,EAAE,SAAS;QAClB,IAAI,EAAE,SAAS;QACf,QAAQ,EAAE;YACR,mBAAmB,EAAE,4CAA4C;SAClE;KACF;IACD,cAAc,EAAE,EAAE;IAClB,MAAM,CAAC,OAAO;QACZ,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;QAEpC,4EAA4E;QAC5E,uBAAuB;QACvB,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC;QAC7B,IAAI,QAAQ,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;YACjC,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,KAAK,MAAM,WAAW,IAAI,CAAC,GAAG,QAAQ,CAAC,OAAO,EAAE,GAAG,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;YACvE,IAAI,WAAW,CAAC,YAAY,IAAI,WAAW,CAAC,eAAe,CAAC,MAAM,EAAE,CAAC;gBACnE,OAAO,CAAC,MAAM,CAAC;oBACb,SAAS,EAAE,qBAAqB;oBAChC,IAAI,EAAE,WAAW,CAAC,UAAU;iBAC7B,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,OAAO,EAAE,CAAC;IACZ,CAAC;CACF,CAAC,CAAC"}
@@ -0,0 +1 @@
1
+ export declare const noExternalBarrelReexports: import("@typescript-eslint/utils/ts-eslint").RuleModule<"noExternalBarrelReexports", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
@@ -0,0 +1,41 @@
1
+ import { createRule, getESMInfo } from '../util.js';
2
+ export const noExternalBarrelReexports = createRule({
3
+ name: 'no-external-barrel-reexports',
4
+ meta: {
5
+ docs: {
6
+ description: 'Ensures that code does not barrel reexport builtin or third party modules. Doing so is not supported by fast-import for performance reasons',
7
+ },
8
+ schema: [],
9
+ fixable: undefined,
10
+ type: 'problem',
11
+ messages: {
12
+ noExternalBarrelReexports: 'Barrel reexporting builtin or third party modules is not supported',
13
+ },
14
+ },
15
+ defaultOptions: [],
16
+ create(context) {
17
+ const esmInfo = getESMInfo(context);
18
+ if (!esmInfo) {
19
+ return {};
20
+ }
21
+ const { fileInfo } = esmInfo;
22
+ if (fileInfo.fileType !== 'code') {
23
+ return {};
24
+ }
25
+ // Now check reexports
26
+ for (const reexportEntry of fileInfo.reexports) {
27
+ if (reexportEntry.reexportType === 'single') {
28
+ continue;
29
+ }
30
+ if (reexportEntry.moduleType === 'builtin' ||
31
+ reexportEntry.moduleType === 'thirdParty') {
32
+ context.report({
33
+ node: reexportEntry.reportNode,
34
+ messageId: 'noExternalBarrelReexports',
35
+ });
36
+ }
37
+ }
38
+ return {};
39
+ },
40
+ });
41
+ //# sourceMappingURL=externalBarrelReexports.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"externalBarrelReexports.js","sourceRoot":"","sources":["../../../src/rules/externalBarrelReexports/externalBarrelReexports.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAEpD,MAAM,CAAC,MAAM,yBAAyB,GAAG,UAAU,CAAC;IAClD,IAAI,EAAE,8BAA8B;IACpC,IAAI,EAAE;QACJ,IAAI,EAAE;YACJ,WAAW,EACT,6IAA6I;SAChJ;QACD,MAAM,EAAE,EAAE;QACV,OAAO,EAAE,SAAS;QAClB,IAAI,EAAE,SAAS;QACf,QAAQ,EAAE;YACR,yBAAyB,EACvB,oEAAoE;SACvE;KACF;IACD,cAAc,EAAE,EAAE;IAClB,MAAM,CAAC,OAAO;QACZ,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;QACpC,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC;QAC7B,IAAI,QAAQ,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;YACjC,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,sBAAsB;QACtB,KAAK,MAAM,aAAa,IAAI,QAAQ,CAAC,SAAS,EAAE,CAAC;YAC/C,IAAI,aAAa,CAAC,YAAY,KAAK,QAAQ,EAAE,CAAC;gBAC5C,SAAS;YACX,CAAC;YACD,IACE,aAAa,CAAC,UAAU,KAAK,SAAS;gBACtC,aAAa,CAAC,UAAU,KAAK,YAAY,EACzC,CAAC;gBACD,OAAO,CAAC,MAAM,CAAC;oBACb,IAAI,EAAE,aAAa,CAAC,UAAU;oBAC9B,SAAS,EAAE,2BAA2B;iBACvC,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,OAAO,EAAE,CAAC;IACZ,CAAC;CACF,CAAC,CAAC"}
@@ -0,0 +1 @@
1
+ export declare const noMissingImports: import("@typescript-eslint/utils/ts-eslint").RuleModule<"noMissingImports", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
@@ -0,0 +1,59 @@
1
+ import { createRule, getESMInfo } from '../util.js';
2
+ export const noMissingImports = createRule({
3
+ name: 'no-missing-imports',
4
+ meta: {
5
+ docs: {
6
+ description: 'Ensures that imports point to valid exports',
7
+ },
8
+ schema: [],
9
+ fixable: undefined,
10
+ type: 'problem',
11
+ messages: {
12
+ noMissingImports: 'Import does not point to a valid export',
13
+ },
14
+ },
15
+ defaultOptions: [],
16
+ create(context) {
17
+ const esmInfo = getESMInfo(context);
18
+ if (!esmInfo) {
19
+ return {};
20
+ }
21
+ const { fileInfo } = esmInfo;
22
+ if (fileInfo.fileType !== 'code') {
23
+ return {};
24
+ }
25
+ // First check imports
26
+ for (const importEntry of fileInfo.imports) {
27
+ // Barrel/dynamic imports don't resolve to a single export, and can be
28
+ // spread across multiple files even. The specific items being imported
29
+ // isn't specified either, meaning the only way to know if an import is
30
+ // valid is to introspect how it's used at runtime. This isn't tractable,
31
+ // so we just don't validate them instead
32
+ if (importEntry.moduleType !== 'firstPartyCode' ||
33
+ importEntry.importType !== 'single') {
34
+ continue;
35
+ }
36
+ if (importEntry.rootModuleType === undefined) {
37
+ context.report({
38
+ node: importEntry.reportNode,
39
+ messageId: 'noMissingImports',
40
+ });
41
+ }
42
+ }
43
+ // Now check reexports
44
+ for (const reexportEntry of fileInfo.reexports) {
45
+ if (reexportEntry.moduleType !== 'firstPartyCode' ||
46
+ reexportEntry.reexportType !== 'single') {
47
+ continue;
48
+ }
49
+ if (reexportEntry.rootModuleType === undefined) {
50
+ context.report({
51
+ node: reexportEntry.reportNode,
52
+ messageId: 'noMissingImports',
53
+ });
54
+ }
55
+ }
56
+ return {};
57
+ },
58
+ });
59
+ //# sourceMappingURL=missing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"missing.js","sourceRoot":"","sources":["../../../src/rules/missing/missing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAEpD,MAAM,CAAC,MAAM,gBAAgB,GAAG,UAAU,CAAC;IACzC,IAAI,EAAE,oBAAoB;IAC1B,IAAI,EAAE;QACJ,IAAI,EAAE;YACJ,WAAW,EAAE,6CAA6C;SAC3D;QACD,MAAM,EAAE,EAAE;QACV,OAAO,EAAE,SAAS;QAClB,IAAI,EAAE,SAAS;QACf,QAAQ,EAAE;YACR,gBAAgB,EAAE,yCAAyC;SAC5D;KACF;IACD,cAAc,EAAE,EAAE;IAClB,MAAM,CAAC,OAAO;QACZ,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;QACpC,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC;QAC7B,IAAI,QAAQ,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;YACjC,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,sBAAsB;QACtB,KAAK,MAAM,WAAW,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC;YAC3C,sEAAsE;YACtE,uEAAuE;YACvE,uEAAuE;YACvE,yEAAyE;YACzE,yCAAyC;YACzC,IACE,WAAW,CAAC,UAAU,KAAK,gBAAgB;gBAC3C,WAAW,CAAC,UAAU,KAAK,QAAQ,EACnC,CAAC;gBACD,SAAS;YACX,CAAC;YACD,IAAI,WAAW,CAAC,cAAc,KAAK,SAAS,EAAE,CAAC;gBAC7C,OAAO,CAAC,MAAM,CAAC;oBACb,IAAI,EAAE,WAAW,CAAC,UAAU;oBAC5B,SAAS,EAAE,kBAAkB;iBAC9B,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,sBAAsB;QACtB,KAAK,MAAM,aAAa,IAAI,QAAQ,CAAC,SAAS,EAAE,CAAC;YAC/C,IACE,aAAa,CAAC,UAAU,KAAK,gBAAgB;gBAC7C,aAAa,CAAC,YAAY,KAAK,QAAQ,EACvC,CAAC;gBACD,SAAS;YACX,CAAC;YACD,IAAI,aAAa,CAAC,cAAc,KAAK,SAAS,EAAE,CAAC;gBAC/C,OAAO,CAAC,MAAM,CAAC;oBACb,IAAI,EAAE,aAAa,CAAC,UAAU;oBAC9B,SAAS,EAAE,kBAAkB;iBAC9B,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,OAAO,EAAE,CAAC;IACZ,CAAC;CACF,CAAC,CAAC"}
@@ -0,0 +1 @@
1
+ export declare const noTestImportsInProd: import("@typescript-eslint/utils/ts-eslint").RuleModule<"noTestImports", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
@@ -0,0 +1,42 @@
1
+ import { createRule, getESMInfo, isNonTestFile } from '../util.js';
2
+ export const noTestImportsInProd = createRule({
3
+ name: 'no-test-imports-in-prod',
4
+ meta: {
5
+ docs: {
6
+ description: 'Ensures that production code does not import test code',
7
+ },
8
+ schema: [],
9
+ fixable: undefined,
10
+ type: 'problem',
11
+ messages: {
12
+ noTestImports: 'Test code should not be imported in production code',
13
+ },
14
+ },
15
+ defaultOptions: [],
16
+ create(context) {
17
+ const esmInfo = getESMInfo(context);
18
+ if (!esmInfo) {
19
+ return {};
20
+ }
21
+ const { fileInfo } = esmInfo;
22
+ if (fileInfo.fileType !== 'code' ||
23
+ !isNonTestFile(context.filename, esmInfo.projectInfo.rootDir)) {
24
+ return {};
25
+ }
26
+ for (const importEntry of [...fileInfo.imports, ...fileInfo.reexports]) {
27
+ if (importEntry.moduleType !== 'firstPartyCode' &&
28
+ importEntry.moduleType !== 'firstPartyOther') {
29
+ continue;
30
+ }
31
+ if (importEntry.resolvedModulePath &&
32
+ !isNonTestFile(importEntry.resolvedModulePath, esmInfo.projectInfo.rootDir)) {
33
+ context.report({
34
+ node: importEntry.reportNode,
35
+ messageId: 'noTestImports',
36
+ });
37
+ }
38
+ }
39
+ return {};
40
+ },
41
+ });
42
+ //# sourceMappingURL=testInProd.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testInProd.js","sourceRoot":"","sources":["../../../src/rules/testInProd/testInProd.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEnE,MAAM,CAAC,MAAM,mBAAmB,GAAG,UAAU,CAAC;IAC5C,IAAI,EAAE,yBAAyB;IAC/B,IAAI,EAAE;QACJ,IAAI,EAAE;YACJ,WAAW,EAAE,wDAAwD;SACtE;QACD,MAAM,EAAE,EAAE;QACV,OAAO,EAAE,SAAS;QAClB,IAAI,EAAE,SAAS;QACf,QAAQ,EAAE;YACR,aAAa,EAAE,qDAAqD;SACrE;KACF;IACD,cAAc,EAAE,EAAE;IAClB,MAAM,CAAC,OAAO;QACZ,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;QACpC,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC;QAC7B,IACE,QAAQ,CAAC,QAAQ,KAAK,MAAM;YAC5B,CAAC,aAAa,CAAC,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC,EAC7D,CAAC;YACD,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,KAAK,MAAM,WAAW,IAAI,CAAC,GAAG,QAAQ,CAAC,OAAO,EAAE,GAAG,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;YACvE,IACE,WAAW,CAAC,UAAU,KAAK,gBAAgB;gBAC3C,WAAW,CAAC,UAAU,KAAK,iBAAiB,EAC5C,CAAC;gBACD,SAAS;YACX,CAAC;YACD,IACE,WAAW,CAAC,kBAAkB;gBAC9B,CAAC,aAAa,CACZ,WAAW,CAAC,kBAAkB,EAC9B,OAAO,CAAC,WAAW,CAAC,OAAO,CAC5B,EACD,CAAC;gBACD,OAAO,CAAC,MAAM,CAAC;oBACb,IAAI,EAAE,WAAW,CAAC,UAAU;oBAC5B,SAAS,EAAE,eAAe;iBAC3B,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,OAAO,EAAE,CAAC;IACZ,CAAC;CACF,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ export declare const noUnusedExports: import("@typescript-eslint/utils/ts-eslint").RuleModule<"noUnusedExports" | "noTestOnlyImports", [{
2
+ allowNonTestTypeExports: boolean;
3
+ } | undefined], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
@@ -0,0 +1,77 @@
1
+ import { z } from 'zod';
2
+ import { zodToJsonSchema } from 'zod-to-json-schema';
3
+ import { createRule, getESMInfo, isNonTestFile } from '../util.js';
4
+ const schema = z
5
+ .strictObject({
6
+ allowNonTestTypeExports: z.boolean(),
7
+ })
8
+ .optional();
9
+ export const noUnusedExports = createRule({
10
+ name: 'no-unused-exports',
11
+ meta: {
12
+ docs: {
13
+ description: 'Ensures that all exports are imported in another file',
14
+ },
15
+ schema: [zodToJsonSchema(schema)],
16
+ fixable: undefined,
17
+ type: 'problem',
18
+ messages: {
19
+ noUnusedExports: 'Exports must be imported in another file',
20
+ noTestOnlyImports: 'Exports in non-test files must be imported by other non-test files',
21
+ },
22
+ },
23
+ defaultOptions: [
24
+ {
25
+ allowNonTestTypeExports: true,
26
+ },
27
+ ],
28
+ create(context) {
29
+ // .d.ts files are not typically referenced directly, and instead are used
30
+ // to type ambient modules. Sometimes they are used directly though when
31
+ // paired with a neighboring vanilla JS file. Either way, we're making the
32
+ // tradeoff of potentially missing an unused type export for better DX.
33
+ if (context.filename.endsWith('.d.ts')) {
34
+ return {};
35
+ }
36
+ // ESLint isn't applying defaults, so options is length 0 when consumers
37
+ // don't specify options, even though ESLint is supposed to do that. I'm not
38
+ // sure what's going on
39
+ const { allowNonTestTypeExports = true } = context.options[0] ?? {};
40
+ const esmInfo = getESMInfo(context);
41
+ if (!esmInfo) {
42
+ return {};
43
+ }
44
+ const { fileInfo, projectInfo: { rootDir }, } = esmInfo;
45
+ if (fileInfo.fileType !== 'code') {
46
+ return {};
47
+ }
48
+ // Check each export and reexport to make sure it's being used
49
+ for (const exportEntry of [...fileInfo.exports, ...fileInfo.reexports]) {
50
+ // If this is an entry point, then it's being imported externally
51
+ if (exportEntry.isEntryPoint) {
52
+ continue;
53
+ }
54
+ // If imported by is empty, then this isn't used anywhere
55
+ if (exportEntry.importedByFiles.length === 0) {
56
+ context.report({
57
+ messageId: 'noUnusedExports',
58
+ node: exportEntry.reportNode,
59
+ });
60
+ }
61
+ // Otherwise, check to see if all of its imports are only in tests
62
+ else if (isNonTestFile(context.filename, rootDir) &&
63
+ !exportEntry.importedByFiles.some((i) => isNonTestFile(i, rootDir))) {
64
+ if (!(`isTypeExport` in exportEntry) ||
65
+ !exportEntry.isTypeExport ||
66
+ !allowNonTestTypeExports) {
67
+ context.report({
68
+ messageId: 'noTestOnlyImports',
69
+ node: exportEntry.reportNode,
70
+ });
71
+ }
72
+ }
73
+ }
74
+ return {};
75
+ },
76
+ });
77
+ //# sourceMappingURL=unused.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unused.js","sourceRoot":"","sources":["../../../src/rules/unused/unused.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEnE,MAAM,MAAM,GAAG,CAAC;KACb,YAAY,CAAC;IACZ,uBAAuB,EAAE,CAAC,CAAC,OAAO,EAAE;CACrC,CAAC;KACD,QAAQ,EAAE,CAAC;AAId,MAAM,CAAC,MAAM,eAAe,GAAG,UAAU,CAGvC;IACA,IAAI,EAAE,mBAAmB;IACzB,IAAI,EAAE;QACJ,IAAI,EAAE;YACJ,WAAW,EAAE,uDAAuD;SACrE;QACD,MAAM,EAAE,CAAC,eAAe,CAAC,MAAM,CAAgB,CAAC;QAChD,OAAO,EAAE,SAAS;QAClB,IAAI,EAAE,SAAS;QACf,QAAQ,EAAE;YACR,eAAe,EAAE,0CAA0C;YAC3D,iBAAiB,EACf,oEAAoE;SACvE;KACF;IACD,cAAc,EAAE;QACd;YACE,uBAAuB,EAAE,IAAI;SAC9B;KACF;IACD,MAAM,CAAC,OAAO;QACZ,0EAA0E;QAC1E,wEAAwE;QACxE,0EAA0E;QAC1E,uEAAuE;QACvE,IAAI,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;YACvC,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,wEAAwE;QACxE,4EAA4E;QAC5E,uBAAuB;QACvB,MAAM,EAAE,uBAAuB,GAAG,IAAI,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAEpE,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;QACpC,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,EACJ,QAAQ,EACR,WAAW,EAAE,EAAE,OAAO,EAAE,GACzB,GAAG,OAAO,CAAC;QACZ,IAAI,QAAQ,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;YACjC,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,8DAA8D;QAC9D,KAAK,MAAM,WAAW,IAAI,CAAC,GAAG,QAAQ,CAAC,OAAO,EAAE,GAAG,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;YACvE,iEAAiE;YACjE,IAAI,WAAW,CAAC,YAAY,EAAE,CAAC;gBAC7B,SAAS;YACX,CAAC;YAED,yDAAyD;YACzD,IAAI,WAAW,CAAC,eAAe,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC7C,OAAO,CAAC,MAAM,CAAC;oBACb,SAAS,EAAE,iBAAiB;oBAC5B,IAAI,EAAE,WAAW,CAAC,UAAU;iBAC7B,CAAC,CAAC;YACL,CAAC;YAED,kEAAkE;iBAC7D,IACH,aAAa,CAAC,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC;gBACxC,CAAC,WAAW,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,aAAa,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,EACnE,CAAC;gBACD,IACE,CAAC,CAAC,cAAc,IAAI,WAAW,CAAC;oBAChC,CAAC,WAAW,CAAC,YAAY;oBACzB,CAAC,uBAAuB,EACxB,CAAC;oBACD,OAAO,CAAC,MAAM,CAAC;wBACb,SAAS,EAAE,mBAAmB;wBAC9B,IAAI,EAAE,WAAW,CAAC,UAAU;qBAC7B,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,EAAE,CAAC;IACZ,CAAC;CACF,CAAC,CAAC"}
@@ -0,0 +1,11 @@
1
+ import { ESLintUtils } from '@typescript-eslint/utils';
2
+ import type { GenericContext } from '../types/context.js';
3
+ import type { ParsedSettings } from '../settings/settings.js';
4
+ export declare const createRule: <Options extends readonly unknown[], MessageIds extends string>({ meta, name, ...rule }: Readonly<ESLintUtils.RuleWithMetaAndName<Options, MessageIds, unknown>>) => ESLintUtils.RuleModule<MessageIds, Options, unknown, ESLintUtils.RuleListener>;
5
+ export declare function registerUpdateListener(cb: () => void): void;
6
+ export declare function getESMInfo(context: GenericContext): {
7
+ fileInfo: import("../types/base.js").BaseOtherFileDetails | import("../types/analyzed.js").AnalyzedCodeFileDetails;
8
+ projectInfo: import("../types/analyzed.js").AnalyzedProjectInfo;
9
+ settings: ParsedSettings;
10
+ } | undefined;
11
+ export declare function isNonTestFile(filePath: string, rootDir: string): boolean;