@gobing-ai/ts-rule-engine 0.3.20 → 0.3.22

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 (71) hide show
  1. package/dist/config/loader.d.ts +3 -0
  2. package/dist/config/loader.d.ts.map +1 -1
  3. package/dist/config/loader.js +3 -4
  4. package/dist/engine.d.ts +8 -1
  5. package/dist/engine.d.ts.map +1 -1
  6. package/dist/engine.js +6 -3
  7. package/dist/evaluators/config-access.d.ts +38 -0
  8. package/dist/evaluators/config-access.d.ts.map +1 -0
  9. package/dist/evaluators/config-access.js +60 -0
  10. package/dist/evaluators/coverage-gate-evaluator.d.ts +1 -2
  11. package/dist/evaluators/coverage-gate-evaluator.d.ts.map +1 -1
  12. package/dist/evaluators/coverage-gate-evaluator.js +7 -6
  13. package/dist/evaluators/file-discovery.d.ts +72 -0
  14. package/dist/evaluators/file-discovery.d.ts.map +1 -0
  15. package/dist/evaluators/file-discovery.js +63 -0
  16. package/dist/evaluators/file-utils.d.ts +11 -118
  17. package/dist/evaluators/file-utils.d.ts.map +1 -1
  18. package/dist/evaluators/file-utils.js +11 -177
  19. package/dist/evaluators/forbidden-import-evaluator.d.ts +1 -0
  20. package/dist/evaluators/forbidden-import-evaluator.d.ts.map +1 -1
  21. package/dist/evaluators/forbidden-import-evaluator.js +9 -1
  22. package/dist/evaluators/glob-match.d.ts +34 -0
  23. package/dist/evaluators/glob-match.d.ts.map +1 -0
  24. package/dist/evaluators/glob-match.js +78 -0
  25. package/dist/evaluators/import-boundary-evaluator.d.ts.map +1 -1
  26. package/dist/evaluators/import-boundary-evaluator.js +3 -1
  27. package/dist/evaluators/path-evaluator.d.ts +1 -2
  28. package/dist/evaluators/path-evaluator.d.ts.map +1 -1
  29. package/dist/evaluators/path-evaluator.js +8 -6
  30. package/dist/evaluators/regex-evaluator.d.ts.map +1 -1
  31. package/dist/evaluators/regex-evaluator.js +3 -0
  32. package/dist/evaluators/schema-artifact-evaluator.d.ts +1 -2
  33. package/dist/evaluators/schema-artifact-evaluator.d.ts.map +1 -1
  34. package/dist/evaluators/schema-artifact-evaluator.js +8 -7
  35. package/dist/evaluators/secrets-scanner-evaluator.d.ts.map +1 -1
  36. package/dist/evaluators/secrets-scanner-evaluator.js +3 -1
  37. package/dist/evaluators/test-location-evaluator.d.ts.map +1 -1
  38. package/dist/evaluators/test-location-evaluator.js +3 -1
  39. package/dist/evaluators/tsdoc-export-evaluator.d.ts.map +1 -1
  40. package/dist/evaluators/tsdoc-export-evaluator.js +21 -7
  41. package/dist/fixers/fixers.d.ts +2 -4
  42. package/dist/fixers/fixers.d.ts.map +1 -1
  43. package/dist/fixers/fixers.js +9 -11
  44. package/dist/fixers/test-stub-fixer.d.ts +1 -1
  45. package/dist/fixers/test-stub-fixer.d.ts.map +1 -1
  46. package/dist/fixers/test-stub-fixer.js +2 -2
  47. package/dist/host/bundled-rules.d.ts +2 -2
  48. package/dist/host/bundled-rules.d.ts.map +1 -1
  49. package/dist/host/bundled-rules.js +24 -19
  50. package/dist/types.d.ts +8 -0
  51. package/dist/types.d.ts.map +1 -1
  52. package/package.json +5 -5
  53. package/src/config/loader.ts +14 -6
  54. package/src/engine.ts +12 -4
  55. package/src/evaluators/config-access.ts +76 -0
  56. package/src/evaluators/coverage-gate-evaluator.ts +7 -8
  57. package/src/evaluators/file-discovery.ts +132 -0
  58. package/src/evaluators/file-utils.ts +29 -258
  59. package/src/evaluators/forbidden-import-evaluator.ts +10 -2
  60. package/src/evaluators/glob-match.ts +76 -0
  61. package/src/evaluators/import-boundary-evaluator.ts +3 -1
  62. package/src/evaluators/path-evaluator.ts +8 -7
  63. package/src/evaluators/regex-evaluator.ts +3 -0
  64. package/src/evaluators/schema-artifact-evaluator.ts +9 -8
  65. package/src/evaluators/secrets-scanner-evaluator.ts +3 -1
  66. package/src/evaluators/test-location-evaluator.ts +5 -2
  67. package/src/evaluators/tsdoc-export-evaluator.ts +21 -7
  68. package/src/fixers/fixers.ts +11 -12
  69. package/src/fixers/test-stub-fixer.ts +3 -3
  70. package/src/host/bundled-rules.ts +23 -19
  71. package/src/types.ts +8 -0
@@ -1,3 +1,4 @@
1
+ import { type FileSystem } from '@gobing-ai/ts-runtime';
1
2
  import { type ConstraintRule } from '../types';
2
3
  import { type ExtensionRef } from './extensions';
3
4
  /** Options for loading rule presets. */
@@ -14,6 +15,8 @@ export interface RuleLoaderOptions {
14
15
  validateSchema?: boolean;
15
16
  /** Optional fetch implementation for remote HTTP(S) schema refs. */
16
17
  fetch?: (input: string) => Promise<Response>;
18
+ /** Filesystem for reading roots. Defaults to `createNodeFileSystem()`; inject to test without disk. */
19
+ fileSystem?: FileSystem;
17
20
  }
18
21
  /** Options for loading a single rule file directly from disk. */
