eslint-plugin-intlayer 9.3.1 → 9.3.3

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 (64) hide show
  1. package/README.md +103 -49
  2. package/dist/cjs/@intlayer/config/dist/esm/extract/constants.cjs +18 -0
  3. package/dist/cjs/@intlayer/config/dist/esm/extract/constants.cjs.map +1 -0
  4. package/dist/cjs/@intlayer/config/dist/esm/extract/shouldExtract.cjs +37 -0
  5. package/dist/cjs/@intlayer/config/dist/esm/extract/shouldExtract.cjs.map +1 -0
  6. package/dist/cjs/_virtual/_rolldown/runtime.cjs +28 -0
  7. package/dist/cjs/index.cjs +41 -29
  8. package/dist/cjs/index.cjs.map +1 -1
  9. package/dist/cjs/preset.cjs +53 -0
  10. package/dist/cjs/preset.cjs.map +1 -0
  11. package/dist/cjs/rules/enforceAdapterImport.cjs +9 -2
  12. package/dist/cjs/rules/enforceAdapterImport.cjs.map +1 -1
  13. package/dist/cjs/rules/noRawText.cjs +4 -3
  14. package/dist/cjs/rules/noRawText.cjs.map +1 -1
  15. package/dist/cjs/rules/noUnusedContent.cjs +143 -0
  16. package/dist/cjs/rules/noUnusedContent.cjs.map +1 -0
  17. package/dist/cjs/rules/staticDictionaryKey.cjs +2 -2
  18. package/dist/cjs/rules/staticDictionaryKey.cjs.map +1 -1
  19. package/dist/cjs/utils/contentDeclaration.cjs +100 -0
  20. package/dist/cjs/utils/contentDeclaration.cjs.map +1 -0
  21. package/dist/cjs/utils/projectUsage.cjs +437 -0
  22. package/dist/cjs/utils/projectUsage.cjs.map +1 -0
  23. package/dist/cjs/utils/reactVersion.cjs +50 -0
  24. package/dist/cjs/utils/reactVersion.cjs.map +1 -0
  25. package/dist/esm/@intlayer/config/dist/esm/extract/constants.mjs +18 -0
  26. package/dist/esm/@intlayer/config/dist/esm/extract/constants.mjs.map +1 -0
  27. package/dist/esm/@intlayer/config/dist/esm/extract/shouldExtract.mjs +37 -0
  28. package/dist/esm/@intlayer/config/dist/esm/extract/shouldExtract.mjs.map +1 -0
  29. package/dist/esm/_virtual/_rolldown/runtime.mjs +8 -0
  30. package/dist/esm/index.mjs +36 -30
  31. package/dist/esm/index.mjs.map +1 -1
  32. package/dist/esm/preset.mjs +48 -0
  33. package/dist/esm/preset.mjs.map +1 -0
  34. package/dist/esm/rules/enforceAdapterImport.mjs +10 -3
  35. package/dist/esm/rules/enforceAdapterImport.mjs.map +1 -1
  36. package/dist/esm/rules/noRawText.mjs +2 -1
  37. package/dist/esm/rules/noRawText.mjs.map +1 -1
  38. package/dist/esm/rules/noUnusedContent.mjs +142 -0
  39. package/dist/esm/rules/noUnusedContent.mjs.map +1 -0
  40. package/dist/esm/rules/staticDictionaryKey.mjs +2 -2
  41. package/dist/esm/rules/staticDictionaryKey.mjs.map +1 -1
  42. package/dist/esm/utils/contentDeclaration.mjs +99 -0
  43. package/dist/esm/utils/contentDeclaration.mjs.map +1 -0
  44. package/dist/esm/utils/projectUsage.mjs +433 -0
  45. package/dist/esm/utils/projectUsage.mjs.map +1 -0
  46. package/dist/esm/utils/reactVersion.mjs +46 -0
  47. package/dist/esm/utils/reactVersion.mjs.map +1 -0
  48. package/dist/types/index.d.ts +19 -6
  49. package/dist/types/index.d.ts.map +1 -1
  50. package/dist/types/node_modules/.bun/@types_estree@1.0.9/node_modules/@types/estree/index.d.ts +528 -0
  51. package/dist/types/node_modules/.bun/@types_estree@1.0.9/node_modules/@types/estree/index.d.ts.map +1 -0
  52. package/dist/types/preset.d.ts +45 -0
  53. package/dist/types/preset.d.ts.map +1 -0
  54. package/dist/types/rules/enforceAdapterImport.d.ts.map +1 -1
  55. package/dist/types/rules/noUnusedContent.d.ts +33 -0
  56. package/dist/types/rules/noUnusedContent.d.ts.map +1 -0
  57. package/dist/types/utils/ast.d.ts +1 -1
  58. package/dist/types/utils/contentDeclaration.d.ts +42 -0
  59. package/dist/types/utils/contentDeclaration.d.ts.map +1 -0
  60. package/dist/types/utils/projectUsage.d.ts +102 -0
  61. package/dist/types/utils/projectUsage.d.ts.map +1 -0
  62. package/dist/types/utils/reactVersion.d.ts +18 -0
  63. package/dist/types/utils/reactVersion.d.ts.map +1 -0
  64. package/package.json +5 -3
