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.cjs
CHANGED
|
@@ -49,22 +49,50 @@ var import_eslint_plugin_import_x = require("eslint-plugin-import-x");
|
|
|
49
49
|
var import_eslint_plugin = __toESM(require("@stylistic/eslint-plugin"), 1);
|
|
50
50
|
var import_typescript_eslint = __toESM(require("typescript-eslint"), 1);
|
|
51
51
|
|
|
52
|
+
// src/rules/constants.ts
|
|
53
|
+
var RULE_NAMES = {
|
|
54
|
+
filenamePascalCase: "filename-pascal-case",
|
|
55
|
+
noMultilineImports: "no-multiline-imports",
|
|
56
|
+
projectSetup: "project-setup",
|
|
57
|
+
projectStructure: "project-structure",
|
|
58
|
+
sortImports: "sort-imports"
|
|
59
|
+
};
|
|
60
|
+
var RULE_IDS = {
|
|
61
|
+
filenamePascalCase: `ai-rules/${RULE_NAMES.filenamePascalCase}`,
|
|
62
|
+
noMultilineImports: `ai-rules/${RULE_NAMES.noMultilineImports}`,
|
|
63
|
+
projectSetup: `ai-rules/${RULE_NAMES.projectSetup}`,
|
|
64
|
+
projectStructure: `ai-rules/${RULE_NAMES.projectStructure}`,
|
|
65
|
+
sortImports: `ai-rules/${RULE_NAMES.sortImports}`
|
|
66
|
+
};
|
|
67
|
+
|
|
52
68
|
// src/rules/FilenamePascalCase.ts
|
|
53
69
|
var import_node_path = __toESM(require("path"), 1);
|
|
54
70
|
var filenamePascalCase = {
|
|
55
71
|
meta: {
|
|
56
72
|
type: "suggestion",
|
|
57
|
-
docs: {
|
|
73
|
+
docs: {
|
|
74
|
+
description: "Enforce PascalCase for file names",
|
|
75
|
+
recommended: true,
|
|
76
|
+
url: "https://github.com/lvsouza/eslint-ai-guard/blob/main/README.md#ai-rulesfilename-pascal-case"
|
|
77
|
+
},
|
|
58
78
|
schema: [
|
|
59
79
|
{
|
|
60
80
|
type: "object",
|
|
61
81
|
properties: {
|
|
62
|
-
ignore: {
|
|
63
|
-
|
|
82
|
+
ignore: {
|
|
83
|
+
type: "array",
|
|
84
|
+
items: { type: "string" },
|
|
85
|
+
description: "Regex strings matched against the file name and relative path."
|
|
86
|
+
},
|
|
87
|
+
ignoreMiddleExtensions: {
|
|
88
|
+
type: "boolean",
|
|
89
|
+
description: "Allow middle extensions such as .test in file names."
|
|
90
|
+
}
|
|
64
91
|
},
|
|
65
92
|
additionalProperties: false
|
|
66
93
|
}
|
|
67
94
|
],
|
|
95
|
+
defaultOptions: [{ ignore: [], ignoreMiddleExtensions: true }],
|
|
68
96
|
messages: {
|
|
69
97
|
invalid: 'File name "{{basename}}" must be in PascalCase. Rename to "{{expected}}".'
|
|
70
98
|
}
|
|
@@ -122,10 +150,12 @@ var filenamePascalCase = {
|
|
|
122
150
|
var noMultilineImports = {
|
|
123
151
|
meta: {
|
|
124
152
|
type: "layout",
|
|
125
|
-
fixable: "code",
|
|
126
153
|
docs: {
|
|
127
|
-
description: "Disallow multiline imports"
|
|
154
|
+
description: "Disallow multiline imports",
|
|
155
|
+
recommended: true,
|
|
156
|
+
url: "https://github.com/lvsouza/eslint-ai-guard/blob/main/README.md#ai-rulesno-multiline-imports"
|
|
128
157
|
},
|
|
158
|
+
fixable: "code",
|
|
129
159
|
schema: [],
|
|
130
160
|
messages: {
|
|
131
161
|
multilineImport: "Imports must be written on a single line."
|
|
@@ -387,7 +417,9 @@ var projectStructure = {
|
|
|
387
417
|
meta: {
|
|
388
418
|
type: "problem",
|
|
389
419
|
docs: {
|
|
390
|
-
description: "Enforce the configured project folder and file structure"
|
|
420
|
+
description: "Enforce the configured project folder and file structure",
|
|
421
|
+
recommended: false,
|
|
422
|
+
url: "https://github.com/lvsouza/eslint-ai-guard/blob/main/README.md#ai-rulesproject-structure"
|
|
391
423
|
},
|
|
392
424
|
schema: [],
|
|
393
425
|
messages: {
|
|
@@ -461,7 +493,7 @@ function hasStructureRules(structure) {
|
|
|
461
493
|
}
|
|
462
494
|
|
|
463
495
|
// src/rules/ProjectSetup.ts
|
|
464
|
-
var
|
|
496
|
+
var hasReported = false;
|
|
465
497
|
function isConfiguredProject(project) {
|
|
466
498
|
if (project.relations) return true;
|
|
467
499
|
if (project.preset === "frontend" || project.preset === "backend" || project.preset === "other") {
|
|
@@ -469,36 +501,38 @@ function isConfiguredProject(project) {
|
|
|
469
501
|
}
|
|
470
502
|
return Boolean(project.structure && hasStructureRules(project.structure));
|
|
471
503
|
}
|
|
472
|
-
function
|
|
473
|
-
if (
|
|
504
|
+
function shouldReportOnce() {
|
|
505
|
+
if (hasReported) return false;
|
|
474
506
|
if (process.env.AI_RULES_SILENT === "1" || process.env.AI_RULES_SILENT === "true") {
|
|
475
|
-
return;
|
|
507
|
+
return false;
|
|
476
508
|
}
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
[
|
|
480
|
-
"[eslint-plugin-ai-rules] Project structure validation is not configured.",
|
|
481
|
-
"Configure it with aiRules.configs.projects([{ rootFolder: '.', preset: 'frontend' | 'backend' }]).",
|
|
482
|
-
"If this project is not a frontend/backend, use preset: 'other' to disable this warning."
|
|
483
|
-
].join("\n")
|
|
484
|
-
);
|
|
509
|
+
hasReported = true;
|
|
510
|
+
return true;
|
|
485
511
|
}
|
|
486
512
|
var projectSetup = {
|
|
487
513
|
meta: {
|
|
488
514
|
type: "suggestion",
|
|
489
515
|
docs: {
|
|
490
|
-
description: "
|
|
516
|
+
description: "Require project structure validation to be configured",
|
|
517
|
+
recommended: true,
|
|
518
|
+
url: "https://github.com/lvsouza/eslint-ai-guard/blob/main/README.md#ai-rulesproject-setup"
|
|
491
519
|
},
|
|
492
520
|
schema: [],
|
|
493
|
-
messages: {
|
|
521
|
+
messages: {
|
|
522
|
+
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.'
|
|
523
|
+
}
|
|
494
524
|
},
|
|
495
525
|
create(context) {
|
|
496
526
|
return {
|
|
497
|
-
Program() {
|
|
527
|
+
Program(node) {
|
|
498
528
|
const settings = context.settings["ai-rules"];
|
|
499
529
|
const projects2 = settings?.projects ?? (settings?.project ? [settings.project] : []);
|
|
500
530
|
if (projects2.some(isConfiguredProject)) return;
|
|
501
|
-
|
|
531
|
+
if (!shouldReportOnce()) return;
|
|
532
|
+
context.report({
|
|
533
|
+
node,
|
|
534
|
+
messageId: "notConfigured"
|
|
535
|
+
});
|
|
502
536
|
}
|
|
503
537
|
};
|
|
504
538
|
}
|
|
@@ -509,12 +543,14 @@ var sortImports = {
|
|
|
509
543
|
meta: {
|
|
510
544
|
type: "layout",
|
|
511
545
|
docs: {
|
|
512
|
-
description: "
|
|
546
|
+
description: "Enforce sorted imports by group and line length descending, collapsing multiline imports",
|
|
547
|
+
recommended: true,
|
|
548
|
+
url: "https://github.com/lvsouza/eslint-ai-guard/blob/main/README.md#ai-rulessort-imports"
|
|
513
549
|
},
|
|
514
550
|
fixable: "code",
|
|
515
551
|
schema: [],
|
|
516
552
|
messages: {
|
|
517
|
-
sortRequired: "
|
|
553
|
+
sortRequired: "Imports must be sorted by group and line length, each on a single line."
|
|
518
554
|
}
|
|
519
555
|
},
|
|
520
556
|
create(context) {
|
|
@@ -632,14 +668,14 @@ function getSortedContent(content) {
|
|
|
632
668
|
var plugin = {
|
|
633
669
|
meta: {
|
|
634
670
|
name: "eslint-plugin-ai-rules",
|
|
635
|
-
version: "0.
|
|
671
|
+
version: "0.4.0"
|
|
636
672
|
},
|
|
637
673
|
rules: {
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
674
|
+
[RULE_NAMES.filenamePascalCase]: filenamePascalCase,
|
|
675
|
+
[RULE_NAMES.noMultilineImports]: noMultilineImports,
|
|
676
|
+
[RULE_NAMES.projectSetup]: projectSetup,
|
|
677
|
+
[RULE_NAMES.projectStructure]: projectStructure,
|
|
678
|
+
[RULE_NAMES.sortImports]: sortImports
|
|
643
679
|
}
|
|
644
680
|
};
|
|
645
681
|
|
|
@@ -660,10 +696,10 @@ var recommended = [
|
|
|
660
696
|
]
|
|
661
697
|
},
|
|
662
698
|
rules: {
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
699
|
+
[RULE_IDS.sortImports]: "error",
|
|
700
|
+
[RULE_IDS.noMultilineImports]: "error",
|
|
701
|
+
[RULE_IDS.filenamePascalCase]: "error",
|
|
702
|
+
[RULE_IDS.projectSetup]: "warn",
|
|
667
703
|
"max-len": "off",
|
|
668
704
|
"import-x/no-duplicates": "error",
|
|
669
705
|
"import-x/no-default-export": "off",
|
|
@@ -1224,15 +1260,15 @@ var frontendRelations = {
|
|
|
1224
1260
|
pageContext: "src/pages/*/contexts",
|
|
1225
1261
|
pageHelper: "src/pages/*/helpers",
|
|
1226
1262
|
page: "src/pages/*",
|
|
1227
|
-
components: "src/components",
|
|
1228
|
-
hooks: "src/hooks",
|
|
1229
|
-
contexts: "src/contexts",
|
|
1230
|
-
generated: "src/services/generated",
|
|
1231
|
-
services: "src/services",
|
|
1232
|
-
utils: "src/utils",
|
|
1233
|
-
helpers: "src/helpers",
|
|
1234
|
-
constants: "src/constants",
|
|
1235
|
-
env: "src/env"
|
|
1263
|
+
components: "src/shared/components",
|
|
1264
|
+
hooks: "src/shared/hooks",
|
|
1265
|
+
contexts: "src/shared/contexts",
|
|
1266
|
+
generated: "src/shared/services/generated",
|
|
1267
|
+
services: "src/shared/services",
|
|
1268
|
+
utils: "src/shared/utils",
|
|
1269
|
+
helpers: "src/shared/helpers",
|
|
1270
|
+
constants: "src/shared/constants",
|
|
1271
|
+
env: "src/shared/env"
|
|
1236
1272
|
},
|
|
1237
1273
|
scope: {
|
|
1238
1274
|
capture: "page",
|
|
@@ -1441,34 +1477,49 @@ var frontendPreset = {
|
|
|
1441
1477
|
"vite-env.d.ts"
|
|
1442
1478
|
],
|
|
1443
1479
|
folders: {
|
|
1444
|
-
|
|
1445
|
-
files: [pascalTsx],
|
|
1480
|
+
shared: {
|
|
1446
1481
|
folders: {
|
|
1447
|
-
|
|
1448
|
-
files: [
|
|
1482
|
+
components: {
|
|
1483
|
+
files: [pascalTsx],
|
|
1484
|
+
folders: {
|
|
1485
|
+
ui: {
|
|
1486
|
+
files: [pascalTsOrTsx]
|
|
1487
|
+
}
|
|
1488
|
+
}
|
|
1489
|
+
},
|
|
1490
|
+
constants: {
|
|
1491
|
+
files: [pascalTs]
|
|
1492
|
+
},
|
|
1493
|
+
contexts: {
|
|
1494
|
+
files: [
|
|
1495
|
+
{
|
|
1496
|
+
case: "PascalCase",
|
|
1497
|
+
extensions: [".tsx"]
|
|
1498
|
+
}
|
|
1499
|
+
]
|
|
1500
|
+
},
|
|
1501
|
+
env: {
|
|
1502
|
+
files: ["index.ts"]
|
|
1503
|
+
},
|
|
1504
|
+
helpers: {
|
|
1505
|
+
files: [pascalTs]
|
|
1506
|
+
},
|
|
1507
|
+
hooks: {
|
|
1508
|
+
files: [pascalTs]
|
|
1509
|
+
},
|
|
1510
|
+
services: {
|
|
1511
|
+
folders: {
|
|
1512
|
+
generated: { ignore: true },
|
|
1513
|
+
utils: {
|
|
1514
|
+
files: [pascalTs]
|
|
1515
|
+
}
|
|
1516
|
+
}
|
|
1517
|
+
},
|
|
1518
|
+
utils: {
|
|
1519
|
+
files: [pascalTs]
|
|
1449
1520
|
}
|
|
1450
1521
|
}
|
|
1451
1522
|
},
|
|
1452
|
-
constants: {
|
|
1453
|
-
files: [pascalTs]
|
|
1454
|
-
},
|
|
1455
|
-
contexts: {
|
|
1456
|
-
files: [
|
|
1457
|
-
{
|
|
1458
|
-
case: "PascalCase",
|
|
1459
|
-
extensions: [".tsx"]
|
|
1460
|
-
}
|
|
1461
|
-
]
|
|
1462
|
-
},
|
|
1463
|
-
env: {
|
|
1464
|
-
files: ["index.ts"]
|
|
1465
|
-
},
|
|
1466
|
-
hooks: {
|
|
1467
|
-
files: [pascalTs]
|
|
1468
|
-
},
|
|
1469
|
-
helpers: {
|
|
1470
|
-
files: [pascalTs]
|
|
1471
|
-
},
|
|
1472
1523
|
pages: {
|
|
1473
1524
|
files: [pascalTsx],
|
|
1474
1525
|
folders: {
|
|
@@ -1531,17 +1582,6 @@ var frontendPreset = {
|
|
|
1531
1582
|
}
|
|
1532
1583
|
}
|
|
1533
1584
|
}
|
|
1534
|
-
},
|
|
1535
|
-
services: {
|
|
1536
|
-
folders: {
|
|
1537
|
-
generated: { ignore: true },
|
|
1538
|
-
utils: {
|
|
1539
|
-
files: [pascalTs]
|
|
1540
|
-
}
|
|
1541
|
-
}
|
|
1542
|
-
},
|
|
1543
|
-
utils: {
|
|
1544
|
-
files: [pascalTs]
|
|
1545
1585
|
}
|
|
1546
1586
|
}
|
|
1547
1587
|
},
|
|
@@ -1579,7 +1619,7 @@ var frontendPreset = {
|
|
|
1579
1619
|
...commonIgnoredPaths,
|
|
1580
1620
|
"playwright-report/**",
|
|
1581
1621
|
"test-results/**",
|
|
1582
|
-
"src/services/generated/**",
|
|
1622
|
+
"src/shared/services/generated/**",
|
|
1583
1623
|
"scripts/types/**"
|
|
1584
1624
|
]
|
|
1585
1625
|
},
|
|
@@ -1876,6 +1916,11 @@ function validateDefinition(definition, index) {
|
|
|
1876
1916
|
});
|
|
1877
1917
|
}
|
|
1878
1918
|
}
|
|
1919
|
+
if (definition.rules !== void 0 && (typeof definition.rules !== "object" || definition.rules === null || Array.isArray(definition.rules))) {
|
|
1920
|
+
throw new Error(
|
|
1921
|
+
`Invalid project at index ${index}: rules must be an object.`
|
|
1922
|
+
);
|
|
1923
|
+
}
|
|
1879
1924
|
}
|
|
1880
1925
|
function resolveStructure(definition, preset) {
|
|
1881
1926
|
return mergeStructure(preset?.structure, definition.structure);
|
|
@@ -1930,15 +1975,16 @@ function projects(definitions) {
|
|
|
1930
1975
|
]));
|
|
1931
1976
|
const rules = {
|
|
1932
1977
|
...baseConfig.rules,
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
"ai-rules/filename-pascal-case": structureEnabled ? "off" : baseConfig.rules?.["ai-rules/filename-pascal-case"] ?? "error",
|
|
1978
|
+
[RULE_IDS.projectStructure]: structureEnabled ? "error" : "off",
|
|
1979
|
+
[RULE_IDS.filenamePascalCase]: structureEnabled ? "off" : baseConfig.rules?.[RULE_IDS.filenamePascalCase] ?? "error",
|
|
1936
1980
|
...relations ? {
|
|
1937
1981
|
"boundaries/dependencies": [
|
|
1938
1982
|
"error",
|
|
1939
1983
|
buildRelationsRuleOptions(relations)
|
|
1940
1984
|
]
|
|
1941
|
-
} : {}
|
|
1985
|
+
} : {},
|
|
1986
|
+
...preset?.rules ?? {},
|
|
1987
|
+
...definition.rules ?? {}
|
|
1942
1988
|
};
|
|
1943
1989
|
return {
|
|
1944
1990
|
...baseConfig,
|