19
22
  export interface RuleFileLoadOptions {
@@ -1 +1 @@
1
- {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"AAUA,OAAO,EACH,KAAK,cAAc,EAOtB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAqB,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AAEpE,wCAAwC;AACxC,MAAM,WAAW,iBAAiB;IAC9B;;;;;;OAMG;IACH,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,4FAA4F;IAC5F,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,oEAAoE;IACpE,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;CAChD;AAED,iEAAiE;AACjE,MAAM,WAAW,mBAAmB;IAChC,mEAAmE;IACnE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,oEAAoE;IACpE,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;CAChD;AAED,mFAAmF;AACnF,MAAM,WAAW,YAAY;IACzB,+DAA+D;IAC/D,QAAQ,CAAC,KAAK,EAAE,cAAc,EAAE,CAAC;IACjC,kFAAkF;IAClF,QAAQ,CAAC,UAAU,EAAE,YAAY,EAAE,CAAC;CACvC;AAUD;;;;;;GAMG;AACH,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,YAAY,CAAC,CAahG;AAyCD;;;;;GAKG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAEzG;AAED;;;;;;;;GAQG;AACH,wBAAsB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,mBAAwB,GAAG,OAAO,CAAC,YAAY,CAAC,CAS7G"}
1
+ {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"AAAA,OAAO,EAIH,KAAK,UAAU,EAMlB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACH,KAAK,cAAc,EAOtB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAqB,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AAEpE,wCAAwC;AACxC,MAAM,WAAW,iBAAiB;IAC9B;;;;;;OAMG;IACH,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,4FAA4F;IAC5F,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,oEAAoE;IACpE,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC7C,uGAAuG;IACvG,UAAU,CAAC,EAAE,UAAU,CAAC;CAC3B;AAED,iEAAiE;AACjE,MAAM,WAAW,mBAAmB;IAChC,mEAAmE;IACnE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,oEAAoE;IACpE,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;CAChD;AAED,mFAAmF;AACnF,MAAM,WAAW,YAAY;IACzB,+DAA+D;IAC/D,QAAQ,CAAC,KAAK,EAAE,cAAc,EAAE,CAAC;IACjC,kFAAkF;IAClF,QAAQ,CAAC,UAAU,EAAE,YAAY,EAAE,CAAC;CACvC;AAUD;;;;;;GAMG;AACH,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,YAAY,CAAC,CAgBhG;AAyCD;;;;;GAKG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAEzG;AAED;;;;;;;;GAQG;AACH,wBAAsB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,mBAAwB,GAAG,OAAO,CAAC,YAAY,CAAC,CAS7G"}
@@ -1,4 +1,4 @@
1
- import { basenamePath, dirnamePath, joinPath, loadStructuredConfig, NodeFileSystem, relativePath, resolvePath, SEP, } from '@gobing-ai/ts-runtime';
1
+ import { basenamePath, createNodeFileSystem, dirnamePath, joinPath, loadStructuredConfig, relativePath, resolvePath, SEP, } from '@gobing-ai/ts-runtime';
2
2
  import { ConstraintRuleFileSchema, ConstraintRuleSchema, PresetDefinitionSchema, } from '../types.js';
3
3
  import { collectExtensions } from './extensions.js';
4
4
  /**
@@ -9,7 +9,7 @@ import { collectExtensions } from './extensions.js';
9
9
  * the rest of a preset's categories from the lower-priority roots.
10
10
  */
11
11
  export async function loadPreset(name, options) {
12
- const merged = await buildMergedRoots(options.roots.map((root) => resolvePath(root)));
12
+ const merged = await buildMergedRoots(options.roots.map((root) => resolvePath(root)), options.fileSystem);
13
13
  const presetPath = findMergedPreset(merged, name);
14
14
  if (presetPath === null)
15
15
  return { rules: [], extensions: [] };
@@ -126,8 +126,7 @@ async function loadPresetEntry(merged, entry, seen, options) {
126
126
  * Roots are processed in the order supplied (highest priority first). The first
127
127
  * root to provide a given relative path owns that file; later roots are shadowed.
128
128
  */
129
- async function buildMergedRoots(roots) {
130
- const fs = new NodeFileSystem();
129
+ async function buildMergedRoots(roots, fs = createNodeFileSystem()) {
131
130
  const files = new Map();
132
131
  const categories = new Set();
133
132
  for (const root of roots) {
package/dist/engine.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { EventBus, Logger } from '@gobing-ai/ts-infra';
2
- import type { ProcessExecutor } from '@gobing-ai/ts-runtime';
2
+ import { type FileSystem, type ProcessExecutor } from '@gobing-ai/ts-runtime';
3
3
  import type { RuleEngineEvents } from './events';
4
4
  import { type FixApplicationResult } from './fixers/fixers';
5
5
  import { RuleEngineHost } from './host/rule-engine-host';
@@ -9,6 +9,12 @@ import type { ConstraintRule, Fix, FixMode, RuleEngineResult, RuleEvaluator } fr
9
9
  export interface RuleEngineOptions {
10
10
  /** Optional executor supplied to process-backed evaluators. */
11
11
  processExecutor?: ProcessExecutor;
12
+ /**
13
+ * Filesystem port (ADR-011 union-return {@link FileSystem}); defaults to
14
+ * `createNodeFileSystem()`. Threaded through {@link RuleContext} to every
15
+ * evaluator and fixer provider so hosts can inject a virtual fs in tests.
16
+ */
17
+ fileSystem?: FileSystem;
12
18
  /** Optional preconfigured host. */
13
19
  host?: RuleEngineHost;
14
20
  /** Optional event bus for structured run observability (R-A4). */
@@ -31,6 +37,7 @@ export declare class RuleEngine {
31
37
  private readonly persistence;
32
38
  private readonly runId;
33
39
  private readonly runMeta;
40
+ private readonly fileSystem;
34
41
  constructor(options?: RuleEngineOptions);
35
42
  /** Register or replace an evaluator. */
36
43
  registerEvaluator(type: string, evaluator: RuleEvaluator): void;
@@ -1 +1 @@
1
- {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAE5D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AACjD,OAAO,EAIH,KAAK,oBAAoB,EAE5B,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AACpE,OAAO,KAAK,EAAqB,cAAc,EAAE,GAAG,EAAE,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAGhH,6CAA6C;AAC7C,MAAM,WAAW,iBAAiB;IAC9B,+DAA+D;IAC/D,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,mCAAmC;IACnC,IAAI,CAAC,EAAE,cAAc,CAAC;IACtB,kEAAkE;IAClE,MAAM,CAAC,EAAE,QAAQ,CAAC,gBAAgB,CAAC,CAAC;IACpC,6EAA6E;IAC7E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iEAAiE;IACjE,WAAW,CAAC,EAAE,sBAAsB,CAAC;IACrC,8DAA8D;IAC9D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2EAA2E;IAC3E,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACrC;AAED,4EAA4E;AAC5E,qBAAa,UAAU;IACnB,2CAA2C;IAC3C,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;IAE9B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAyC;IAChE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAqC;IACjE,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsC;gBAElD,OAAO,GAAE,iBAAsB;IAW3C,wCAAwC;IACxC,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,aAAa,GAAG,IAAI;IAI/D;;;;;;;OAOG;IACG,QAAQ,CACV,KAAK,EAAE,cAAc,EAAE,EACvB,OAAO,EAAE,MAAM,EACf,WAAW,CAAC,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,GAC3C,OAAO,CAAC,gBAAgB,CAAC;IAI5B;;;;;;;;;;;;;;;;;;OAkBG;IACG,iBAAiB,CACnB,KAAK,EAAE,cAAc,EAAE,EACvB,OAAO,EAAE,MAAM,EACf,UAAU,GAAE,OAAgB,EAC5B,WAAW,CAAC,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,GAC3C,OAAO,CAAC,gBAAgB,CAAC;IAmK5B;;;;;;;OAOG;IACG,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,GAAG,EAAE,EAAE,MAAM,UAAQ,GAAG,OAAO,CAAC,oBAAoB,CAAC;CAG1G"}
1
+ {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAE5D,OAAO,EAAwB,KAAK,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACpG,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AACjD,OAAO,EAIH,KAAK,oBAAoB,EAE5B,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AACpE,OAAO,KAAK,EAAqB,cAAc,EAAE,GAAG,EAAE,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAGhH,6CAA6C;AAC7C,MAAM,WAAW,iBAAiB;IAC9B,+DAA+D;IAC/D,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC;;;;OAIG;IACH,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,mCAAmC;IACnC,IAAI,CAAC,EAAE,cAAc,CAAC;IACtB,kEAAkE;IAClE,MAAM,CAAC,EAAE,QAAQ,CAAC,gBAAgB,CAAC,CAAC;IACpC,6EAA6E;IAC7E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iEAAiE;IACjE,WAAW,CAAC,EAAE,sBAAsB,CAAC;IACrC,8DAA8D;IAC9D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2EAA2E;IAC3E,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACrC;AAED,4EAA4E;AAC5E,qBAAa,UAAU;IACnB,2CAA2C;IAC3C,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;IAE9B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAyC;IAChE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAqC;IACjE,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsC;IAC9D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAa;gBAE5B,OAAO,GAAE,iBAAsB;IAY3C,wCAAwC;IACxC,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,aAAa,GAAG,IAAI;IAI/D;;;;;;;OAOG;IACG,QAAQ,CACV,KAAK,EAAE,cAAc,EAAE,EACvB,OAAO,EAAE,MAAM,EACf,WAAW,CAAC,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,GAC3C,OAAO,CAAC,gBAAgB,CAAC;IAI5B;;;;;;;;;;;;;;;;;;OAkBG;IACG,iBAAiB,CACnB,KAAK,EAAE,cAAc,EAAE,EACvB,OAAO,EAAE,MAAM,EACf,UAAU,GAAE,OAAgB,EAC5B,WAAW,CAAC,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,GAC3C,OAAO,CAAC,gBAAgB,CAAC;IAmK5B;;;;;;;OAOG;IACG,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,GAAG,EAAE,EAAE,MAAM,UAAQ,GAAG,OAAO,CAAC,oBAAoB,CAAC;CAG1G"}
package/dist/engine.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { addSpanEvent, getLogger, traceAsync } from '@gobing-ai/ts-infra';
2
+ import { createNodeFileSystem } from '@gobing-ai/ts-runtime';
2
3
  import { applyFixes as applyFixesImpl, FIX_MODE_RANK, registerBuiltinFixers, } from './fixers/fixers.js';
3
4
  import { registerBuiltins } from './host/builtins.js';
4
5
  import { RuleEngineHost } from './host/rule-engine-host.js';
@@ -12,6 +13,7 @@ export class RuleEngine {
12
13
  persistence;
13
14
  runId;
14
15
  runMeta;
16
+ fileSystem;
15
17
  constructor(options = {}) {
16
18
  this.host = options.host ?? new RuleEngineHost();
17
19
  registerBuiltins(this.host, options.processExecutor);
@@ -21,6 +23,7 @@ export class RuleEngine {
21
23
  this.persistence = options.persistence;
22
24
  this.runId = options.runId ?? crypto.randomUUID();
23
25
  this.runMeta = options.runMeta;
26
+ this.fileSystem = options.fileSystem ?? createNodeFileSystem();
24
27
  }
25
28
  /** Register or replace an evaluator. */
26
29
  registerEvaluator(type, evaluator) {
@@ -103,7 +106,7 @@ export class RuleEngine {
103
106
  try {
104
107
  const result = await this.host.evaluators
105
108
  .get(rule.evaluator.type)
106
- .evaluate(rule, { rule, workdir });
109
+ .evaluate(rule, { rule, workdir, fileSystem: this.fileSystem });
107
110
  ruleFindings = result.findings;
108
111
  ruleEvalFixes = result.fixes;
109
112
  }
@@ -154,7 +157,7 @@ export class RuleEngine {
154
157
  };
155
158
  const providerFixes = await provider.createFixes({
156
159
  rule,
157
- context: { rule, workdir },
160
+ context: { rule, workdir, fileSystem: this.fileSystem },
158
161
  findings: ruleFindings,
159
162
  fix: effectiveFix,
160
163
  });
@@ -201,7 +204,7 @@ export class RuleEngine {
201
204
  * @returns Application details and optional diff.
202
205
  */
203
206
  async applyFixes(workdir, fixes, dryRun = false) {
204
- return applyFixesImpl(workdir, fixes, dryRun);
207
+ return applyFixesImpl(workdir, fixes, dryRun, this.fileSystem);
205
208
  }
206
209
  }
207
210
  /** Return the lower-authority mode between what the rule requests and what the caller allows. */
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Typed accessors for a rule's `evaluator.config` bag and inline-flag parsing.
3
+ *
4
+ * Required keys fail loudly (throw, naming the evaluator) so misconfigured rules
5
+ * surface at evaluation time rather than silently scanning the wrong set.
6
+ */
7
+ /** Return the value as a `string[]` when every item is a string, otherwise undefined. */
8
+ export declare function stringArray(value: unknown): string[] | undefined;
9
+ /** Optional accessor context — names the evaluator in "required config" errors for rule authors. */
10
+ export interface ConfigAccessorOptions {
11
+ /** Evaluator name surfaced in the error, e.g. `"regex evaluator requires string config \"pattern\""`. */
12
+ evaluator?: string;
13
+ }
14
+ /**
15
+ * Read a string entry from a rule's evaluator config. Returns the value when it is a string,
16
+ * the `fallback` when one is supplied, otherwise throws — so required keys fail loudly.
17
+ */
18
+ export declare function configString(config: Record<string, unknown>, key: string, fallback?: string, options?: ConfigAccessorOptions): string;
19
+ /**
20
+ * Read a string-array entry from a rule's evaluator config. A bare string is coerced to a
21
+ * single-element array. Returns the `fallback` when one is supplied and the value is absent;
22
+ * otherwise throws — so required keys fail loudly.
23
+ */
24
+ export declare function configArray(config: Record<string, unknown>, key: string, fallback?: string[], options?: ConfigAccessorOptions): string[];
25
+ /** Read a finite-number entry from a rule's evaluator config, falling back when absent or invalid. */
26
+ export declare function configNumber(config: Record<string, unknown>, key: string, fallback: number): number;
27
+ /**
28
+ * Split a leading ripgrep/PCRE-style `(?flags)` inline group off a regex source.
29
+ *
30
+ * Returns the JS-relevant flags found in the group (filtered to `imsu`) and the
31
+ * remaining source with the group removed. When no leading group is present, returns
32
+ * empty flags and the source unchanged. Shared by evaluators that accept inline flags.
33
+ */
34
+ export declare function parseInlineFlags(source: string): {
35
+ flags: string;
36
+ rest: string;
37
+ };
38
+ //# sourceMappingURL=config-access.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-access.d.ts","sourceRoot":"","sources":["../../src/evaluators/config-access.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,yFAAyF;AACzF,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,EAAE,GAAG,SAAS,CAEhE;AAED,oGAAoG;AACpG,MAAM,WAAW,qBAAqB;IAClC,yGAAyG;IACzG,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAOD;;;GAGG;AACH,wBAAgB,YAAY,CACxB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,GAAG,EAAE,MAAM,EACX,QAAQ,CAAC,EAAE,MAAM,EACjB,OAAO,GAAE,qBAA0B,GACpC,MAAM,CAKR;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CACvB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,GAAG,EAAE,MAAM,EACX,QAAQ,CAAC,EAAE,MAAM,EAAE,EACnB,OAAO,GAAE,qBAA0B,GACpC,MAAM,EAAE,CAMV;AAED,sGAAsG;AACtG,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGnG;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAKhF"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Typed accessors for a rule's `evaluator.config` bag and inline-flag parsing.
3
+ *
4
+ * Required keys fail loudly (throw, naming the evaluator) so misconfigured rules
5
+ * surface at evaluation time rather than silently scanning the wrong set.
6
+ */
7
+ /** Return the value as a `string[]` when every item is a string, otherwise undefined. */
8
+ export function stringArray(value) {
9
+ return Array.isArray(value) && value.every((item) => typeof item === 'string') ? value : undefined;
10
+ }
11
+ function requiredConfigError(kind, key, evaluator) {
12
+ const who = evaluator !== undefined ? `${evaluator} evaluator` : 'evaluator';
13
+ return new Error(`${who} requires ${kind} config "${key}"`);
14
+ }
15
+ /**
16
+ * Read a string entry from a rule's evaluator config. Returns the value when it is a string,
17
+ * the `fallback` when one is supplied, otherwise throws — so required keys fail loudly.
18
+ */
19
+ export function configString(config, key, fallback, options = {}) {
20
+ const value = config[key];
21
+ if (typeof value === 'string')
22
+ return value;
23
+ if (fallback !== undefined)
24
+ return fallback;
25
+ throw requiredConfigError('string', key, options.evaluator);
26
+ }
27
+ /**
28
+ * Read a string-array entry from a rule's evaluator config. A bare string is coerced to a
29
+ * single-element array. Returns the `fallback` when one is supplied and the value is absent;
30
+ * otherwise throws — so required keys fail loudly.
31
+ */
32
+ export function configArray(config, key, fallback, options = {}) {
33
+ const value = config[key];
34
+ if (Array.isArray(value) && value.every((item) => typeof item === 'string'))
35
+ return value;
36
+ if (typeof value === 'string')
37
+ return [value];
38
+ if (fallback !== undefined)
39
+ return fallback;
40
+ throw requiredConfigError('string[]', key, options.evaluator);
41
+ }
42
+ /** Read a finite-number entry from a rule's evaluator config, falling back when absent or invalid. */
43
+ export function configNumber(config, key, fallback) {
44
+ const value = config[key];
45
+ return typeof value === 'number' && Number.isFinite(value) ? value : fallback;
46
+ }
47
+ /**
48
+ * Split a leading ripgrep/PCRE-style `(?flags)` inline group off a regex source.
49
+ *
50
+ * Returns the JS-relevant flags found in the group (filtered to `imsu`) and the
51
+ * remaining source with the group removed. When no leading group is present, returns
52
+ * empty flags and the source unchanged. Shared by evaluators that accept inline flags.
53
+ */
54
+ export function parseInlineFlags(source) {
55
+ const match = /^\(\?([a-z]+)\)/.exec(source);
56
+ if (!match)
57
+ return { flags: '', rest: source };
58
+ const flags = [...(match[1] ?? '')].filter((flag) => 'imsu'.includes(flag)).join('');
59
+ return { flags, rest: source.slice(match[0].length) };
60
+ }
@@ -13,9 +13,8 @@ import { type ConstraintRule, type RuleContext, type RuleEvaluationResult, type
13
13
  * error, so the gate degrades gracefully when coverage was not generated.
14
14
  */
15
15
  export declare class CoverageGateEvaluator implements RuleEvaluator {
16
- private readonly fs;
17
- constructor();
18
16
  /** Evaluate per-file coverage against the configured threshold. */
17
+ constructor();
19
18
  evaluate(rule: ConstraintRule, context: RuleContext): Promise<RuleEvaluationResult>;
20
19
  }
21
20
  //# sourceMappingURL=coverage-gate-evaluator.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"coverage-gate-evaluator.d.ts","sourceRoot":"","sources":["../../src/evaluators/coverage-gate-evaluator.ts"],"names":[],"mappings":"AACA,OAAO,EACH,KAAK,cAAc,EAEnB,KAAK,WAAW,EAChB,KAAK,oBAAoB,EACzB,KAAK,aAAa,EACrB,MAAM,UAAU,CAAC;AAyBlB;;;;;;;;;;;;GAYG;AACH,qBAAa,qBAAsB,YAAW,aAAa;IACvD,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAiB;;IAMpC,mEAAmE;IAC7D,QAAQ,CAAC,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,oBAAoB,CAAC;CA0C5F"}
1
+ {"version":3,"file":"coverage-gate-evaluator.d.ts","sourceRoot":"","sources":["../../src/evaluators/coverage-gate-evaluator.ts"],"names":[],"mappings":"AACA,OAAO,EACH,KAAK,cAAc,EAEnB,KAAK,WAAW,EAChB,KAAK,oBAAoB,EACzB,KAAK,aAAa,EACrB,MAAM,UAAU,CAAC;AAyBlB;;;;;;;;;;;;GAYG;AACH,qBAAa,qBAAsB,YAAW,aAAa;IACvD,mEAAmE;;IAM7D,QAAQ,CAAC,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,oBAAoB,CAAC;CA0C5F"}
@@ -1,4 +1,4 @@
1
- import { isAbsolutePath, NodeFileSystem, relativePath, resolvePath } from '@gobing-ai/ts-runtime';
1
+ import { createNodeFileSystem, isAbsolutePath, relativePath, resolvePath } from '@gobing-ai/ts-runtime';
2
2
  import { createFinding, } from '../types.js';
3
3
  import { matchesGlob } from './file-utils.js';
4
4
  /**
@@ -15,17 +15,18 @@ import { matchesGlob } from './file-utils.js';
15
15
  * error, so the gate degrades gracefully when coverage was not generated.
16
16
  */
17
17
  export class CoverageGateEvaluator {
18
- fs;
18
+ /** Evaluate per-file coverage against the configured threshold. */
19
+ // Explicit constructor avoids a V8 function-coverage phantom (synthesized default ctor).
19
20
  constructor() {
20
- this.fs = new NodeFileSystem();
21
+ // no-op; all state comes from evaluate() context
21
22
  }
22
- /** Evaluate per-file coverage against the configured threshold. */
23
23
  async evaluate(rule, context) {
24
+ const fs = context.fileSystem ?? createNodeFileSystem();
24
25
  const config = (rule.evaluator.config ?? {});
25
26
  const lcovPath = config.lcovPath
26
27
  ? resolvePath(context.workdir, config.lcovPath)
27
28
  : resolvePath(context.workdir, 'coverage', 'lcov.info');
28
- if (!(await this.fs.exists(lcovPath))) {
29
+ if (!(await fs.exists(lcovPath))) {
29
30
  return {
30
31
  findings: [
31
32
  createFinding(rule, 'No lcov file found — coverage not generated. Skipping gate.', lcovPath, {
@@ -35,7 +36,7 @@ export class CoverageGateEvaluator {
35
36
  fixes: [],
36
37
  };
37
38
  }
38
- const coverage = parseLcov(await this.fs.readFile(lcovPath));
39
+ const coverage = parseLcov(await fs.readFile(lcovPath));
39
40
  const threshold = config.threshold ?? 90;
40
41
  const exemptions = new Map((config.exemptions ?? []).map((entry) => [entry.path, entry]));
41
42
  const findings = [];
@@ -0,0 +1,72 @@
1
+ /**
2
+ * File discovery and reading for evaluators — the shared scaffolding behind the
3
+ * line-scanning rules. Owns directory walks, scope filtering, and per-file reads
4
+ * so each evaluator is left with only its own matcher.
5
+ */
6
+ import { type FileSystem } from '@gobing-ai/ts-runtime';
7
+ /** Options for source-file discovery. */
8
+ export interface SourceDiscoveryOptions {
9
+ /** Working directory. */
10
+ workdir: string;
11
+ /** Include path fragments or suffixes. */
12
+ include?: string[];
13
+ /** Exclude path fragments. */
14
+ exclude?: string[];
15
+ /** Filesystem adapter. */
16
+ fs?: FileSystem;
17
+ }
18
+ /**
19
+ * Directory names pruned from every file walk — heavy or generated trees that no rule
20
+ * should scan. Shared so subprocess-backed evaluators (e.g. `sg`) can forward the same
21
+ * skip-list to the external tool instead of relying on each rule to remember it.
22
+ */
23
+ export declare const DEFAULT_EXCLUDES: Set<string>;
24
+ /** Resolve source files for evaluators using conservative path-fragment matching. */
25
+ export declare function discoverFiles(options: SourceDiscoveryOptions): Promise<string[]>;
26
+ /** Read a file from a workdir-relative path. */
27
+ export declare function readWorkdirFile(workdir: string, filePath: string, fs?: FileSystem): Promise<string>;
28
+ /** A discovered in-scope file paired with its contents. */
29
+ export interface ScannedFile {
30
+ /** Workdir-relative path. */
31
+ readonly file: string;
32
+ /** Full file contents. */
33
+ readonly content: string;
34
+ }
35
+ /** How `scanFiles` matches `include` / `exclude` against discovered paths. */
36
+ export type ScanMatchMode = 'loose' | 'glob';
37
+ /** Options for {@link scanFiles}. */
38
+ export interface ScanFilesOptions {
39
+ /** Working directory to walk. */
40
+ workdir: string;
41
+ /** Include patterns; semantics depend on `matchMode`. Undefined/empty = all files. */
42
+ include?: string[];
43
+ /** Exclude patterns; semantics depend on `matchMode`. */
44
+ exclude?: string[];
45
+ /**
46
+ * Scope matching policy:
47
+ * - `loose` — substring/suffix fragments via {@link matchesAny} (back-compat for
48
+ * evaluators that historically accepted bare fragments like `.ts` or `src/`).
49
+ * - `glob` — anchored `**`/`*` globs via {@link matchesGlob}.
50
+ *
51
+ * The two are NOT interchangeable: a bare `src/` matches different sets under each.
52
+ * Each evaluator declares the mode that preserves its existing behavior.
53
+ */
54
+ matchMode: ScanMatchMode;
55
+ /** Filesystem adapter. */
56
+ fs?: FileSystem;
57
+ }
58
+ /**
59
+ * Discover in-scope files and read each once — the shared scaffolding behind the
60
+ * line-scanning evaluators. Owns discovery, scope filtering (per `matchMode`), and
61
+ * reads, so each evaluator is left with only its own matcher.
62
+ *
63
+ * Scope is a parameter, not assumed one-per-rule: callers that scan under several
64
+ * scopes (e.g. import boundaries) pass no `include` here and apply their own globs to
65
+ * the returned paths.
66
+ */
67
+ export declare function scanFiles(options: ScanFilesOptions): Promise<ScannedFile[]>;
68
+ /** Ensure a path is workdir-relative for findings. */
69
+ export declare function relativeToWorkdir(workdir: string, path: string): string;
70
+ /** Return parent directory for a workdir-relative path. */
71
+ export declare function relativeParent(path: string): string;
72
+ //# sourceMappingURL=file-discovery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-discovery.d.ts","sourceRoot":"","sources":["../../src/evaluators/file-discovery.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAGH,KAAK,UAAU,EAIlB,MAAM,uBAAuB,CAAC;AAG/B,yCAAyC;AACzC,MAAM,WAAW,sBAAsB;IACnC,yBAAyB;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,0CAA0C;IAC1C,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,8BAA8B;IAC9B,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,0BAA0B;IAC1B,EAAE,CAAC,EAAE,UAAU,CAAC;CACnB;AAED;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,aAAgF,CAAC;AAE9G,qFAAqF;AACrF,wBAAsB,aAAa,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAWtF;AAED,gDAAgD;AAChD,wBAAsB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,aAAyB,GAAG,OAAO,CAAC,MAAM,CAAC,CAErH;AAED,2DAA2D;AAC3D,MAAM,WAAW,WAAW;IACxB,6BAA6B;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,0BAA0B;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC5B;AAED,8EAA8E;AAC9E,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,MAAM,CAAC;AAE7C,qCAAqC;AACrC,MAAM,WAAW,gBAAgB;IAC7B,iCAAiC;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,sFAAsF;IACtF,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,yDAAyD;IACzD,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB;;;;;;;;OAQG;IACH,SAAS,EAAE,aAAa,CAAC;IACzB,0BAA0B;IAC1B,EAAE,CAAC,EAAE,UAAU,CAAC;CACnB;AAED;;;;;;;;GAQG;AACH,wBAAsB,SAAS,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAWjF;AAeD,sDAAsD;AACtD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAEvE;AAED,2DAA2D;AAC3D,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAGnD"}
@@ -0,0 +1,63 @@
1
+ /**
2
+ * File discovery and reading for evaluators — the shared scaffolding behind the
3
+ * line-scanning rules. Owns directory walks, scope filtering, and per-file reads
4
+ * so each evaluator is left with only its own matcher.
5
+ */
6
+ import { createNodeFileSystem, dirnamePath, relativePath, resolvePath, walkDir, } from '@gobing-ai/ts-runtime';
7
+ import { matchesAny, matchesGlob } from './glob-match.js';
8
+ /**
9
+ * Directory names pruned from every file walk — heavy or generated trees that no rule
10
+ * should scan. Shared so subprocess-backed evaluators (e.g. `sg`) can forward the same
11
+ * skip-list to the external tool instead of relying on each rule to remember it.
12
+ */
13
+ export const DEFAULT_EXCLUDES = new Set(['.git', 'node_modules', 'dist', '.coverage', '.astro', '.wrangler']);
14
+ /** Resolve source files for evaluators using conservative path-fragment matching. */
15
+ export async function discoverFiles(options) {
16
+ const fs = options.fs ?? createNodeFileSystem();
17
+ const allFiles = await walkDir(options.workdir, fs, DEFAULT_EXCLUDES);
18
+ return allFiles
19
+ .map((path) => relativePath(options.workdir, path))
20
+ .filter((path) => !path.split('/').some((segment) => DEFAULT_EXCLUDES.has(segment)))
21
+ .filter((path) => matchesAny(path, options.include) &&
22
+ (options.exclude === undefined || !matchesAny(path, options.exclude)));
23
+ }
24
+ /** Read a file from a workdir-relative path. */
25
+ export async function readWorkdirFile(workdir, filePath, fs = createNodeFileSystem()) {
26
+ return await fs.readFile(resolvePath(workdir, filePath));
27
+ }
28
+ /**
29
+ * Discover in-scope files and read each once — the shared scaffolding behind the
30
+ * line-scanning evaluators. Owns discovery, scope filtering (per `matchMode`), and
31
+ * reads, so each evaluator is left with only its own matcher.
32
+ *
33
+ * Scope is a parameter, not assumed one-per-rule: callers that scan under several
34
+ * scopes (e.g. import boundaries) pass no `include` here and apply their own globs to
35
+ * the returned paths.
36
+ */
37
+ export async function scanFiles(options) {
38
+ const fs = options.fs ?? createNodeFileSystem();
39
+ const files = options.matchMode === 'loose'
40
+ ? await discoverFiles({ workdir: options.workdir, include: options.include, exclude: options.exclude, fs })
41
+ : await discoverFilesByGlob(options.workdir, options.include, options.exclude, fs);
42
+ const scanned = [];
43
+ for (const file of files) {
44
+ scanned.push({ file, content: await readWorkdirFile(options.workdir, file, fs) });
45
+ }
46
+ return scanned;
47
+ }
48
+ /** Discover files then filter with anchored globs (strict mode for {@link scanFiles}). */
49
+ async function discoverFilesByGlob(workdir, include, exclude, fs) {
50
+ const all = await discoverFiles({ workdir, fs });
51
+ return all
52
+ .filter((file) => include === undefined || include.length === 0 || include.some((g) => matchesGlob(file, g)))
53
+ .filter((file) => exclude === undefined || !exclude.some((g) => matchesGlob(file, g)));
54
+ }
55
+ /** Ensure a path is workdir-relative for findings. */
56
+ export function relativeToWorkdir(workdir, path) {
57
+ return relativePath(workdir, resolvePath(path));
58
+ }
59
+ /** Return parent directory for a workdir-relative path. */
60
+ export function relativeParent(path) {
61
+ const parent = dirnamePath(path);
62
+ return parent === '.' ? '' : parent;
63
+ }
@@ -1,123 +1,16 @@
1
- import { type LegacyFileSystem as FileSystem, NodeFileSystem } from '@gobing-ai/ts-runtime';
2
- /** Options for source-file discovery. */
3
- export interface SourceDiscoveryOptions {
4
- /** Working directory. */
5
- workdir: string;
6
- /** Include path fragments or suffixes. */
7
- include?: string[];
8
- /** Exclude path fragments. */
9
- exclude?: string[];
10
- /** Filesystem adapter. */
11
- fs?: FileSystem;
12
- }
13
1
  /**
14
- * Directory names pruned from every file walk — heavy or generated trees that no rule
15
- * should scan. Shared so subprocess-backed evaluators (e.g. `sg`) can forward the same
16
- * skip-list to the external tool instead of relying on each rule to remember it.
17
- */
18
- export declare const DEFAULT_EXCLUDES: Set<string>;
19
- /** Resolve source files for evaluators using conservative path-fragment matching. */
20
- export declare function discoverFiles(options: SourceDiscoveryOptions): Promise<string[]>;
21
- /** Read a file from a workdir-relative path. */
22
- export declare function readWorkdirFile(workdir: string, filePath: string, fs?: NodeFileSystem): Promise<string>;
23
- /** A discovered in-scope file paired with its contents. */
24
- export interface ScannedFile {
25
- /** Workdir-relative path. */
26
- readonly file: string;
27
- /** Full file contents. */
28
- readonly content: string;
29
- }
30
- /** How `scanFiles` matches `include` / `exclude` against discovered paths. */
31
- export type ScanMatchMode = 'loose' | 'glob';
32
- /** Options for {@link scanFiles}. */
33
- export interface ScanFilesOptions {
34
- /** Working directory to walk. */
35
- workdir: string;
36
- /** Include patterns; semantics depend on `matchMode`. Undefined/empty = all files. */
37
- include?: string[];
38
- /** Exclude patterns; semantics depend on `matchMode`. */
39
- exclude?: string[];
40
- /**
41
- * Scope matching policy:
42
- * - `loose` — substring/suffix fragments via {@link matchesAny} (back-compat for
43
- * evaluators that historically accepted bare fragments like `.ts` or `src/`).
44
- * - `glob` — anchored `**`/`*` globs via {@link matchesGlob}.
45
- *
46
- * The two are NOT interchangeable: a bare `src/` matches different sets under each.
47
- * Each evaluator declares the mode that preserves its existing behavior.
48
- */
49
- matchMode: ScanMatchMode;
50
- /** Filesystem adapter. */
51
- fs?: FileSystem;
52
- }
53
- /**
54
- * Discover in-scope files and read each once — the shared scaffolding behind the
55
- * line-scanning evaluators. Owns discovery, scope filtering (per `matchMode`), and
56
- * reads, so each evaluator is left with only its own matcher.
57
- *
58
- * Scope is a parameter, not assumed one-per-rule: callers that scan under several
59
- * scopes (e.g. import boundaries) pass no `include` here and apply their own globs to
60
- * the returned paths.
61
- */
62
- export declare function scanFiles(options: ScanFilesOptions): Promise<ScannedFile[]>;
63
- /** Ensure a path is workdir-relative for findings. */
64
- export declare function relativeToWorkdir(workdir: string, path: string): string;
65
- /** Return parent directory for a workdir-relative path. */
66
- export declare function relativeParent(path: string): string;
67
- /**
68
- * Return true when a path matches any supplied pattern.
69
- *
70
- * Each pattern is matched in two passes, most-specific first:
71
- * 1. If it contains a glob metachar (`*`), try anchored {@link matchesGlob} —
72
- * so `packages/**\/*.ts` resolves segment-by-segment instead of collapsing
73
- * to a bare fragment (the latter silently matched nothing, leaving every
74
- * glob-scoped loose-mode rule scanning zero files).
75
- * 2. Otherwise (or if the glob did not match), fall back to the legacy
76
- * fragment/suffix substring test, where stars are stripped — preserving
77
- * bare fragments like `.ts`, `src/`, `/tests/` that loose-mode evaluators
78
- * have always accepted, and keeping unanchored patterns like `*.ts`
79
- * (→ suffix `.ts`) matching nested paths.
80
- */
81
- export declare function matchesAny(path: string, patterns: string[] | undefined): boolean;
82
- /**
83
- * Segment-aware glob matching with `**` (any depth) and `*` (single segment).
2
+ * Aggregating barrel for evaluator file utilities — kept so existing imports
3
+ * (`./file-utils`) stay stable. The implementation now lives in three focused
4
+ * modules by concern:
84
5
  *
85
- * Stricter than {@link matchesAny}: it anchors the whole path, so `apps/**` does
86
- * not match `vendor/apps/x`. Used by evaluators that enforce path policies
87
- * (coverage scoping, test-file location) where a loose match would change findings.
88
- */
89
- export declare function matchesGlob(path: string, pattern: string): boolean;
90
- /** Escape a string for safe literal use inside a `RegExp` source. */
91
- export declare function escapeRegExp(value: string): string;
92
- /** Return the value as a `string[]` when every item is a string, otherwise undefined. */
93
- export declare function stringArray(value: unknown): string[] | undefined;
94
- /** Optional accessor context — names the evaluator in "required config" errors for rule authors. */
95
- export interface ConfigAccessorOptions {
96
- /** Evaluator name surfaced in the error, e.g. `"regex evaluator requires string config \"pattern\""`. */
97
- evaluator?: string;
98
- }
99
- /**
100
- * Read a string entry from a rule's evaluator config. Returns the value when it is a string,
101
- * the `fallback` when one is supplied, otherwise throws — so required keys fail loudly.
102
- */
103
- export declare function configString(config: Record<string, unknown>, key: string, fallback?: string, options?: ConfigAccessorOptions): string;
104
- /**
105
- * Read a string-array entry from a rule's evaluator config. A bare string is coerced to a
106
- * single-element array. Returns the `fallback` when one is supplied and the value is absent;
107
- * otherwise throws — so required keys fail loudly.
108
- */
109
- export declare function configArray(config: Record<string, unknown>, key: string, fallback?: string[], options?: ConfigAccessorOptions): string[];
110
- /** Read a finite-number entry from a rule's evaluator config, falling back when absent or invalid. */
111
- export declare function configNumber(config: Record<string, unknown>, key: string, fallback: number): number;
112
- /**
113
- * Split a leading ripgrep/PCRE-style `(?flags)` inline group off a regex source.
6
+ * - `./glob-match` — path-pattern matching (`matchesAny`, `matchesGlob`, `escapeRegExp`)
7
+ * - `./file-discovery` — directory walks, scope filtering, per-file reads
8
+ * - `./config-access` — typed `evaluator.config` accessors + inline-flag parsing
114
9
  *
115
- * Returns the JS-relevant flags found in the group (filtered to `imsu`) and the
116
- * remaining source with the group removed. When no leading group is present, returns
117
- * empty flags and the source unchanged. Shared by evaluators that accept inline flags.
10
+ * Prefer importing from the specific module in new code; this barrel exists for
11
+ * back-compat and as a convenience surface.
118
12
  */
119
- export declare function parseInlineFlags(source: string): {
120
- flags: string;
121
- rest: string;
122
- };
13
+ export { type ConfigAccessorOptions, configArray, configNumber, configString, parseInlineFlags, stringArray, } from './config-access';
14
+ export { DEFAULT_EXCLUDES, discoverFiles, readWorkdirFile, relativeParent, relativeToWorkdir, type ScanFilesOptions, type ScanMatchMode, type ScannedFile, type SourceDiscoveryOptions, scanFiles, } from './file-discovery';
15
+ export { escapeRegExp, matchesAny, matchesGlob } from './glob-match';
123
16
  //# sourceMappingURL=file-utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"file-utils.d.ts","sourceRoot":"","sources":["../../src/evaluators/file-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAEH,KAAK,gBAAgB,IAAI,UAAU,EACnC,cAAc,EAIjB,MAAM,uBAAuB,CAAC;AAE/B,yCAAyC;AACzC,MAAM,WAAW,sBAAsB;IACnC,yBAAyB;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,0CAA0C;IAC1C,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,8BAA8B;IAC9B,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,0BAA0B;IAC1B,EAAE,CAAC,EAAE,UAAU,CAAC;CACnB;AAED;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,aAAgF,CAAC;AAE9G,qFAAqF;AACrF,wBAAsB,aAAa,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAWtF;AAED,gDAAgD;AAChD,wBAAsB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,iBAAuB,GAAG,OAAO,CAAC,MAAM,CAAC,CAEnH;AAED,2DAA2D;AAC3D,MAAM,WAAW,WAAW;IACxB,6BAA6B;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,0BAA0B;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC5B;AAED,8EAA8E;AAC9E,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,MAAM,CAAC;AAE7C,qCAAqC;AACrC,MAAM,WAAW,gBAAgB;IAC7B,iCAAiC;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,sFAAsF;IACtF,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,yDAAyD;IACzD,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB;;;;;;;;OAQG;IACH,SAAS,EAAE,aAAa,CAAC;IACzB,0BAA0B;IAC1B,EAAE,CAAC,EAAE,UAAU,CAAC;CACnB;AAED;;;;;;;;GAQG;AACH,wBAAsB,SAAS,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAWjF;AAeD,sDAAsD;AACtD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAEvE;AAED,2DAA2D;AAC3D,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAGnD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,SAAS,GAAG,OAAO,CAShF;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAUlE;AAqBD,qEAAqE;AACrE,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,yFAAyF;AACzF,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,EAAE,GAAG,SAAS,CAEhE;AAED,oGAAoG;AACpG,MAAM,WAAW,qBAAqB;IAClC,yGAAyG;IACzG,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAOD;;;GAGG;AACH,wBAAgB,YAAY,CACxB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,GAAG,EAAE,MAAM,EACX,QAAQ,CAAC,EAAE,MAAM,EACjB,OAAO,GAAE,qBAA0B,GACpC,MAAM,CAKR;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CACvB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,GAAG,EAAE,MAAM,EACX,QAAQ,CAAC,EAAE,MAAM,EAAE,EACnB,OAAO,GAAE,qBAA0B,GACpC,MAAM,EAAE,CAMV;AAED,sGAAsG;AACtG,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGnG;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAKhF"}
1
+ {"version":3,"file":"file-utils.d.ts","sourceRoot":"","sources":["../../src/evaluators/file-utils.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EACH,KAAK,qBAAqB,EAC1B,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,gBAAgB,EAChB,WAAW,GACd,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACH,gBAAgB,EAChB,aAAa,EACb,eAAe,EACf,cAAc,EACd,iBAAiB,EACjB,KAAK,gBAAgB,EACrB,KAAK,aAAa,EAClB,KAAK,WAAW,EAChB,KAAK,sBAAsB,EAC3B,SAAS,GACZ,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC"}