@@ -0,0 +1,33 @@
1
+ import { IntlayerRule } from "../utils/createRule.js";
2
+ //#region src/rules/noUnusedContent.d.ts
3
+ type NoUnusedContentOptions = {
4
+ /** Report a dictionary whose key is never referenced anywhere. Default: `true`. */
5
+ reportUnusedDictionaries?: boolean;
6
+ /** Report a content field that is never read anywhere. Default: `true`. */
7
+ reportUnusedFields?: boolean;
8
+ /**
9
+ * Report a dictionary key that is also declared elsewhere. Needs the unmerged
10
+ * dictionaries on disk, so it stays silent until the project has been built.
11
+ * Default: `true`.
12
+ */
13
+ reportDuplicateKeys?: boolean;
14
+ /** Regular-expression sources for field paths that are never reported. */
15
+ ignoreFields?: string[];
16
+ /**
17
+ * Project root the scan starts from. Defaults to ESLint's working directory,
18
+ * which is the right answer unless one lint run spans several Intlayer
19
+ * projects in a monorepo.
20
+ */
21
+ baseDir?: string;
22
+ /**
23
+ * How long one project scan is reused, in milliseconds. Lower it when linting
24
+ * from a long-lived editor server and you want edits reflected sooner; `0`
25
+ * rescans on every file. Default: `30000`.
26
+ */
27
+ cacheTtl?: number;
28
+ };
29
+ type MessageIds = 'unusedDictionary' | 'unusedField' | 'duplicateDictionary';
30
+ declare const noUnusedContent: IntlayerRule<[NoUnusedContentOptions?], MessageIds>;
31
+ //#endregion
32
+ export { NoUnusedContentOptions, noUnusedContent };
33
+ //# sourceMappingURL=noUnusedContent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"noUnusedContent.d.ts","names":[],"sources":["../../../src/rules/noUnusedContent.ts"],"mappings":";;KAmBY;;EAEV;;EAEA;;;;;;EAMA;;EAEA;;;;;;EAMA;;;;;;EAMA;;KAGG;cAsDQ,iBAAe,cAAA,0BAAA"}
@@ -1,4 +1,4 @@
1
- import { Node } from "/Users/aymericpineau/Documents/intlayer_/node_modules/.bun/@types+estree@1.0.9/node_modules/@types/estree/index.js";
1
+ import { Node } from "../node_modules/.bun/@types_estree@1.0.9/node_modules/@types/estree/index.js";
2
2
  //#region src/utils/ast.d.ts
