@shrkcrft/boundaries 0.1.0-alpha.29 → 0.1.0-alpha.31
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/baseline/compute-baseline.d.ts +8 -0
- package/dist/baseline/compute-baseline.d.ts.map +1 -1
- package/dist/baseline/compute-baseline.js +10 -8
- package/dist/baseline/diff-baseline.d.ts +28 -0
- package/dist/baseline/diff-baseline.d.ts.map +1 -1
- package/dist/baseline/diff-baseline.js +29 -0
- package/dist/evaluate/boundary-unit-finding.d.ts +10 -0
- package/dist/evaluate/boundary-unit-finding.d.ts.map +1 -0
- package/dist/evaluate/boundary-unit-finding.js +21 -0
- package/dist/evaluate/boundary-unit-kind.d.ts +7 -0
- package/dist/evaluate/boundary-unit-kind.d.ts.map +1 -0
- package/dist/evaluate/boundary-unit-kind.js +14 -0
- package/dist/evaluate/evaluate-boundaries.d.ts +230 -3
- package/dist/evaluate/evaluate-boundaries.d.ts.map +1 -1
- package/dist/evaluate/evaluate-boundaries.js +481 -53
- package/dist/evaluate/i-boundary-rule-settle-input.d.ts +27 -0
- package/dist/evaluate/i-boundary-rule-settle-input.d.ts.map +1 -0
- package/dist/evaluate/i-boundary-rule-settle-input.js +1 -0
- package/dist/evaluate/i-boundary-rule-settlement.d.ts +23 -0
- package/dist/evaluate/i-boundary-rule-settlement.d.ts.map +1 -0
- package/dist/evaluate/i-boundary-rule-settlement.js +1 -0
- package/dist/evaluate/i-boundary-unit-finding.d.ts +22 -0
- package/dist/evaluate/i-boundary-unit-finding.d.ts.map +1 -0
- package/dist/evaluate/i-boundary-unit-finding.js +1 -0
- package/dist/evaluate/settle-boundary-rule.d.ts +23 -0
- package/dist/evaluate/settle-boundary-rule.d.ts.map +1 -0
- package/dist/evaluate/settle-boundary-rule.js +73 -0
- package/dist/evaluate/with-boundary-rule-settlement.d.ts +11 -0
- package/dist/evaluate/with-boundary-rule-settlement.d.ts.map +1 -0
- package/dist/evaluate/with-boundary-rule-settlement.js +44 -0
- package/dist/extract/code-zones.d.ts +95 -3
- package/dist/extract/code-zones.d.ts.map +1 -1
- package/dist/extract/code-zones.js +313 -4
- package/dist/extract/extract-tokens.d.ts +49 -1
- package/dist/extract/extract-tokens.d.ts.map +1 -1
- package/dist/extract/extract-tokens.js +283 -25
- package/dist/extract/i-labeled-source.d.ts +12 -0
- package/dist/extract/i-labeled-source.d.ts.map +1 -0
- package/dist/extract/i-labeled-source.js +1 -0
- package/dist/extract/import-edges.d.ts +50 -0
- package/dist/extract/import-edges.d.ts.map +1 -0
- package/dist/extract/import-edges.js +170 -0
- package/dist/extract/inspect-source.d.ts +38 -3
- package/dist/extract/inspect-source.d.ts.map +1 -1
- package/dist/extract/inspect-source.js +56 -8
- package/dist/extract/parse-imports.d.ts +80 -0
- package/dist/extract/parse-imports.d.ts.map +1 -0
- package/dist/extract/parse-imports.js +254 -0
- package/dist/extract/scan-literals.d.ts +12 -1
- package/dist/extract/scan-literals.d.ts.map +1 -1
- package/dist/extract/scan-literals.js +15 -1
- package/dist/extract/source-liveness-request.d.ts +24 -0
- package/dist/extract/source-liveness-request.d.ts.map +1 -0
- package/dist/extract/source-liveness-request.js +45 -0
- package/dist/generated/check-provenance.d.ts +20 -2
- package/dist/generated/check-provenance.d.ts.map +1 -1
- package/dist/generated/check-provenance.js +27 -6
- package/dist/generated/read-regen-tree.d.ts +16 -0
- package/dist/generated/read-regen-tree.d.ts.map +1 -0
- package/dist/generated/read-regen-tree.js +61 -0
- package/dist/generated/scan-generated.d.ts +57 -3
- package/dist/generated/scan-generated.d.ts.map +1 -1
- package/dist/generated/scan-generated.js +111 -11
- package/dist/index.d.ts +51 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +54 -0
- package/dist/model/boundary-intended-empty-line.d.ts +10 -0
- package/dist/model/boundary-intended-empty-line.d.ts.map +1 -0
- package/dist/model/boundary-intended-empty-line.js +11 -0
- package/dist/model/boundary-markable-list.d.ts +15 -0
- package/dist/model/boundary-markable-list.d.ts.map +1 -0
- package/dist/model/boundary-markable-list.js +15 -0
- package/dist/model/boundary-rule-input-keys.d.ts +11 -0
- package/dist/model/boundary-rule-input-keys.d.ts.map +1 -0
- package/dist/model/boundary-rule-input-keys.js +29 -0
- package/dist/model/boundary-rule-input.d.ts +23 -0
- package/dist/model/boundary-rule-input.d.ts.map +1 -0
- package/dist/model/boundary-rule-input.js +1 -0
- package/dist/model/boundary-rule-key-problems.d.ts +11 -0
- package/dist/model/boundary-rule-key-problems.d.ts.map +1 -0
- package/dist/model/boundary-rule-key-problems.js +36 -0
- package/dist/model/boundary-rule-marker-problems.d.ts +26 -0
- package/dist/model/boundary-rule-marker-problems.d.ts.map +1 -0
- package/dist/model/boundary-rule-marker-problems.js +94 -0
- package/dist/model/boundary-rule-scope.d.ts +88 -0
- package/dist/model/boundary-rule-scope.d.ts.map +1 -0
- package/dist/model/boundary-rule-scope.js +175 -0
- package/dist/model/boundary-rule.d.ts +120 -5
- package/dist/model/boundary-rule.d.ts.map +1 -1
- package/dist/model/boundary-rule.js +148 -1
- package/dist/model/boundary-unit-problem-issue.d.ts +9 -0
- package/dist/model/boundary-unit-problem-issue.d.ts.map +1 -0
- package/dist/model/boundary-unit-problem-issue.js +16 -0
- package/dist/model/normalize-boundary-rule.d.ts +21 -0
- package/dist/model/normalize-boundary-rule.d.ts.map +1 -0
- package/dist/model/normalize-boundary-rule.js +62 -0
- package/dist/policy/evaluate-policy.d.ts +80 -3
- package/dist/policy/evaluate-policy.d.ts.map +1 -1
- package/dist/policy/evaluate-policy.js +152 -19
- package/dist/policy/i-policy-rule-liveness.d.ts +15 -0
- package/dist/policy/i-policy-rule-liveness.d.ts.map +1 -0
- package/dist/policy/i-policy-rule-liveness.js +1 -0
- package/dist/policy/run-policy.d.ts +1 -1
- package/dist/policy/run-policy.d.ts.map +1 -1
- package/dist/policy/run-policy.js +171 -21
- package/dist/registry/load-boundary-rules.d.ts +29 -1
- package/dist/registry/load-boundary-rules.d.ts.map +1 -1
- package/dist/registry/load-boundary-rules.js +38 -8
- package/dist/scan/glob.d.ts +90 -0
- package/dist/scan/glob.d.ts.map +1 -1
- package/dist/scan/glob.js +205 -0
- package/dist/scan/i-glob-unit-measure.d.ts +22 -0
- package/dist/scan/i-glob-unit-measure.d.ts.map +1 -0
- package/dist/scan/i-glob-unit-measure.js +1 -0
- package/dist/scan/import-pattern.d.ts +109 -0
- package/dist/scan/import-pattern.d.ts.map +1 -0
- package/dist/scan/import-pattern.js +191 -0
- package/dist/scan/node-builtin-package-names.d.ts +13 -0
- package/dist/scan/node-builtin-package-names.d.ts.map +1 -0
- package/dist/scan/node-builtin-package-names.js +25 -0
- package/dist/scan/scan-imports.d.ts +36 -3
- package/dist/scan/scan-imports.d.ts.map +1 -1
- package/dist/scan/scan-imports.js +114 -45
- package/dist/util/blank-run-hazard-finding.d.ts +34 -0
- package/dist/util/blank-run-hazard-finding.d.ts.map +1 -0
- package/dist/util/blank-run-hazard-finding.js +1 -0
- package/dist/util/blank-run-hazard.d.ts +29 -0
- package/dist/util/blank-run-hazard.d.ts.map +1 -0
- package/dist/util/blank-run-hazard.js +450 -0
- package/dist/util/dead-glob-units.d.ts +46 -0
- package/dist/util/dead-glob-units.d.ts.map +1 -0
- package/dist/util/dead-glob-units.js +116 -0
- package/dist/util/glob-list-liveness-input.d.ts +31 -0
- package/dist/util/glob-list-liveness-input.d.ts.map +1 -0
- package/dist/util/glob-list-liveness-input.js +65 -0
- package/dist/util/i-dead-glob-unit.d.ts +24 -0
- package/dist/util/i-dead-glob-unit.d.ts.map +1 -0
- package/dist/util/i-dead-glob-unit.js +1 -0
- package/dist/util/i-glob-list-units.d.ts +25 -0
- package/dist/util/i-glob-list-units.d.ts.map +1 -0
- package/dist/util/i-glob-list-units.js +1 -0
- package/dist/util/i-glob-liveness-list.d.ts +23 -0
- package/dist/util/i-glob-liveness-list.d.ts.map +1 -0
- package/dist/util/i-glob-liveness-list.js +1 -0
- package/dist/util/i-glob-liveness-request.d.ts +11 -0
- package/dist/util/i-glob-liveness-request.d.ts.map +1 -0
- package/dist/util/i-glob-liveness-request.js +1 -0
- package/dist/util/i-glob-negation.d.ts +13 -0
- package/dist/util/i-glob-negation.d.ts.map +1 -0
- package/dist/util/i-glob-negation.js +1 -0
- package/dist/util/matched-files.d.ts +22 -0
- package/dist/util/matched-files.d.ts.map +1 -0
- package/dist/util/matched-files.js +1 -0
- package/dist/util/negation-cause.d.ts +15 -0
- package/dist/util/negation-cause.d.ts.map +1 -0
- package/dist/util/negation-cause.js +21 -0
- package/dist/util/plane-scan-exclude-dirs.d.ts +17 -0
- package/dist/util/plane-scan-exclude-dirs.d.ts.map +1 -0
- package/dist/util/plane-scan-exclude-dirs.js +22 -0
- package/dist/util/read-glob-list-liveness.d.ts +20 -0
- package/dist/util/read-glob-list-liveness.d.ts.map +1 -0
- package/dist/util/read-glob-list-liveness.js +20 -0
- package/dist/util/read-scope-coverage.d.ts +90 -0
- package/dist/util/read-scope-coverage.d.ts.map +1 -0
- package/dist/util/read-scope-coverage.js +173 -0
- package/dist/util/read-scope.d.ts +14 -0
- package/dist/util/read-scope.d.ts.map +1 -0
- package/dist/util/read-scope.js +1 -0
- package/dist/util/read-selected-files.d.ts +16 -0
- package/dist/util/read-selected-files.d.ts.map +1 -0
- package/dist/util/read-selected-files.js +25 -0
- package/dist/util/settle-glob-lists.d.ts +12 -0
- package/dist/util/settle-glob-lists.d.ts.map +1 -0
- package/dist/util/settle-glob-lists.js +13 -0
- package/dist/util/unread-file-reason.d.ts +26 -0
- package/dist/util/unread-file-reason.d.ts.map +1 -0
- package/dist/util/unread-file-reason.js +26 -0
- package/dist/util/unread-file.d.ts +10 -0
- package/dist/util/unread-file.d.ts.map +1 -0
- package/dist/util/unread-file.js +1 -0
- package/dist/util/walk-files.d.ts +90 -7
- package/dist/util/walk-files.d.ts.map +1 -1
- package/dist/util/walk-files.js +206 -19
- package/dist/wiring/evaluate-wiring.d.ts +88 -7
- package/dist/wiring/evaluate-wiring.d.ts.map +1 -1
- package/dist/wiring/evaluate-wiring.js +276 -16
- package/dist/wiring/explain-wiring.d.ts +56 -14
- package/dist/wiring/explain-wiring.d.ts.map +1 -1
- package/dist/wiring/explain-wiring.js +136 -10
- package/dist/wiring/i-idiom-role-coverage.d.ts +24 -0
- package/dist/wiring/i-idiom-role-coverage.d.ts.map +1 -0
- package/dist/wiring/i-idiom-role-coverage.js +1 -0
- package/dist/wiring/i-registration-query-verdict.d.ts +38 -0
- package/dist/wiring/i-registration-query-verdict.d.ts.map +1 -0
- package/dist/wiring/i-registration-query-verdict.js +1 -0
- package/dist/wiring/i-registration-roles.d.ts +71 -0
- package/dist/wiring/i-registration-roles.d.ts.map +1 -0
- package/dist/wiring/i-registration-roles.js +1 -0
- package/dist/wiring/measure-idiom-role-coverage.d.ts +12 -0
- package/dist/wiring/measure-idiom-role-coverage.d.ts.map +1 -0
- package/dist/wiring/measure-idiom-role-coverage.js +20 -0
- package/dist/wiring/measure-registration-roles.d.ts +25 -0
- package/dist/wiring/measure-registration-roles.d.ts.map +1 -0
- package/dist/wiring/measure-registration-roles.js +124 -0
- package/dist/wiring/plan-wiring-fix.d.ts +16 -1
- package/dist/wiring/plan-wiring-fix.d.ts.map +1 -1
- package/dist/wiring/plan-wiring-fix.js +177 -4
- package/dist/wiring/registration-graph.d.ts +13 -1
- package/dist/wiring/registration-graph.d.ts.map +1 -1
- package/dist/wiring/registration-graph.js +22 -6
- package/dist/wiring/registration-query-verdict.d.ts +23 -0
- package/dist/wiring/registration-query-verdict.d.ts.map +1 -0
- package/dist/wiring/registration-query-verdict.js +118 -0
- package/dist/wiring/registry-query.d.ts +9 -1
- package/dist/wiring/registry-query.d.ts.map +1 -1
- package/dist/wiring/registry-query.js +17 -6
- package/dist/wiring/scan-wiring-files.d.ts +5 -3
- package/dist/wiring/scan-wiring-files.d.ts.map +1 -1
- package/dist/wiring/scan-wiring-files.js +55 -14
- package/dist/wiring/sink-imports.d.ts +95 -0
- package/dist/wiring/sink-imports.d.ts.map +1 -0
- package/dist/wiring/sink-imports.js +124 -0
- package/dist/wiring/trace-literal.d.ts +6 -0
- package/dist/wiring/trace-literal.d.ts.map +1 -1
- package/dist/wiring/trace-literal.js +5 -2
- package/dist/wiring/wiring-labeled-sources.d.ts +12 -0
- package/dist/wiring/wiring-labeled-sources.d.ts.map +1 -0
- package/dist/wiring/wiring-labeled-sources.js +20 -0
- package/package.json +2 -2
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type IWiringSource } from '@shrkcrft/core';
|
|
2
|
+
import type { ITsconfigPathsMap } from '../scan/tsconfig-aliases.js';
|
|
2
3
|
/** A file made available to an extractor. */
|
|
3
4
|
export interface IExtractFileEntry {
|
|
4
5
|
/** Project-relative POSIX path. */
|
|
@@ -11,11 +12,37 @@ export interface IExtractedSite {
|
|
|
11
12
|
readonly file: string;
|
|
12
13
|
readonly line: number;
|
|
13
14
|
}
|
|
15
|
+
/**
|
|
16
|
+
* Optional project context an extractor may need.
|
|
17
|
+
*
|
|
18
|
+
* Kept OUT of the source spec because it is not part of the rule — it is what
|
|
19
|
+
* the caller knows about the workspace. Only `import-edges` reads it today, and
|
|
20
|
+
* every other kind stays a pure function of (source, file contents).
|
|
21
|
+
*/
|
|
22
|
+
export interface IExtractContext {
|
|
23
|
+
/** tsconfig `paths` map, so alias specifiers resolve as the compiler would. */
|
|
24
|
+
readonly tsconfigPaths?: ITsconfigPathsMap;
|
|
25
|
+
}
|
|
14
26
|
/** Outcome of running one source: the sites, or a configuration error. */
|
|
15
27
|
export interface IExtractResult {
|
|
16
28
|
readonly sites: readonly IExtractedSite[];
|
|
29
|
+
/**
|
|
30
|
+
* How many characters a non-`all` `scan` zone blanked before extraction.
|
|
31
|
+
*
|
|
32
|
+
* Surfaced (not merely applied) because a zone is the one setting that can
|
|
33
|
+
* make a rule match LESS while still reading green: an author who sees the
|
|
34
|
+
* number drop can tell "my pattern was matching prose" from "my glob went
|
|
35
|
+
* stale". `explain` prints it.
|
|
36
|
+
*/
|
|
37
|
+
readonly blankedChars?: number;
|
|
17
38
|
/** Set when the SOURCE is misconfigured (never thrown — rules degrade). */
|
|
18
39
|
readonly error?: string;
|
|
40
|
+
/**
|
|
41
|
+
* A diagnosis for a zero-match that is CORRECT but almost certainly not what
|
|
42
|
+
* the author meant. Distinct from `error`: nothing is wrong with the source,
|
|
43
|
+
* it just cannot mean what it looks like it means.
|
|
44
|
+
*/
|
|
45
|
+
readonly hint?: string;
|
|
19
46
|
}
|
|
20
47
|
/**
|
|
21
48
|
* Run one source's extractor over the given files.
|
|
@@ -26,5 +53,26 @@ export interface IExtractResult {
|
|
|
26
53
|
* new extractor kind for free). Never throws — a misconfigured source returns
|
|
27
54
|
* an `error` and no sites.
|
|
28
55
|
*/
|
|
29
|
-
export declare function extractTokens(source: IWiringSource, files: readonly IExtractFileEntry[]): IExtractResult;
|
|
56
|
+
export declare function extractTokens(source: IWiringSource, files: readonly IExtractFileEntry[], context?: IExtractContext): IExtractResult;
|
|
57
|
+
/**
|
|
58
|
+
* Wall-clock cap for ONE file's `regex-capture` pass under a non-`all` scan
|
|
59
|
+
* zone. Checked between matches; a file that trips it contributes nothing and
|
|
60
|
+
* is NAMED (the source errors), so a partial token set can never read green.
|
|
61
|
+
*/
|
|
62
|
+
export declare const ZONED_REGEX_FILE_BUDGET_MS = 1000;
|
|
63
|
+
/**
|
|
64
|
+
* The head regexes the anchor-based extractors run — possibly on a blanked
|
|
65
|
+
* buffer. One factory, so the linearity lock (`r75-blank-run-linearity`)
|
|
66
|
+
* times and lints the exact patterns that run, not copies of them.
|
|
67
|
+
*/
|
|
68
|
+
export declare function extractorHeadPatterns(anchor: string): {
|
|
69
|
+
readonly arrayLiteral: RegExp;
|
|
70
|
+
readonly objectLiteral: RegExp;
|
|
71
|
+
readonly enumBody: RegExp;
|
|
72
|
+
readonly call: RegExp;
|
|
73
|
+
readonly decorator: RegExp;
|
|
74
|
+
readonly stringUnion: RegExp;
|
|
75
|
+
readonly exportDecl: RegExp;
|
|
76
|
+
readonly exportClause: RegExp;
|
|
77
|
+
};
|
|
30
78
|
//# sourceMappingURL=extract-tokens.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extract-tokens.d.ts","sourceRoot":"","sources":["../../src/extract/extract-tokens.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,aAAa,EACnB,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"extract-tokens.d.ts","sourceRoot":"","sources":["../../src/extract/extract-tokens.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,aAAa,EACnB,MAAM,gBAAgB,CAAC;AAMxB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AASrE,6CAA6C;AAC7C,MAAM,WAAW,iBAAiB;IAChC,mCAAmC;IACnC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,6CAA6C;AAC7C,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,eAAe;IAC9B,+EAA+E;IAC/E,QAAQ,CAAC,aAAa,CAAC,EAAE,iBAAiB,CAAC;CAC5C;AAED,0EAA0E;AAC1E,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,KAAK,EAAE,SAAS,cAAc,EAAE,CAAC;IAC1C;;;;;;;OAOG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,2EAA2E;IAC3E,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB;;;;OAIG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,aAAa,EACrB,KAAK,EAAE,SAAS,iBAAiB,EAAE,EACnC,OAAO,GAAE,eAAoB,GAC5B,cAAc,CAiHhB;AA+CD;;;;GAIG;AACH,eAAO,MAAM,0BAA0B,OAAO,CAAC;AAmN/C;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG;IACrD,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B,CAgBA"}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { resolveExtractorAnchor, resolveExtractorKind, validateWiringSource, } from '@shrkcrft/core';
|
|
2
2
|
import { safeCompile } from "../util/safe-regex.js";
|
|
3
|
+
import { findBlankRunHazards } from "../util/blank-run-hazard.js";
|
|
4
|
+
import { blankOutsideZone } from "./code-zones.js";
|
|
5
|
+
import { extractImportEdges } from "./import-edges.js";
|
|
3
6
|
import { elementToken, elementValue, escapeRegex, lineOf, scanBalanced, } from "./scan-literals.js";
|
|
4
7
|
/**
|
|
5
8
|
* Run one source's extractor over the given files.
|
|
@@ -10,41 +13,94 @@ import { elementToken, elementValue, escapeRegex, lineOf, scanBalanced, } from "
|
|
|
10
13
|
* new extractor kind for free). Never throws — a misconfigured source returns
|
|
11
14
|
* an `error` and no sites.
|
|
12
15
|
*/
|
|
13
|
-
export function extractTokens(source, files) {
|
|
16
|
+
export function extractTokens(source, files, context = {}) {
|
|
14
17
|
const error = validateWiringSource(source);
|
|
15
18
|
if (error)
|
|
16
19
|
return { sites: [], error };
|
|
17
20
|
const kind = resolveExtractorKind(source);
|
|
18
21
|
const anchor = resolveExtractorAnchor(source);
|
|
22
|
+
// Zone the CONTENT once, up front, instead of teaching every extractor about
|
|
23
|
+
// comments. Blanking preserves length and newlines, so each extractor still
|
|
24
|
+
// reports the true `file:line` and none of them needs zone logic of its own.
|
|
25
|
+
const zone = source.scan ?? 'all';
|
|
26
|
+
let blankedChars = 0;
|
|
27
|
+
// `import-edges` zones itself (round 11, 6.1a#import-edges-scan): it judges a
|
|
28
|
+
// statement by where its KEYWORD starts, through the one import parser.
|
|
29
|
+
// Pre-blanking here erased every specifier (a string) under `scan: 'code'`,
|
|
30
|
+
// and the rule silently extracted nothing.
|
|
31
|
+
const scanned = zone === 'all' || kind === 'import-edges'
|
|
32
|
+
? files
|
|
33
|
+
: files.map((f) => {
|
|
34
|
+
const blanked = blankOutsideZone(f.content, zone);
|
|
35
|
+
blankedChars += blanked.blankedChars;
|
|
36
|
+
return { path: f.path, content: blanked.content };
|
|
37
|
+
});
|
|
19
38
|
let sites;
|
|
39
|
+
// A user pattern run on a BLANKED buffer can backtrack O(run²) on the
|
|
40
|
+
// whitespace runs the zone manufactures. Lint it (the hint reaches `gates
|
|
41
|
+
// coverage` / `explain`), and bound each file: a file over budget is a
|
|
42
|
+
// named, loud skip — the rule errors, never a silent partial.
|
|
43
|
+
let regexHint;
|
|
20
44
|
switch (kind) {
|
|
21
|
-
case 'regex-capture':
|
|
22
|
-
|
|
45
|
+
case 'regex-capture': {
|
|
46
|
+
const zoned = zone !== 'all';
|
|
47
|
+
const hazards = zoned ? findBlankRunHazards(source.pattern) : [];
|
|
48
|
+
if (hazards.length > 0)
|
|
49
|
+
regexHint = blankRunHazardHint(zone, hazards);
|
|
50
|
+
const run = byRegex(source, scanned, zoned, hazards);
|
|
51
|
+
if (run.predicted.length + run.ran.length > 0) {
|
|
52
|
+
return {
|
|
53
|
+
sites: [],
|
|
54
|
+
error: zonedOverBudgetError(zone, run, hazards),
|
|
55
|
+
...(regexHint ? { hint: regexHint } : {}),
|
|
56
|
+
...zoneMeta(zone, blankedChars),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
sites = run.sites;
|
|
23
60
|
break;
|
|
61
|
+
}
|
|
24
62
|
case 'array-members':
|
|
25
|
-
sites = byBracketLiteral(anchor, '[',
|
|
63
|
+
sites = byBracketLiteral(anchor, '[', scanned, (el) => elementToken(el));
|
|
26
64
|
break;
|
|
27
65
|
case 'object-keys':
|
|
28
|
-
sites = byBracketLiteral(anchor, '{',
|
|
66
|
+
sites = byBracketLiteral(anchor, '{', scanned, (el) => source.capture === 'value' ? elementValue(el) : elementToken(el));
|
|
29
67
|
break;
|
|
30
68
|
case 'enum-members':
|
|
31
|
-
sites = byEnumMembers(anchor, source.capture === 'value',
|
|
69
|
+
sites = byEnumMembers(anchor, source.capture === 'value', scanned);
|
|
32
70
|
break;
|
|
33
71
|
case 'export-names':
|
|
34
|
-
sites = byExportNames(
|
|
72
|
+
sites = byExportNames(scanned);
|
|
35
73
|
break;
|
|
36
74
|
case 'call-args':
|
|
37
|
-
sites = byCallArgs(anchor, source.argIndex ?? 0, false,
|
|
75
|
+
sites = byCallArgs(anchor, source.argIndex ?? 0, false, scanned);
|
|
38
76
|
break;
|
|
39
77
|
case 'decorator-args':
|
|
40
|
-
sites = byCallArgs(anchor, source.argIndex ?? 0, true,
|
|
78
|
+
sites = byCallArgs(anchor, source.argIndex ?? 0, true, scanned);
|
|
41
79
|
break;
|
|
42
80
|
case 'string-union-members':
|
|
43
|
-
sites = byStringUnion(anchor,
|
|
81
|
+
sites = byStringUnion(anchor, scanned);
|
|
44
82
|
break;
|
|
45
83
|
case 'json-path':
|
|
46
|
-
sites = byJsonPath(source.jsonPath,
|
|
84
|
+
sites = byJsonPath(source.jsonPath, scanned);
|
|
85
|
+
break;
|
|
86
|
+
case 'filenames':
|
|
87
|
+
sites = byFilenames(source, scanned);
|
|
88
|
+
break;
|
|
89
|
+
case 'import-edges': {
|
|
90
|
+
const edges = extractImportEdges(source, scanned, {
|
|
91
|
+
...(context.tsconfigPaths ? { tsconfigPaths: context.tsconfigPaths } : {}),
|
|
92
|
+
});
|
|
93
|
+
if (edges.error)
|
|
94
|
+
return { sites: [], error: edges.error };
|
|
95
|
+
// It zones itself, so what its zone blanked is its own figure — the
|
|
96
|
+
// `scan: code (N chars blanked)` note must not read 0 over a zone that
|
|
97
|
+
// dropped a commented-out edge.
|
|
98
|
+
blankedChars += edges.blankedChars ?? 0;
|
|
99
|
+
if (edges.hint)
|
|
100
|
+
return { sites: edges.sites, hint: edges.hint, ...zoneMeta(zone, blankedChars) };
|
|
101
|
+
sites = edges.sites;
|
|
47
102
|
break;
|
|
103
|
+
}
|
|
48
104
|
default:
|
|
49
105
|
return { sites: [], error: `unknown extract kind "${String(kind)}"` };
|
|
50
106
|
}
|
|
@@ -66,15 +122,187 @@ export function extractTokens(source, files) {
|
|
|
66
122
|
});
|
|
67
123
|
}
|
|
68
124
|
}
|
|
69
|
-
return { sites };
|
|
125
|
+
return { sites, ...zoneMeta(zone, blankedChars), ...(regexHint ? { hint: regexHint } : {}) };
|
|
126
|
+
}
|
|
127
|
+
/** The zone provenance to attach to a result — omitted entirely when unzoned. */
|
|
128
|
+
function zoneMeta(zone, blankedChars) {
|
|
129
|
+
return zone === 'all' ? {} : { blankedChars };
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* One id per FILE, derived from its path.
|
|
133
|
+
*
|
|
134
|
+
* Every other extractor reads a file's CONTENTS, so "a declared thing must have
|
|
135
|
+
* its sibling FILE" — a `FOO_DESCRIPTOR` const paired with `FOO_DESCRIPTOR.ts` —
|
|
136
|
+
* had no expression at all. Paired with a `parity` wiring rule this asserts the
|
|
137
|
+
* correspondence in BOTH directions: a const with no file, and a file with no
|
|
138
|
+
* const.
|
|
139
|
+
*
|
|
140
|
+
* The site line is 1: the id comes from the path, not from any line in it, and
|
|
141
|
+
* claiming a more specific location would be inventing one.
|
|
142
|
+
*/
|
|
143
|
+
function byFilenames(source, files) {
|
|
144
|
+
const capture = source.capturePath ?? 'stem';
|
|
145
|
+
let re;
|
|
146
|
+
if (capture === 'regex') {
|
|
147
|
+
const compiled = safeCompile(source.pathPattern, source.pathPatternFlags);
|
|
148
|
+
if (!compiled.re)
|
|
149
|
+
return [];
|
|
150
|
+
re = compiled.re;
|
|
151
|
+
}
|
|
152
|
+
const sites = [];
|
|
153
|
+
for (const file of files) {
|
|
154
|
+
if (capture === 'regex') {
|
|
155
|
+
re.lastIndex = 0;
|
|
156
|
+
const m = re.exec(file.path);
|
|
157
|
+
if (m?.[1])
|
|
158
|
+
sites.push({ token: m[1], file: file.path, line: 1 });
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
const basename = file.path.slice(file.path.lastIndexOf('/') + 1);
|
|
162
|
+
const dot = basename.indexOf('.');
|
|
163
|
+
const token = capture === 'basename' || dot <= 0 ? basename : basename.slice(0, dot);
|
|
164
|
+
sites.push({ token, file: file.path, line: 1 });
|
|
165
|
+
}
|
|
166
|
+
return sites;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Wall-clock cap for ONE file's `regex-capture` pass under a non-`all` scan
|
|
170
|
+
* zone. Checked between matches; a file that trips it contributes nothing and
|
|
171
|
+
* is NAMED (the source errors), so a partial token set can never read green.
|
|
172
|
+
*/
|
|
173
|
+
export const ZONED_REGEX_FILE_BUDGET_MS = 1000;
|
|
174
|
+
/**
|
|
175
|
+
* For a pattern the blank-run lint flags: a file whose PREDICTED backtracking
|
|
176
|
+
* work (priced by each hazard's reach, below) exceeds this is skipped BEFORE
|
|
177
|
+
* the regex runs. One `exec` over such a buffer cannot be interrupted (a
|
|
178
|
+
* 16 KB newline-crossing run already costs ~300–470 ms), so the prediction is
|
|
179
|
+
* what makes the cap a real bound.
|
|
180
|
+
*/
|
|
181
|
+
const ZONED_HAZARD_COST_LIMIT = 2e8;
|
|
182
|
+
/** Blank stretches shorter than this are ordinary indentation — not worth pricing. */
|
|
183
|
+
const MIN_PRICED_RUN = 64;
|
|
184
|
+
function blankRunCosts(content) {
|
|
185
|
+
let run = 0;
|
|
186
|
+
let segment = 0;
|
|
187
|
+
let newlines = 0;
|
|
188
|
+
let runCost = 0;
|
|
189
|
+
let lineCost = 0;
|
|
190
|
+
let linesTimesRun = 0;
|
|
191
|
+
for (let i = 0; i <= content.length; i += 1) {
|
|
192
|
+
const c = i < content.length ? content.charCodeAt(i) : 0;
|
|
193
|
+
if (c === 0x20) {
|
|
194
|
+
run += 1;
|
|
195
|
+
segment += 1;
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
if (segment >= MIN_PRICED_RUN)
|
|
199
|
+
lineCost += segment * segment;
|
|
200
|
+
segment = 0;
|
|
201
|
+
if (c === 0x0a) {
|
|
202
|
+
run += 1;
|
|
203
|
+
newlines += 1;
|
|
204
|
+
continue;
|
|
205
|
+
}
|
|
206
|
+
if (run >= MIN_PRICED_RUN) {
|
|
207
|
+
runCost += run * run;
|
|
208
|
+
linesTimesRun += (newlines + 1) * run;
|
|
209
|
+
}
|
|
210
|
+
run = 0;
|
|
211
|
+
newlines = 0;
|
|
212
|
+
}
|
|
213
|
+
return { run: runCost, line: lineCost, linesTimesRun };
|
|
70
214
|
}
|
|
71
|
-
/**
|
|
72
|
-
function
|
|
215
|
+
/** Price every flagged hazard by its OWN reach; the file costs what its worst hazard costs. */
|
|
216
|
+
function predictedHazardCost(hazards, costs) {
|
|
217
|
+
let worst = { cost: 0, measure: 'Σ run²' };
|
|
218
|
+
for (const h of hazards) {
|
|
219
|
+
const priced = !h.crossesNewline
|
|
220
|
+
? { cost: costs.line, measure: 'Σ line-run²' }
|
|
221
|
+
: h.shape === 'leading' && h.fromLineStart
|
|
222
|
+
? { cost: costs.linesTimesRun, measure: 'Σ lines×run' }
|
|
223
|
+
: { cost: costs.run, measure: 'Σ run²' };
|
|
224
|
+
if (priced.cost > worst.cost)
|
|
225
|
+
worst = priced;
|
|
226
|
+
}
|
|
227
|
+
return worst;
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* The remedy for each hazard shape present. A LEADING quantifier is fixed by
|
|
231
|
+
* a literal anchor — never by another quantifier: a leading `[ \t]*` is still
|
|
232
|
+
* tried at every offset of a blanked line.
|
|
233
|
+
*/
|
|
234
|
+
function hazardRemedy(hazards) {
|
|
235
|
+
const remedies = [];
|
|
236
|
+
if (hazards.some((h) => h.shape === 'leading')) {
|
|
237
|
+
remedies.push('anchor the alternative on a literal — begin it with the token the whitespace precedes ' +
|
|
238
|
+
'(`foo[ \\t]*\\(`, not `[ \\t]*foo\\(`), since a leading whitespace quantifier of any class is tried at every offset');
|
|
239
|
+
}
|
|
240
|
+
if (hazards.some((h) => h.shape === 'adjacent')) {
|
|
241
|
+
remedies.push('collapse the touching whitespace quantifiers into one');
|
|
242
|
+
}
|
|
243
|
+
return remedies.join('; ');
|
|
244
|
+
}
|
|
245
|
+
/** The hint a hazardous user pattern earns under a zone — surfaced through `gates coverage` / `explain`. */
|
|
246
|
+
function blankRunHazardHint(zone, hazards) {
|
|
247
|
+
const h = hazards[0];
|
|
248
|
+
const reach = hazards.every((x) => !x.crossesNewline)
|
|
249
|
+
? ' It stops at each newline, so only a very long blanked line is costly.'
|
|
250
|
+
: '';
|
|
251
|
+
return (`pattern backtracking hazard under scan: '${zone}': ${h.message}. Blanked comments and strings become ` +
|
|
252
|
+
`long whitespace runs; ${hazardRemedy(hazards)} (or scan: 'all').${reach}`);
|
|
253
|
+
}
|
|
254
|
+
function namedFiles(files) {
|
|
255
|
+
return files.slice(0, 5).join(', ') + (files.length > 5 ? `, … (+${files.length - 5} more)` : '');
|
|
256
|
+
}
|
|
257
|
+
function formatCost(n) {
|
|
258
|
+
return n.toExponential(1).replace('e+', 'e');
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* The error for files a zoned `regex-capture` could not judge — loud, named,
|
|
262
|
+
* never a silent partial. The two causes are worded apart: a PREDICTED skip
|
|
263
|
+
* never ran the regex (so it spent nothing), a STOPPED file ran past the cap.
|
|
264
|
+
*/
|
|
265
|
+
function zonedOverBudgetError(zone, run, hazards) {
|
|
266
|
+
const parts = [];
|
|
267
|
+
if (run.predicted.length > 0) {
|
|
268
|
+
const worst = run.predicted.reduce((a, b) => (b.cost > a.cost ? b : a));
|
|
269
|
+
parts.push(`predicted over budget, so the regex was never run (${worst.measure} = ${formatCost(worst.cost)} > ` +
|
|
270
|
+
`${formatCost(ZONED_HAZARD_COST_LIMIT)}): ${namedFiles(run.predicted.map((p) => p.path))}`);
|
|
271
|
+
}
|
|
272
|
+
if (run.ran.length > 0) {
|
|
273
|
+
parts.push(`ran past the ${ZONED_REGEX_FILE_BUDGET_MS} ms per-file cap and was stopped: ${namedFiles(run.ran)}`);
|
|
274
|
+
}
|
|
275
|
+
const total = run.predicted.length + run.ran.length;
|
|
276
|
+
const why = hazards.length > 0 ? ` — ${hazards[0].message}` : '';
|
|
277
|
+
const fix = hazards.length > 0 ? hazardRemedy(hazards) : 'simplify the pattern';
|
|
278
|
+
return (`regex-capture under scan: '${zone}' skipped ${total} file(s): over budget — ${parts.join('; ')}${why}. ` +
|
|
279
|
+
`${fix.charAt(0).toUpperCase()}${fix.slice(1)}, or use scan: 'all'.`);
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Capture-group-1 of a pattern, per file. Under a zone (`zoned`), each file is
|
|
283
|
+
* bounded: a FLAGGED pattern skips a file whose predicted work — each hazard
|
|
284
|
+
* priced by its own reach, so a line-bounded one pays per line — is over the
|
|
285
|
+
* limit, and any pattern stops a file that runs past the per-file budget.
|
|
286
|
+
* Both are named, never a quietly smaller token set.
|
|
287
|
+
*/
|
|
288
|
+
function byRegex(source, files, zoned, hazards) {
|
|
73
289
|
const { re } = safeCompile(source.pattern, source.flags);
|
|
74
290
|
if (!re)
|
|
75
|
-
return [];
|
|
291
|
+
return { sites: [], predicted: [], ran: [] };
|
|
76
292
|
const sites = [];
|
|
293
|
+
const predicted = [];
|
|
294
|
+
const ran = [];
|
|
77
295
|
for (const f of files) {
|
|
296
|
+
if (zoned && hazards.length > 0) {
|
|
297
|
+
const p = predictedHazardCost(hazards, blankRunCosts(f.content));
|
|
298
|
+
if (p.cost > ZONED_HAZARD_COST_LIMIT) {
|
|
299
|
+
predicted.push({ path: f.path, ...p });
|
|
300
|
+
continue;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
const startedAt = Date.now();
|
|
304
|
+
const fileSites = [];
|
|
305
|
+
let over = false;
|
|
78
306
|
re.lastIndex = 0;
|
|
79
307
|
let m;
|
|
80
308
|
while ((m = re.exec(f.content)) !== null) {
|
|
@@ -82,12 +310,42 @@ function byRegex(source, files) {
|
|
|
82
310
|
if (m.index === re.lastIndex)
|
|
83
311
|
re.lastIndex += 1;
|
|
84
312
|
const token = m[1];
|
|
85
|
-
if (token
|
|
86
|
-
|
|
87
|
-
|
|
313
|
+
if (token !== undefined && token !== '') {
|
|
314
|
+
fileSites.push({ token, file: f.path, line: lineOf(f.content, m.index) });
|
|
315
|
+
}
|
|
316
|
+
if (zoned && Date.now() - startedAt > ZONED_REGEX_FILE_BUDGET_MS) {
|
|
317
|
+
over = true;
|
|
318
|
+
break;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
if (over) {
|
|
322
|
+
ran.push(f.path);
|
|
323
|
+
continue;
|
|
88
324
|
}
|
|
325
|
+
sites.push(...fileSites);
|
|
89
326
|
}
|
|
90
|
-
return sites;
|
|
327
|
+
return { sites, predicted, ran };
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* The head regexes the anchor-based extractors run — possibly on a blanked
|
|
331
|
+
* buffer. One factory, so the linearity lock (`r75-blank-run-linearity`)
|
|
332
|
+
* times and lints the exact patterns that run, not copies of them.
|
|
333
|
+
*/
|
|
334
|
+
export function extractorHeadPatterns(anchor) {
|
|
335
|
+
const a = escapeRegex(anchor);
|
|
336
|
+
const literalHead = (open) => new RegExp(`(?<![\\w$])${a}\\s*(?::[^=\\n]*)?[:=]\\s*(?:[A-Za-z_$][\\w$.]*\\s*\\(\\s*)?\\${open}`, 'g');
|
|
337
|
+
return {
|
|
338
|
+
arrayLiteral: literalHead('['),
|
|
339
|
+
objectLiteral: literalHead('{'),
|
|
340
|
+
enumBody: new RegExp(`\\benum\\s+${a}\\s*\\{`, 'g'),
|
|
341
|
+
call: new RegExp(`(?<![\\w$.@])${a}\\s*\\(`, 'g'),
|
|
342
|
+
decorator: new RegExp(`@${a}\\s*\\(`, 'g'),
|
|
343
|
+
// Collapsed from `\s*(?:<[^>]*>)?\s*=`: two whitespace quantifiers with
|
|
344
|
+
// only an optional group between them re-partition a blank run.
|
|
345
|
+
stringUnion: new RegExp(`\\btype\\s+${a}\\s*(?:<[^>]*>\\s*)?=`, 'g'),
|
|
346
|
+
exportDecl: EXPORT_DECL,
|
|
347
|
+
exportClause: EXPORT_CLAUSE,
|
|
348
|
+
};
|
|
91
349
|
}
|
|
92
350
|
/**
|
|
93
351
|
* Elements of every `<anchor> = <open> … ` / `<anchor>: <open> … ` literal.
|
|
@@ -99,7 +357,8 @@ function byRegex(source, files) {
|
|
|
99
357
|
*/
|
|
100
358
|
function byBracketLiteral(anchor, open, files, tokenOf) {
|
|
101
359
|
const sites = [];
|
|
102
|
-
const
|
|
360
|
+
const heads = extractorHeadPatterns(anchor);
|
|
361
|
+
const head = open === '[' ? heads.arrayLiteral : heads.objectLiteral;
|
|
103
362
|
for (const f of files) {
|
|
104
363
|
head.lastIndex = 0;
|
|
105
364
|
let m;
|
|
@@ -122,7 +381,7 @@ function byBracketLiteral(anchor, open, files, tokenOf) {
|
|
|
122
381
|
/** Members of `enum <anchor> { … }` — the member name, or its assigned value. */
|
|
123
382
|
function byEnumMembers(anchor, wantValue, files) {
|
|
124
383
|
const sites = [];
|
|
125
|
-
const head =
|
|
384
|
+
const head = extractorHeadPatterns(anchor).enumBody;
|
|
126
385
|
for (const f of files) {
|
|
127
386
|
head.lastIndex = 0;
|
|
128
387
|
let m;
|
|
@@ -173,9 +432,8 @@ function byExportNames(files) {
|
|
|
173
432
|
/** Argument `argIndex` of every `anchor(…)` call — or `@anchor(…)` decorator. */
|
|
174
433
|
function byCallArgs(anchor, argIndex, decorator, files) {
|
|
175
434
|
const sites = [];
|
|
176
|
-
const
|
|
177
|
-
|
|
178
|
-
: new RegExp(`(?<![\\w$.@])${escapeRegex(anchor)}\\s*\\(`, 'g');
|
|
435
|
+
const heads = extractorHeadPatterns(anchor);
|
|
436
|
+
const head = decorator ? heads.decorator : heads.call;
|
|
179
437
|
for (const f of files) {
|
|
180
438
|
head.lastIndex = 0;
|
|
181
439
|
let m;
|
|
@@ -199,7 +457,7 @@ function byCallArgs(anchor, argIndex, decorator, files) {
|
|
|
199
457
|
/** The string literals of `type <anchor> = 'a' | 'b' | 'c'`. */
|
|
200
458
|
function byStringUnion(anchor, files) {
|
|
201
459
|
const sites = [];
|
|
202
|
-
const head =
|
|
460
|
+
const head = extractorHeadPatterns(anchor).stringUnion;
|
|
203
461
|
const member = /['"`]([^'"`]+)['"`]/g;
|
|
204
462
|
for (const f of files) {
|
|
205
463
|
head.lastIndex = 0;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { IWiringSource } from '@shrkcrft/core';
|
|
2
|
+
/**
|
|
3
|
+
* One extraction source of a gate rule, named by the side it plays —
|
|
4
|
+
* `declared`, `registered[1]`, `chain[0]`, `source`, `consumer`, a role, or
|
|
5
|
+
* `compute.source`. The label qualifies the source's marker lists
|
|
6
|
+
* (`declared.files`) and prefixes its units in a multi-source report.
|
|
7
|
+
*/
|
|
8
|
+
export interface ILabeledSource {
|
|
9
|
+
readonly label: string;
|
|
10
|
+
readonly source: IWiringSource;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=i-labeled-source.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"i-labeled-source.d.ts","sourceRoot":"","sources":["../../src/extract/i-labeled-source.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEpD;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;CAChC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { IWiringSource } from '@shrkcrft/core';
|
|
2
|
+
import { type ITsconfigPathsMap } from '../scan/tsconfig-aliases.js';
|
|
3
|
+
import type { IExtractFileEntry, IExtractedSite } from './extract-tokens.js';
|
|
4
|
+
/**
|
|
5
|
+
* The `import-edges` extractor — the dependency graph as a rule input.
|
|
6
|
+
*
|
|
7
|
+
* Every other extractor reads file CONTENTS: a regex, an array literal, an enum
|
|
8
|
+
* body, an export list. None of them can see which file imports what, so an
|
|
9
|
+
* entire class of invariant — alias-resolved dependency direction — was
|
|
10
|
+
* inexpressible as a rule, and repos hand-rolled scripts for it (adoption
|
|
11
|
+
* ledgers, orphan scans, deprecation ratchets).
|
|
12
|
+
*
|
|
13
|
+
* This emits that missing fact as an id set, so every existing plane gets it for
|
|
14
|
+
* free: a `baseline` over the set is an adoption ledger (a LOST edge is a silent
|
|
15
|
+
* de-adoption); `direction: 'no-shrink'` over the importer set is a deprecation
|
|
16
|
+
* ratchet; a `wiring` rule whose registered side is "symbols with ≥1 importer"
|
|
17
|
+
* finds dead generated code a byte-drift gate cannot see.
|
|
18
|
+
*
|
|
19
|
+
* **On freshness.** It reads the files the caller already walked, resolving
|
|
20
|
+
* specifiers on the spot — there is no persisted graph index behind it and
|
|
21
|
+
* therefore no staleness question to get wrong. That is deliberate: a rule
|
|
22
|
+
* answering from a stale graph would be a confident false green, the exact
|
|
23
|
+
* failure this engine exists to prevent.
|
|
24
|
+
*
|
|
25
|
+
* **Honest scope.** It resolves what the text says plus tsconfig path aliases —
|
|
26
|
+
* the same resolution `check boundaries` uses. It does not follow a re-export
|
|
27
|
+
* chain to attribute a symbol to its original module: a barrel is reported as
|
|
28
|
+
* the module the consumer actually names. That is a lexer's honest answer, and
|
|
29
|
+
* `to.files` matches the resolved target when you need the real path.
|
|
30
|
+
*/
|
|
31
|
+
/** What an emitted id represents. */
|
|
32
|
+
export type ImportEdgeEmit = 'edge' | 'symbol' | 'from';
|
|
33
|
+
/** Context a caller supplies so alias specifiers resolve. */
|
|
34
|
+
export interface IImportEdgeContext {
|
|
35
|
+
readonly tsconfigPaths?: ITsconfigPathsMap;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Extract the import edges a source selects.
|
|
39
|
+
*
|
|
40
|
+
* `files` is the CONSUMER glob (the `from` side): it reuses the field every
|
|
41
|
+
* other extractor uses, so `--changed-only` footprinting, the shared walk, and
|
|
42
|
+
* `$use` all work on it unchanged.
|
|
43
|
+
*/
|
|
44
|
+
export declare function extractImportEdges(source: IWiringSource, files: readonly IExtractFileEntry[], context?: IImportEdgeContext): {
|
|
45
|
+
sites: IExtractedSite[];
|
|
46
|
+
error?: string;
|
|
47
|
+
hint?: string;
|
|
48
|
+
blankedChars?: number;
|
|
49
|
+
};
|
|
50
|
+
//# sourceMappingURL=import-edges.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"import-edges.d.ts","sourceRoot":"","sources":["../../src/extract/import-edges.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEpD,OAAO,EAA0B,KAAK,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAG7F,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE7E;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,qCAAqC;AACrC,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,CAAC;AAmFxD,6DAA6D;AAC7D,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,aAAa,CAAC,EAAE,iBAAiB,CAAC;CAC5C;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,aAAa,EACrB,KAAK,EAAE,SAAS,iBAAiB,EAAE,EACnC,OAAO,GAAE,kBAAuB,GAC/B;IAAE,KAAK,EAAE,cAAc,EAAE,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,CA4FnF"}
|