eslint-plugin-ai-rules 0.3.1 → 0.4.0
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.
- package/LICENSE +1 -1
- package/README.md +170 -57
- package/dist/index.cjs +80 -38
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -5
- package/dist/index.d.ts +6 -5
- package/dist/index.js +80 -38
- package/dist/index.js.map +1 -1
- package/package.json +19 -8
package/dist/index.d.ts
CHANGED
|
@@ -45,6 +45,7 @@ interface IProjectDefinition {
|
|
|
45
45
|
preset?: TProjectPreset;
|
|
46
46
|
structure?: IProjectStructure;
|
|
47
47
|
relations?: IRelationsConfig;
|
|
48
|
+
rules?: Linter.RulesRecord;
|
|
48
49
|
}
|
|
49
50
|
interface IProjectPreset {
|
|
50
51
|
structure: IProjectStructure;
|
|
@@ -72,11 +73,11 @@ declare const plugin: {
|
|
|
72
73
|
readonly version: string;
|
|
73
74
|
};
|
|
74
75
|
readonly rules: {
|
|
75
|
-
readonly
|
|
76
|
-
readonly
|
|
77
|
-
readonly
|
|
78
|
-
readonly
|
|
79
|
-
readonly
|
|
76
|
+
readonly "filename-pascal-case": eslint.Rule.RuleModule;
|
|
77
|
+
readonly "no-multiline-imports": eslint.Rule.RuleModule;
|
|
78
|
+
readonly "project-setup": eslint.Rule.RuleModule;
|
|
79
|
+
readonly "project-structure": eslint.Rule.RuleModule;
|
|
80
|
+
readonly "sort-imports": eslint.Rule.RuleModule;
|
|
80
81
|
};
|
|
81
82
|
};
|
|
82
83
|
|
package/dist/index.js
CHANGED
|
@@ -3,22 +3,50 @@ import { createNodeResolver, importX } from "eslint-plugin-import-x";
|
|
|
3
3
|
import stylistic from "@stylistic/eslint-plugin";
|
|
4
4
|
import tseslint from "typescript-eslint";
|
|
5
5
|
|
|
6
|
+
// src/rules/constants.ts
|
|
7
|
+
var RULE_NAMES = {
|
|
8
|
+
filenamePascalCase: "filename-pascal-case",
|
|
9
|
+
noMultilineImports: "no-multiline-imports",
|
|
10
|
+
projectSetup: "project-setup",
|
|
11
|
+
projectStructure: "project-structure",
|
|
12
|
+
sortImports: "sort-imports"
|
|
13
|
+
};
|
|
14
|
+
var RULE_IDS = {
|
|
15
|
+
filenamePascalCase: `ai-rules/${RULE_NAMES.filenamePascalCase}`,
|
|
16
|
+
noMultilineImports: `ai-rules/${RULE_NAMES.noMultilineImports}`,
|
|
17
|
+
projectSetup: `ai-rules/${RULE_NAMES.projectSetup}`,
|
|
18
|
+
projectStructure: `ai-rules/${RULE_NAMES.projectStructure}`,
|
|
19
|
+
sortImports: `ai-rules/${RULE_NAMES.sortImports}`
|
|
20
|
+
};
|
|
21
|
+
|
|
6
22
|
// src/rules/FilenamePascalCase.ts
|
|
7
23
|
import path from "path";
|
|
8
24
|
var filenamePascalCase = {
|
|
9
25
|
meta: {
|
|
10
26
|
type: "suggestion",
|
|
11
|
-
docs: {
|
|
27
|
+
docs: {
|
|
28
|
+
description: "Enforce PascalCase for file names",
|
|
29
|
+
recommended: true,
|
|
30
|
+
url: "https://github.com/lvsouza/eslint-ai-guard/blob/main/README.md#ai-rulesfilename-pascal-case"
|
|
31
|
+
},
|
|
12
32
|
schema: [
|
|
13
33
|
{
|
|
14
34
|
type: "object",
|
|
15
35
|
properties: {
|
|
16
|
-
ignore: {
|
|
17
|
-
|
|
36
|
+
ignore: {
|
|
37
|
+
type: "array",
|
|
38
|
+
items: { type: "string" },
|
|
39
|
+
description: "Regex strings matched against the file name and relative path."
|
|
40
|
+
},
|
|
41
|
+
ignoreMiddleExtensions: {
|
|
42
|
+
type: "boolean",
|
|
43
|
+
description: "Allow middle extensions such as .test in file names."
|
|
44
|
+
}
|
|
18
45
|
},
|
|
19
46
|
additionalProperties: false
|
|
20
47
|
}
|
|
21
48
|
],
|
|
49
|
+
defaultOptions: [{ ignore: [], ignoreMiddleExtensions: true }],
|
|
22
50
|
messages: {
|
|
23
51
|
invalid: 'File name "{{basename}}" must be in PascalCase. Rename to "{{expected}}".'
|
|
24
52
|
}
|
|
@@ -76,10 +104,12 @@ var filenamePascalCase = {
|
|
|
76
104
|
var noMultilineImports = {
|
|
77
105
|
meta: {
|
|
78
106
|
type: "layout",
|
|
79
|
-
fixable: "code",
|
|
80
107
|
docs: {
|
|
81
|
-
description: "Disallow multiline imports"
|
|
108
|
+
description: "Disallow multiline imports",
|
|
109
|
+
recommended: true,
|
|
110
|
+
url: "https://github.com/lvsouza/eslint-ai-guard/blob/main/README.md#ai-rulesno-multiline-imports"
|
|
82
111
|
},
|
|
112
|
+
fixable: "code",
|
|
83
113
|
schema: [],
|
|
84
114
|
messages: {
|
|
85
115
|
multilineImport: "Imports must be written on a single line."
|
|
@@ -341,7 +371,9 @@ var projectStructure = {
|
|
|
341
371
|
meta: {
|
|
342
372
|
type: "problem",
|
|
343
373
|
docs: {
|
|
344
|
-
description: "Enforce the configured project folder and file structure"
|
|
374
|
+
description: "Enforce the configured project folder and file structure",
|
|
375
|
+
recommended: false,
|
|
376
|
+
url: "https://github.com/lvsouza/eslint-ai-guard/blob/main/README.md#ai-rulesproject-structure"
|
|
345
377
|
},
|
|
346
378
|
schema: [],
|
|
347
379
|
messages: {
|
|
@@ -415,7 +447,7 @@ function hasStructureRules(structure) {
|
|
|
415
447
|
}
|
|
416
448
|
|
|
417
449
|
// src/rules/ProjectSetup.ts
|
|
418
|
-
var
|
|
450
|
+
var hasReported = false;
|
|
419
451
|
function isConfiguredProject(project) {
|
|
420
452
|
if (project.relations) return true;
|
|
421
453
|
if (project.preset === "frontend" || project.preset === "backend" || project.preset === "other") {
|
|
@@ -423,36 +455,38 @@ function isConfiguredProject(project) {
|
|
|
423
455
|
}
|
|
424
456
|
return Boolean(project.structure && hasStructureRules(project.structure));
|
|
425
457
|
}
|
|
426
|
-
function
|
|
427
|
-
if (
|
|
458
|
+
function shouldReportOnce() {
|
|
459
|
+
if (hasReported) return false;
|
|
428
460
|
if (process.env.AI_RULES_SILENT === "1" || process.env.AI_RULES_SILENT === "true") {
|
|
429
|
-
return;
|
|
461
|
+
return false;
|
|
430
462
|
}
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
[
|
|
434
|
-
"[eslint-plugin-ai-rules] Project structure validation is not configured.",
|
|
435
|
-
"Configure it with aiRules.configs.projects([{ rootFolder: '.', preset: 'frontend' | 'backend' }]).",
|
|
436
|
-
"If this project is not a frontend/backend, use preset: 'other' to disable this warning."
|
|
437
|
-
].join("\n")
|
|
438
|
-
);
|
|
463
|
+
hasReported = true;
|
|
464
|
+
return true;
|
|
439
465
|
}
|
|
440
466
|
var projectSetup = {
|
|
441
467
|
meta: {
|
|
442
468
|
type: "suggestion",
|
|
443
469
|
docs: {
|
|
444
|
-
description: "
|
|
470
|
+
description: "Require project structure validation to be configured",
|
|
471
|
+
recommended: true,
|
|
472
|
+
url: "https://github.com/lvsouza/eslint-ai-guard/blob/main/README.md#ai-rulesproject-setup"
|
|
445
473
|
},
|
|
446
474
|
schema: [],
|
|
447
|
-
messages: {
|
|
475
|
+
messages: {
|
|
476
|
+
notConfigured: 'Project structure validation is not configured. Configure it with aiRules.configs.projects([{ rootFolder: ".", preset: "frontend" | "backend" }]). If this project is not a frontend/backend, use preset: "other" to disable this warning.'
|
|
477
|
+
}
|
|
448
478
|
},
|
|
449
479
|
create(context) {
|
|
450
480
|
return {
|
|
451
|
-
Program() {
|
|
481
|
+
Program(node) {
|
|
452
482
|
const settings = context.settings["ai-rules"];
|
|
453
483
|
const projects2 = settings?.projects ?? (settings?.project ? [settings.project] : []);
|
|
454
484
|
if (projects2.some(isConfiguredProject)) return;
|
|
455
|
-
|
|
485
|
+
if (!shouldReportOnce()) return;
|
|
486
|
+
context.report({
|
|
487
|
+
node,
|
|
488
|
+
messageId: "notConfigured"
|
|
489
|
+
});
|
|
456
490
|
}
|
|
457
491
|
};
|
|
458
492
|
}
|
|
@@ -463,12 +497,14 @@ var sortImports = {
|
|
|
463
497
|
meta: {
|
|
464
498
|
type: "layout",
|
|
465
499
|
docs: {
|
|
466
|
-
description: "
|
|
500
|
+
description: "Enforce sorted imports by group and line length descending, collapsing multiline imports",
|
|
501
|
+
recommended: true,
|
|
502
|
+
url: "https://github.com/lvsouza/eslint-ai-guard/blob/main/README.md#ai-rulessort-imports"
|
|
467
503
|
},
|
|
468
504
|
fixable: "code",
|
|
469
505
|
schema: [],
|
|
470
506
|
messages: {
|
|
471
|
-
sortRequired: "
|
|
507
|
+
sortRequired: "Imports must be sorted by group and line length, each on a single line."
|
|
472
508
|
}
|
|
473
509
|
},
|
|
474
510
|
create(context) {
|
|
@@ -586,14 +622,14 @@ function getSortedContent(content) {
|
|
|
586
622
|
var plugin = {
|
|
587
623
|
meta: {
|
|
588
624
|
name: "eslint-plugin-ai-rules",
|
|
589
|
-
version: "0.
|
|
625
|
+
version: "0.4.0"
|
|
590
626
|
},
|
|
591
627
|
rules: {
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
628
|
+
[RULE_NAMES.filenamePascalCase]: filenamePascalCase,
|
|
629
|
+
[RULE_NAMES.noMultilineImports]: noMultilineImports,
|
|
630
|
+
[RULE_NAMES.projectSetup]: projectSetup,
|
|
631
|
+
[RULE_NAMES.projectStructure]: projectStructure,
|
|
632
|
+
[RULE_NAMES.sortImports]: sortImports
|
|
597
633
|
}
|
|
598
634
|
};
|
|
599
635
|
|
|
@@ -614,10 +650,10 @@ var recommended = [
|
|
|
614
650
|
]
|
|
615
651
|
},
|
|
616
652
|
rules: {
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
653
|
+
[RULE_IDS.sortImports]: "error",
|
|
654
|
+
[RULE_IDS.noMultilineImports]: "error",
|
|
655
|
+
[RULE_IDS.filenamePascalCase]: "error",
|
|
656
|
+
[RULE_IDS.projectSetup]: "warn",
|
|
621
657
|
"max-len": "off",
|
|
622
658
|
"import-x/no-duplicates": "error",
|
|
623
659
|
"import-x/no-default-export": "off",
|
|
@@ -1834,6 +1870,11 @@ function validateDefinition(definition, index) {
|
|
|
1834
1870
|
});
|
|
1835
1871
|
}
|
|
1836
1872
|
}
|
|
1873
|
+
if (definition.rules !== void 0 && (typeof definition.rules !== "object" || definition.rules === null || Array.isArray(definition.rules))) {
|
|
1874
|
+
throw new Error(
|
|
1875
|
+
`Invalid project at index ${index}: rules must be an object.`
|
|
1876
|
+
);
|
|
1877
|
+
}
|
|
1837
1878
|
}
|
|
1838
1879
|
function resolveStructure(definition, preset) {
|
|
1839
1880
|
return mergeStructure(preset?.structure, definition.structure);
|
|
@@ -1888,15 +1929,16 @@ function projects(definitions) {
|
|
|
1888
1929
|
]));
|
|
1889
1930
|
const rules = {
|
|
1890
1931
|
...baseConfig.rules,
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
"ai-rules/filename-pascal-case": structureEnabled ? "off" : baseConfig.rules?.["ai-rules/filename-pascal-case"] ?? "error",
|
|
1932
|
+
[RULE_IDS.projectStructure]: structureEnabled ? "error" : "off",
|
|
1933
|
+
[RULE_IDS.filenamePascalCase]: structureEnabled ? "off" : baseConfig.rules?.[RULE_IDS.filenamePascalCase] ?? "error",
|
|
1894
1934
|
...relations ? {
|
|
1895
1935
|
"boundaries/dependencies": [
|
|
1896
1936
|
"error",
|
|
1897
1937
|
buildRelationsRuleOptions(relations)
|
|
1898
1938
|
]
|
|
1899
|
-
} : {}
|
|
1939
|
+
} : {},
|
|
1940
|
+
...preset?.rules ?? {},
|
|
1941
|
+
...definition.rules ?? {}
|
|
1900
1942
|
};
|
|
1901
1943
|
return {
|
|
1902
1944
|
...baseConfig,
|