3
3
  /**
4
4
  * Minimal structural models for the nodes this plugin inspects that are not
@@ -0,0 +1,42 @@
1
+ import { AstNode } from "./ast.js";
2
+ //#region src/utils/contentDeclaration.d.ts
3
+ /**
4
+ * Reading an Intlayer content declaration out of the file being linted.
5
+ *
6
+ * A declaration is any object literal carrying both a `key` and a `content`
7
+ * property — the same shape the VS Code extension looks for, which covers
8
+ * `export default { … }`, `const dictionary = { … } satisfies Dictionary` and
9
+ * every variant in between without caring how the object reaches the export.
10
+ */
11
+ /** One field declared inside a dictionary's `content`. */
12
+ type DeclaredField = {
13
+ /** Dotted path from the content root, e.g. `hero.title`. */
14
+ path: string;
15
+ /** The property key node, so a report points at the field name. */
16
+ keyNode: AstNode;
17
+ };
18
+ /** A dictionary declaration found in the linted file. */
19
+ type ContentDeclaration = {
20
+ /** The static dictionary key. */
21
+ dictionaryKey: string;
22
+ /** The node holding the key, for reporting a fully unused dictionary. */
23
+ keyNode: AstNode;
24
+ /** Every field declared under `content`, depth-first. */
25
+ fields: DeclaredField[];
26
+ /**
27
+ * True when the content object holds a spread or a computed key, so the field
28
+ * list is not exhaustive. No field may be reported unused in that case — the
29
+ * missing entries could be exactly the ones being read.
30
+ */
31
+ isPartiallyEnumerated: boolean;
32
+ };
33
+ /**
34
+ * Read the dictionary declaration an object literal represents, or `null` when
35
+ * it is not one.
36
+ *
37
+ * @param objectExpression - Any `ObjectExpression` node from the linted file.
38
+ */
39
+ declare const readContentDeclaration: (objectExpression: AstNode) => ContentDeclaration | null;
40
+ //#endregion
41
+ export { ContentDeclaration, DeclaredField, readContentDeclaration };
42
+ //# sourceMappingURL=contentDeclaration.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contentDeclaration.d.ts","names":[],"sources":["../../../src/utils/contentDeclaration.ts"],"mappings":";;;;;;;;;;;KAaY;;EAEV;;EAEA,SAAS;;;KAIC;;EAEV;;EAEA,SAAS;;EAET,QAAQ;;;;;;EAMR;;;;;;;;cA+GW,yBACX,kBAAkB,YACjB"}
@@ -0,0 +1,102 @@
1
+ //#region src/utils/projectUsage.d.ts
2
+ /**
3
+ * The configuration fields the scan reads.
4
+ *
5
+ * Declared structurally rather than imported from `@intlayer/types` so the
6
+ * plugin keeps its single runtime dependency, and so the exact surface this
7
+ * rule depends on stays visible in one place.
8
+ */
9
+ type IntlayerProjectConfig = {
10
+ content: {
11
+ fileExtensions?: string[];
12
+ codeDir?: string[];
13
+ };
14
+ build: {
15
+ traversePattern?: string[];
16
+ };
17
+ compiler?: {
18
+ transformPattern?: string | string[];
19
+ };
20
+ system: {
21
+ baseDir: string;
22
+ unmergedDictionariesDir: string;
23
+ };
24
+ };
25
+ /** How one dictionary key is consumed across the project. */
26
+ type DictionaryUsage = {
27
+ /**
28
+ * Dotted content-field paths read somewhere, every parent prefix included —
29
+ * reading `hero.title` marks `hero` used too.
30
+ */
31
+ usedFieldPaths: Set<string>;
32
+ /**
33
+ * True when at least one reference consumes the dictionary in a way field
34
+ * tracking cannot follow: the content object escapes as a whole, a translator
35
+ * function is bound, or the referencing file could not be parsed. No field of
36
+ * the dictionary may be reported unused once this is set.
37
+ */
38
+ tracksEveryField: boolean;
39
+ };
40
+ /** The result of one project scan. */
41
+ type ProjectUsageIndex = {
42
+ /** Every dictionary key referenced by the project, and how. */
43
+ byDictionaryKey: Map<string, DictionaryUsage>;
44
+ /**
45
+ * Extension-less absolute paths of modules imported by the scanned files. A
46
+ * content declaration reached through a direct import (`useDictionary(myDict)`)
47
+ * carries no key at the call site, so importing it at all counts as a use.
48
+ */
49
+ importedModulePaths: Set<string>;
50
+ /**
51
+ * False when the project could not be scanned — no config, no analyser, or no
52
+ * matching source file. Every report is suppressed in that case rather than
53
+ * flagging a whole project as unused.
54
+ */
55
+ isAvailable: boolean;
56
+ };
57
+ /** One other place a dictionary key is declared. */
58
+ type DuplicateDeclaration = {
59
+ /** Path as recorded in the unmerged dictionary, or `'remote'` for CMS entries. */
60
+ filePath: string;
61
+ /** Whether the other declaration lives in the project or in the CMS. */
62
+ location: 'local' | 'remote';
63
+ };
64
+ /**
65
+ * Drop the module extension from a path so `./home.content` and
66
+ * `/project/src/home.content.ts` compare equal.
67
+ *
68
+ * @param filePath - Absolute or relative path.
69
+ */
70
+ declare const stripModuleExtension: (filePath: string) => string;
71
+ /** Drop every cached configuration and usage index. Exposed for tests. */
72
+ declare const clearProjectUsageCache: () => void;
73
+ /**
74
+ * Load the Intlayer configuration for a project, or `null` when it cannot be
75
+ * read — a project without Intlayer installed must not break the lint run.
76
+ *
77
+ * @param baseDir - Project root, normally ESLint's working directory.
78
+ * @param cacheTtlMs - Lifetime of the cached configuration.
79
+ */
80
+ declare const getProjectConfiguration: (baseDir: string, cacheTtlMs: number) => IntlayerProjectConfig | null;
81
+ /**
82
+ * Scan the project once and aggregate every dictionary reference it contains.
83
+ *
84
+ * @param baseDir - Project root, normally ESLint's working directory.
85
+ * @param cacheTtlMs - Lifetime of the cached index.
86
+ */
87
+ declare const getProjectUsageIndex: (baseDir: string, cacheTtlMs: number) => ProjectUsageIndex;
88
+ /**
89
+ * Other declarations of the same dictionary key, read from the unmerged
90
+ * dictionaries the build writes to disk.
91
+ *
92
+ * Returns an empty list when the build output is missing — the rule then simply
93
+ * has nothing to say about duplicates.
94
+ *
95
+ * @param configuration - The project configuration.
96
+ * @param dictionaryKey - Key declared by the linted file.
97
+ * @param currentFilePath - Absolute path of the linted file.
98
+ */
99
+ declare const getDuplicateDeclarations: (configuration: IntlayerProjectConfig, dictionaryKey: string, currentFilePath: string) => DuplicateDeclaration[];
100
+ //#endregion
101
+ export { DictionaryUsage, DuplicateDeclaration, IntlayerProjectConfig, ProjectUsageIndex, clearProjectUsageCache, getDuplicateDeclarations, getProjectConfiguration, getProjectUsageIndex, stripModuleExtension };
102
+ //# sourceMappingURL=projectUsage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projectUsage.d.ts","names":[],"sources":["../../../src/utils/projectUsage.ts"],"mappings":";;;;;;;;KAiGY;EACV;IAAW;IAA2B;;EACtC;IAAS;;EACT;IAAa;;EACb;IAAU;IAAiB;;;;KAMjB;;;;;EAKV,gBAAgB;;;;;;;EAOhB;;;KAIU;;EAEV,iBAAiB,YAAY;;;;;;EAM7B,qBAAqB;;;;;;EAMrB;;;KAIU;;EAEV;;EAEA;;;;;;;;cA4CW,uBAAwB;;cA+FxB;;;;;;;;cAcA,0BACX,iBACA,uBACC;;;;;;;cAqUU,uBACX,iBACA,uBACC;;;;;;;;;;;;cA6HU,2BACX,eAAe,uBACf,uBACA,4BACC"}
@@ -0,0 +1,18 @@
1
+ //#region src/utils/reactVersion.d.ts
2
+ /**
3
+ * Detect the installed React version for ESLint configuration.
4
+ *
5
+ * `eslint-plugin-react` versions <= 7.37.5 rely on `context.getFilename()` to detect
6
+ * the React version when `settings.react.version` is set to `"detect"`.
7
+ * Because ESLint 10 removed `context.getFilename()`, every `react/*` rule throws on load
8
+ * when `settings.react.version` is `"detect"`.
9
+ *
10
+ * Specifying an explicit detected React version in `settings.react.version`
11
+ * bypasses the broken `detectReactVersion` codepath in `eslint-plugin-react`, allowing
12
+ * Next.js and React projects using `eslint-config-next` / `eslint-plugin-react` to work
13
+ * seamlessly under both ESLint 9 and ESLint 10 without needing manual configuration hacks.
14
+ */
15
+ declare const getReactVersion: (dir?: string) => string;
16
+ //#endregion
17
+ export { getReactVersion };
18
+ //# sourceMappingURL=reactVersion.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reactVersion.d.ts","names":[],"sources":["../../../src/utils/reactVersion.ts"],"mappings":";;;;;;;;;;;;;;cAgBa,kBAAmB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-intlayer",
3
- "version": "9.3.1",
3
+ "version": "9.3.3",
4
4
  "private": false,
5
5
  "description": "ESLint (and oxlint) plugin for Intlayer. Catches untranslated strings and the dynamic call shapes the Intlayer compiler cannot optimize.",
6
6
  "keywords": [
@@ -76,7 +76,9 @@
76
76
  "typecheck": "tsc --noEmit --project tsconfig.types.json"
77
77
  },
78
78
  "dependencies": {
79
- "@intlayer/config": "9.3.1"
79
+ "@intlayer/config": "9.3.3",
80
+ "@intlayer/lsp": "9.3.3",
81
+ "fast-glob": "3.3.3"
80
82
  },
81
83
  "devDependencies": {
82
84
  "@angular-eslint/template-parser": "22.1.0",
@@ -93,7 +95,7 @@
93
95
  "tsdown": "0.22.14",
94
96
  "typescript": "6.0.3",
95
97
  "typescript-eslint": "8.67.0",
96
- "vitest": "4.1.10",
98
+ "vitest": "4.1.11",
97
99
  "vue-eslint-parser": "10.4.1"
98
100
  },
99
101
  "peerDependencies": {