eslint-plugin-ai-rules 0.3.0 → 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 +203 -81
- package/dist/index.cjs +129 -83
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -6
- package/dist/index.d.ts +7 -6
- package/dist/index.js +129 -83
- package/dist/index.js.map +1 -1
- package/package.json +20 -11
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;
|
|
@@ -69,14 +70,14 @@ declare function projects(definitions: IProjectDefinition[]): Linter.Config[];
|
|
|
69
70
|
declare const plugin: {
|
|
70
71
|
readonly meta: {
|
|
71
72
|
readonly name: "eslint-plugin-ai-rules";
|
|
72
|
-
readonly version:
|
|
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",
|
|
@@ -1178,15 +1214,15 @@ var frontendRelations = {
|
|
|
1178
1214
|
pageContext: "src/pages/*/contexts",
|
|
1179
1215
|
pageHelper: "src/pages/*/helpers",
|
|
1180
1216
|
page: "src/pages/*",
|
|
1181
|
-
components: "src/components",
|
|
1182
|
-
hooks: "src/hooks",
|
|
1183
|
-
contexts: "src/contexts",
|
|
1184
|
-
generated: "src/services/generated",
|
|
1185
|
-
services: "src/services",
|
|
1186
|
-
utils: "src/utils",
|
|
1187
|
-
helpers: "src/helpers",
|
|
1188
|
-
constants: "src/constants",
|
|
1189
|
-
env: "src/env"
|
|
1217
|
+
components: "src/shared/components",
|
|
1218
|
+
hooks: "src/shared/hooks",
|
|
1219
|
+
contexts: "src/shared/contexts",
|
|
1220
|
+
generated: "src/shared/services/generated",
|
|
1221
|
+
services: "src/shared/services",
|
|
1222
|
+
utils: "src/shared/utils",
|
|
1223
|
+
helpers: "src/shared/helpers",
|
|
1224
|
+
constants: "src/shared/constants",
|
|
1225
|
+
env: "src/shared/env"
|
|
1190
1226
|
},
|
|
1191
1227
|
scope: {
|
|
1192
1228
|
capture: "page",
|
|
@@ -1395,34 +1431,49 @@ var frontendPreset = {
|
|
|
1395
1431
|
"vite-env.d.ts"
|
|
1396
1432
|
],
|
|
1397
1433
|
folders: {
|
|
1398
|
-
|
|
1399
|
-
files: [pascalTsx],
|
|
1434
|
+
shared: {
|
|
1400
1435
|
folders: {
|
|
1401
|
-
|
|
1402
|
-
files: [
|
|
1436
|
+
components: {
|
|
1437
|
+
files: [pascalTsx],
|
|
1438
|
+
folders: {
|
|
1439
|
+
ui: {
|
|
1440
|
+
files: [pascalTsOrTsx]
|
|
1441
|
+
}
|
|
1442
|
+
}
|
|
1443
|
+
},
|
|
1444
|
+
constants: {
|
|
1445
|
+
files: [pascalTs]
|
|
1446
|
+
},
|
|
1447
|
+
contexts: {
|
|
1448
|
+
files: [
|
|
1449
|
+
{
|
|
1450
|
+
case: "PascalCase",
|
|
1451
|
+
extensions: [".tsx"]
|
|
1452
|
+
}
|
|
1453
|
+
]
|
|
1454
|
+
},
|
|
1455
|
+
env: {
|
|
1456
|
+
files: ["index.ts"]
|
|
1457
|
+
},
|
|
1458
|
+
helpers: {
|
|
1459
|
+
files: [pascalTs]
|
|
1460
|
+
},
|
|
1461
|
+
hooks: {
|
|
1462
|
+
files: [pascalTs]
|
|
1463
|
+
},
|
|
1464
|
+
services: {
|
|
1465
|
+
folders: {
|
|
1466
|
+
generated: { ignore: true },
|
|
1467
|
+
utils: {
|
|
1468
|
+
files: [pascalTs]
|
|
1469
|
+
}
|
|
1470
|
+
}
|
|
1471
|
+
},
|
|
1472
|
+
utils: {
|
|
1473
|
+
files: [pascalTs]
|
|
1403
1474
|
}
|
|
1404
1475
|
}
|
|
1405
1476
|
},
|
|
1406
|
-
constants: {
|
|
1407
|
-
files: [pascalTs]
|
|
1408
|
-
},
|
|
1409
|
-
contexts: {
|
|
1410
|
-
files: [
|
|
1411
|
-
{
|
|
1412
|
-
case: "PascalCase",
|
|
1413
|
-
extensions: [".tsx"]
|
|
1414
|
-
}
|
|
1415
|
-
]
|
|
1416
|
-
},
|
|
1417
|
-
env: {
|
|
1418
|
-
files: ["index.ts"]
|
|
1419
|
-
},
|
|
1420
|
-
hooks: {
|
|
1421
|
-
files: [pascalTs]
|
|
1422
|
-
},
|
|
1423
|
-
helpers: {
|
|
1424
|
-
files: [pascalTs]
|
|
1425
|
-
},
|
|
1426
1477
|
pages: {
|
|
1427
1478
|
files: [pascalTsx],
|
|
1428
1479
|
folders: {
|
|
@@ -1485,17 +1536,6 @@ var frontendPreset = {
|
|
|
1485
1536
|
}
|
|
1486
1537
|
}
|
|
1487
1538
|
}
|
|
1488
|
-
},
|
|
1489
|
-
services: {
|
|
1490
|
-
folders: {
|
|
1491
|
-
generated: { ignore: true },
|
|
1492
|
-
utils: {
|
|
1493
|
-
files: [pascalTs]
|
|
1494
|
-
}
|
|
1495
|
-
}
|
|
1496
|
-
},
|
|
1497
|
-
utils: {
|
|
1498
|
-
files: [pascalTs]
|
|
1499
1539
|
}
|
|
1500
1540
|
}
|
|
1501
1541
|
},
|
|
@@ -1533,7 +1573,7 @@ var frontendPreset = {
|
|
|
1533
1573
|
...commonIgnoredPaths,
|
|
1534
1574
|
"playwright-report/**",
|
|
1535
1575
|
"test-results/**",
|
|
1536
|
-
"src/services/generated/**",
|
|
1576
|
+
"src/shared/services/generated/**",
|
|
1537
1577
|
"scripts/types/**"
|
|
1538
1578
|
]
|
|
1539
1579
|
},
|
|
@@ -1830,6 +1870,11 @@ function validateDefinition(definition, index) {
|
|
|
1830
1870
|
});
|
|
1831
1871
|
}
|
|
1832
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
|
+
}
|
|
1833
1878
|
}
|
|
1834
1879
|
function resolveStructure(definition, preset) {
|
|
1835
1880
|
return mergeStructure(preset?.structure, definition.structure);
|
|
@@ -1884,15 +1929,16 @@ function projects(definitions) {
|
|
|
1884
1929
|
]));
|
|
1885
1930
|
const rules = {
|
|
1886
1931
|
...baseConfig.rules,
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
"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",
|
|
1890
1934
|
...relations ? {
|
|
1891
1935
|
"boundaries/dependencies": [
|
|
1892
1936
|
"error",
|
|
1893
1937
|
buildRelationsRuleOptions(relations)
|
|
1894
1938
|
]
|
|
1895
|
-
} : {}
|
|
1939
|
+
} : {},
|
|
1940
|
+
...preset?.rules ?? {},
|
|
1941
|
+
...definition.rules ?? {}
|
|
1896
1942
|
};
|
|
1897
1943
|
return {
|
|
1898
1944
|
...baseConfig,
|