@gobing-ai/ts-rule-engine 0.3.20 → 0.3.21
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/config/loader.d.ts +3 -0
- package/dist/config/loader.d.ts.map +1 -1
- package/dist/config/loader.js +3 -4
- package/dist/engine.d.ts +8 -1
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +6 -3
- package/dist/evaluators/config-access.d.ts +38 -0
- package/dist/evaluators/config-access.d.ts.map +1 -0
- package/dist/evaluators/config-access.js +60 -0
- package/dist/evaluators/coverage-gate-evaluator.d.ts +1 -2
- package/dist/evaluators/coverage-gate-evaluator.d.ts.map +1 -1
- package/dist/evaluators/coverage-gate-evaluator.js +7 -6
- package/dist/evaluators/file-discovery.d.ts +72 -0
- package/dist/evaluators/file-discovery.d.ts.map +1 -0
- package/dist/evaluators/file-discovery.js +63 -0
- package/dist/evaluators/file-utils.d.ts +11 -118
- package/dist/evaluators/file-utils.d.ts.map +1 -1
- package/dist/evaluators/file-utils.js +11 -177
- package/dist/evaluators/forbidden-import-evaluator.d.ts +1 -0
- package/dist/evaluators/forbidden-import-evaluator.d.ts.map +1 -1
- package/dist/evaluators/forbidden-import-evaluator.js +9 -1
- package/dist/evaluators/glob-match.d.ts +34 -0
- package/dist/evaluators/glob-match.d.ts.map +1 -0
- package/dist/evaluators/glob-match.js +78 -0
- package/dist/evaluators/import-boundary-evaluator.d.ts.map +1 -1
- package/dist/evaluators/import-boundary-evaluator.js +3 -1
- package/dist/evaluators/path-evaluator.d.ts +1 -2
- package/dist/evaluators/path-evaluator.d.ts.map +1 -1
- package/dist/evaluators/path-evaluator.js +8 -6
- package/dist/evaluators/regex-evaluator.d.ts.map +1 -1
- package/dist/evaluators/regex-evaluator.js +3 -0
- package/dist/evaluators/schema-artifact-evaluator.d.ts +1 -2
- package/dist/evaluators/schema-artifact-evaluator.d.ts.map +1 -1
- package/dist/evaluators/schema-artifact-evaluator.js +8 -7
- package/dist/evaluators/secrets-scanner-evaluator.d.ts.map +1 -1
- package/dist/evaluators/secrets-scanner-evaluator.js +3 -1
- package/dist/evaluators/test-location-evaluator.d.ts.map +1 -1
- package/dist/evaluators/test-location-evaluator.js +3 -1
- package/dist/evaluators/tsdoc-export-evaluator.d.ts.map +1 -1
- package/dist/evaluators/tsdoc-export-evaluator.js +3 -1
- package/dist/fixers/fixers.d.ts +2 -4
- package/dist/fixers/fixers.d.ts.map +1 -1
- package/dist/fixers/fixers.js +9 -11
- package/dist/fixers/test-stub-fixer.d.ts +1 -1
- package/dist/fixers/test-stub-fixer.d.ts.map +1 -1
- package/dist/fixers/test-stub-fixer.js +2 -2
- package/dist/host/bundled-rules.d.ts +2 -2
- package/dist/host/bundled-rules.d.ts.map +1 -1
- package/dist/host/bundled-rules.js +24 -19
- package/dist/types.d.ts +8 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/config/loader.ts +14 -6
- package/src/engine.ts +12 -4
- package/src/evaluators/config-access.ts +76 -0
- package/src/evaluators/coverage-gate-evaluator.ts +7 -8
- package/src/evaluators/file-discovery.ts +132 -0
- package/src/evaluators/file-utils.ts +29 -258
- package/src/evaluators/forbidden-import-evaluator.ts +10 -2
- package/src/evaluators/glob-match.ts +76 -0
- package/src/evaluators/import-boundary-evaluator.ts +3 -1
- package/src/evaluators/path-evaluator.ts +8 -7
- package/src/evaluators/regex-evaluator.ts +3 -0
- package/src/evaluators/schema-artifact-evaluator.ts +9 -8
- package/src/evaluators/secrets-scanner-evaluator.ts +3 -1
- package/src/evaluators/test-location-evaluator.ts +5 -2
- package/src/evaluators/tsdoc-export-evaluator.ts +3 -1
- package/src/fixers/fixers.ts +11 -12
- package/src/fixers/test-stub-fixer.ts +3 -3
- package/src/host/bundled-rules.ts +23 -19
- package/src/types.ts +8 -0
package/dist/config/loader.d.ts
CHANGED
|
@@ -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":"
|
|
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"}
|
package/dist/config/loader.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { basenamePath, dirnamePath, joinPath, loadStructuredConfig,
|
|
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
|
|
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;
|
package/dist/engine.d.ts.map
CHANGED
|
@@ -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;
|
|
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,
|
|
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 {
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
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
|
-
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
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
|
-
*
|
|
116
|
-
*
|
|
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
|
|
120
|
-
|
|
121
|
-
|
|
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,
|
|
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"}
|