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/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 'filename-pascal-case': eslint.Rule.RuleModule;
76
- readonly 'no-multiline-imports': eslint.Rule.RuleModule;
77
- readonly 'project-setup': eslint.Rule.RuleModule;
78
- readonly 'project-structure': eslint.Rule.RuleModule;
79
- readonly 'sort-imports': eslint.Rule.RuleModule;
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: { description: "Enforce PascalCase for file names" },
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: { type: "array", items: { type: "string" } },
17
- ignoreMiddleExtensions: { type: "boolean" }
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 hasWarned = false;
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 warnOnce() {
427
- if (hasWarned) return;
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
- hasWarned = true;
432
- console.warn(
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: "Warn when the project structure validation is not configured"
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
- warnOnce();
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: "Sort imports by group and line length descending, collapsing multiline imports"
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: "As importa\xE7\xF5es devem estar ordenadas por grupo e tamanho da linha, ocupando uma \xFAnica linha."
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.3.1"
625
+ version: "0.4.0"
590
626
  },
591
627
  rules: {
592
- "filename-pascal-case": filenamePascalCase,
593
- "no-multiline-imports": noMultilineImports,
594
- "project-setup": projectSetup,
595
- "project-structure": projectStructure,
596
- "sort-imports": sortImports
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
- "ai-rules/sort-imports": "error",
618
- "ai-rules/no-multiline-imports": "error",
619
- "ai-rules/filename-pascal-case": "error",
620
- "ai-rules/project-setup": "warn",
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
- ...preset?.rules ?? {},
1892
- "ai-rules/project-structure": structureEnabled ? "error" : "off",
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,