archprint 0.13.1 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +26 -0
- package/README.md +21 -12
- package/dist/cli/adopted-rules.d.ts +30 -2
- package/dist/cli/adopted-rules.d.ts.map +1 -1
- package/dist/cli/adopted-rules.js +158 -2
- package/dist/cli/adopted-rules.js.map +1 -1
- package/dist/cli/allow.d.ts.map +1 -1
- package/dist/cli/allow.js +21 -4
- package/dist/cli/allow.js.map +1 -1
- package/dist/cli/allowed-evidence.d.ts.map +1 -1
- package/dist/cli/allowed-evidence.js +183 -1
- package/dist/cli/allowed-evidence.js.map +1 -1
- package/dist/cli/check-evaluate.d.ts.map +1 -1
- package/dist/cli/check-evaluate.js +124 -0
- package/dist/cli/check-evaluate.js.map +1 -1
- package/dist/cli/generate.d.ts +4 -4
- package/dist/cli/generate.d.ts.map +1 -1
- package/dist/cli/generate.js +115 -42
- package/dist/cli/generate.js.map +1 -1
- package/dist/cli/layout.d.ts +5 -2
- package/dist/cli/layout.d.ts.map +1 -1
- package/dist/cli/layout.js +43 -10
- package/dist/cli/layout.js.map +1 -1
- package/dist/cli/migrate.d.ts.map +1 -1
- package/dist/cli/migrate.js +1 -2
- package/dist/cli/migrate.js.map +1 -1
- package/dist/cli/program.d.ts.map +1 -1
- package/dist/cli/program.js +10 -6
- package/dist/cli/program.js.map +1 -1
- package/dist/cli/recommend.d.ts +3 -0
- package/dist/cli/recommend.d.ts.map +1 -1
- package/dist/cli/recommend.js +28 -8
- package/dist/cli/recommend.js.map +1 -1
- package/dist/cli/report.js +1 -1
- package/dist/cli/report.js.map +1 -1
- package/dist/detector/cycle-detector.d.ts +5 -0
- package/dist/detector/cycle-detector.d.ts.map +1 -1
- package/dist/detector/cycle-detector.js +20 -0
- package/dist/detector/cycle-detector.js.map +1 -1
- package/dist/detector/dependency-internals-detector.d.ts.map +1 -1
- package/dist/detector/dependency-internals-detector.js +6 -20
- package/dist/detector/dependency-internals-detector.js.map +1 -1
- package/dist/detector/entry-purity-detector.d.ts +7 -0
- package/dist/detector/entry-purity-detector.d.ts.map +1 -1
- package/dist/detector/entry-purity-detector.js +21 -10
- package/dist/detector/entry-purity-detector.js.map +1 -1
- package/dist/detector/phantom-dependency-detector.d.ts +7 -0
- package/dist/detector/phantom-dependency-detector.d.ts.map +1 -1
- package/dist/detector/phantom-dependency-detector.js +18 -39
- package/dist/detector/phantom-dependency-detector.js.map +1 -1
- package/dist/detector/server-client-detector.d.ts +5 -0
- package/dist/detector/server-client-detector.d.ts.map +1 -1
- package/dist/detector/server-client-detector.js +8 -3
- package/dist/detector/server-client-detector.js.map +1 -1
- package/dist/generator/app-isolation-emitters.d.ts +1 -0
- package/dist/generator/app-isolation-emitters.d.ts.map +1 -1
- package/dist/generator/app-isolation-emitters.js +2 -1
- package/dist/generator/app-isolation-emitters.js.map +1 -1
- package/dist/generator/depcruise-exempt.d.ts +4 -0
- package/dist/generator/depcruise-exempt.d.ts.map +1 -1
- package/dist/generator/depcruise-exempt.js +7 -0
- package/dist/generator/depcruise-exempt.js.map +1 -1
- package/dist/generator/dependency-internals-emitters.d.ts +2 -1
- package/dist/generator/dependency-internals-emitters.d.ts.map +1 -1
- package/dist/generator/dependency-internals-emitters.js +7 -3
- package/dist/generator/dependency-internals-emitters.js.map +1 -1
- package/dist/generator/entry-purity-emitters.d.ts +7 -3
- package/dist/generator/entry-purity-emitters.d.ts.map +1 -1
- package/dist/generator/entry-purity-emitters.js +19 -5
- package/dist/generator/entry-purity-emitters.js.map +1 -1
- package/dist/generator/env-access-emitters.d.ts +1 -0
- package/dist/generator/env-access-emitters.d.ts.map +1 -1
- package/dist/generator/env-access-emitters.js +1 -0
- package/dist/generator/env-access-emitters.js.map +1 -1
- package/dist/generator/eslint-app-emitter.d.ts +59 -0
- package/dist/generator/eslint-app-emitter.d.ts.map +1 -0
- package/dist/generator/eslint-app-emitter.js +275 -0
- package/dist/generator/eslint-app-emitter.js.map +1 -0
- package/dist/generator/eslint-preset-emitter.d.ts +2 -2
- package/dist/generator/eslint-preset-emitter.d.ts.map +1 -1
- package/dist/generator/eslint-preset-emitter.js +6 -6
- package/dist/generator/eslint-preset-emitter.js.map +1 -1
- package/dist/generator/feature-slice-emitters.d.ts +1 -0
- package/dist/generator/feature-slice-emitters.d.ts.map +1 -1
- package/dist/generator/feature-slice-emitters.js +2 -1
- package/dist/generator/feature-slice-emitters.js.map +1 -1
- package/dist/generator/layer-emitters.d.ts.map +1 -1
- package/dist/generator/layer-emitters.js +2 -6
- package/dist/generator/layer-emitters.js.map +1 -1
- package/dist/generator/phantom-dependency-emitters.d.ts +2 -1
- package/dist/generator/phantom-dependency-emitters.d.ts.map +1 -1
- package/dist/generator/phantom-dependency-emitters.js +7 -3
- package/dist/generator/phantom-dependency-emitters.js.map +1 -1
- package/dist/generator/role-layering-emitters.d.ts +2 -0
- package/dist/generator/role-layering-emitters.d.ts.map +1 -1
- package/dist/generator/role-layering-emitters.js +2 -1
- package/dist/generator/role-layering-emitters.js.map +1 -1
- package/dist/generator/server-client-emitters.d.ts +10 -3
- package/dist/generator/server-client-emitters.d.ts.map +1 -1
- package/dist/generator/server-client-emitters.js +23 -4
- package/dist/generator/server-client-emitters.js.map +1 -1
- package/dist/generator/stories-isolation-emitters.d.ts +1 -0
- package/dist/generator/stories-isolation-emitters.d.ts.map +1 -1
- package/dist/generator/stories-isolation-emitters.js +2 -1
- package/dist/generator/stories-isolation-emitters.js.map +1 -1
- package/dist/generator/ui-data-isolation-emitters.d.ts +1 -0
- package/dist/generator/ui-data-isolation-emitters.d.ts.map +1 -1
- package/dist/generator/ui-data-isolation-emitters.js +2 -1
- package/dist/generator/ui-data-isolation-emitters.js.map +1 -1
- package/dist/generator/workspace-package-emitters.d.ts +1 -0
- package/dist/generator/workspace-package-emitters.d.ts.map +1 -1
- package/dist/generator/workspace-package-emitters.js +1 -0
- package/dist/generator/workspace-package-emitters.js.map +1 -1
- package/dist/scanner/directives.d.ts +6 -0
- package/dist/scanner/directives.d.ts.map +1 -0
- package/dist/scanner/directives.js +35 -0
- package/dist/scanner/directives.js.map +1 -0
- package/dist/scanner/package-name.d.ts +10 -0
- package/dist/scanner/package-name.d.ts.map +1 -0
- package/dist/scanner/package-name.js +37 -0
- package/dist/scanner/package-name.js.map +1 -0
- package/dist/scanner/resolve-import.d.ts +5 -0
- package/dist/scanner/resolve-import.d.ts.map +1 -1
- package/dist/scanner/resolve-import.js +22 -19
- package/dist/scanner/resolve-import.js.map +1 -1
- package/dist/scanner/role-classifier.d.ts +11 -2
- package/dist/scanner/role-classifier.d.ts.map +1 -1
- package/dist/scanner/role-classifier.js +13 -39
- package/dist/scanner/role-classifier.js.map +1 -1
- package/package.json +2 -2
- package/dist/generator/eslint-layer-emitter.d.ts +0 -29
- package/dist/generator/eslint-layer-emitter.d.ts.map +0 -1
- package/dist/generator/eslint-layer-emitter.js +0 -121
- package/dist/generator/eslint-layer-emitter.js.map +0 -1
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { type ImportGraph } from '../scanner/import-graph.js';
|
|
2
|
+
import { type Role } from '../scanner/role-classifier.js';
|
|
2
3
|
import { type GateResult } from './confidence-gate.js';
|
|
4
|
+
/** Files the framework loads itself: pages, layouts, route and API handlers. */
|
|
5
|
+
export declare const ENTRY_ROLES: readonly Role[];
|
|
3
6
|
export interface EntryImportViolation {
|
|
4
7
|
file: string;
|
|
5
8
|
importer: string;
|
|
@@ -7,10 +10,14 @@ export interface EntryImportViolation {
|
|
|
7
10
|
export interface EntryPurityAnalysis {
|
|
8
11
|
appDir: string;
|
|
9
12
|
entryCount: number;
|
|
13
|
+
/** Every import of a framework entry from a file that is not one. */
|
|
14
|
+
imports: EntryImportViolation[];
|
|
10
15
|
offenderCount: number;
|
|
11
16
|
gate: GateResult;
|
|
12
17
|
violations: EntryImportViolation[];
|
|
13
18
|
}
|
|
19
|
+
/** One violation per imported entry: its first importer in path order. */
|
|
20
|
+
export declare function importedEntries(imports: readonly EntryImportViolation[]): EntryImportViolation[];
|
|
14
21
|
export interface EntryPurityOptions {
|
|
15
22
|
graph?: ImportGraph;
|
|
16
23
|
resolve?: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entry-purity-detector.d.ts","sourceRoot":"","sources":["../../src/detector/entry-purity-detector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,KAAK,WAAW,EAAE,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"entry-purity-detector.d.ts","sourceRoot":"","sources":["../../src/detector/entry-purity-detector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,KAAK,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAChF,OAAO,EAAE,KAAK,IAAI,EAAE,MAAM,+BAA+B,CAAC;AAC1D,OAAO,EAAgB,KAAK,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAErE,gFAAgF;AAChF,eAAO,MAAM,WAAW,EAAE,SAAS,IAAI,EAAoD,CAAC;AAE5F,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,qEAAqE;IACrE,OAAO,EAAE,oBAAoB,EAAE,CAAC;IAChC,aAAa,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,UAAU,CAAC;IACjB,UAAU,EAAE,oBAAoB,EAAE,CAAC;CACpC;AAED,0EAA0E;AAC1E,wBAAgB,eAAe,CAAC,OAAO,EAAE,SAAS,oBAAoB,EAAE,GAAG,oBAAoB,EAAE,CAShG;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,kBAAuB,GAC/B,mBAAmB,CA6BrB"}
|
|
@@ -1,25 +1,36 @@
|
|
|
1
1
|
import { buildImportGraph } from '../scanner/import-graph.js';
|
|
2
2
|
import {} from '../scanner/role-classifier.js';
|
|
3
3
|
import { evaluateGate } from './confidence-gate.js';
|
|
4
|
-
|
|
4
|
+
/** Files the framework loads itself: pages, layouts, route and API handlers. */
|
|
5
|
+
export const ENTRY_ROLES = ['ROUTE_ENTRY', 'ROUTE_HANDLER', 'API_HANDLER'];
|
|
6
|
+
/** One violation per imported entry: its first importer in path order. */
|
|
7
|
+
export function importedEntries(imports) {
|
|
8
|
+
const firstImporter = new Map();
|
|
9
|
+
for (const { file, importer } of imports) {
|
|
10
|
+
const known = firstImporter.get(file);
|
|
11
|
+
if (known === undefined || importer < known)
|
|
12
|
+
firstImporter.set(file, importer);
|
|
13
|
+
}
|
|
14
|
+
return [...firstImporter]
|
|
15
|
+
.map(([file, importer]) => ({ file, importer }))
|
|
16
|
+
.sort((a, b) => a.file.localeCompare(b.file));
|
|
17
|
+
}
|
|
5
18
|
export function detectEntryPurity(appDir, options = {}) {
|
|
6
19
|
const { root, files, adjacency } = options.graph ?? buildImportGraph(appDir, { resolve: options.resolve ?? false });
|
|
7
|
-
const entries = new Set(files.filter((file) => ENTRY_ROLES.
|
|
8
|
-
const
|
|
20
|
+
const entries = new Set(files.filter((file) => ENTRY_ROLES.includes(file.role)).map((file) => file.relativePath));
|
|
21
|
+
const imports = [];
|
|
9
22
|
for (const [file, targets] of adjacency) {
|
|
10
23
|
if (entries.has(file))
|
|
11
24
|
continue;
|
|
12
|
-
for (const target of targets)
|
|
13
|
-
if (entries.has(target)
|
|
14
|
-
|
|
15
|
-
}
|
|
25
|
+
for (const target of targets)
|
|
26
|
+
if (entries.has(target))
|
|
27
|
+
imports.push({ file: target, importer: file });
|
|
16
28
|
}
|
|
17
|
-
const violations =
|
|
18
|
-
.map(([file, importer]) => ({ file, importer }))
|
|
19
|
-
.sort((a, b) => a.file.localeCompare(b.file));
|
|
29
|
+
const violations = importedEntries(imports);
|
|
20
30
|
return {
|
|
21
31
|
appDir: root,
|
|
22
32
|
entryCount: entries.size,
|
|
33
|
+
imports: imports.sort((a, b) => a.file.localeCompare(b.file) || a.importer.localeCompare(b.importer)),
|
|
23
34
|
offenderCount: violations.length,
|
|
24
35
|
gate: evaluateGate({
|
|
25
36
|
roleFileCount: entries.size,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entry-purity-detector.js","sourceRoot":"","sources":["../../src/detector/entry-purity-detector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAoB,MAAM,4BAA4B,CAAC;AAChF,OAAO,EAAa,MAAM,+BAA+B,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAmB,MAAM,sBAAsB,CAAC;AAErE,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"entry-purity-detector.js","sourceRoot":"","sources":["../../src/detector/entry-purity-detector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAoB,MAAM,4BAA4B,CAAC;AAChF,OAAO,EAAa,MAAM,+BAA+B,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAmB,MAAM,sBAAsB,CAAC;AAErE,gFAAgF;AAChF,MAAM,CAAC,MAAM,WAAW,GAAoB,CAAC,aAAa,EAAE,eAAe,EAAE,aAAa,CAAC,CAAC;AAiB5F,0EAA0E;AAC1E,MAAM,UAAU,eAAe,CAAC,OAAwC;IACtE,MAAM,aAAa,GAAG,IAAI,GAAG,EAAkB,CAAC;IAChD,KAAK,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,OAAO,EAAE,CAAC;QACzC,MAAM,KAAK,GAAG,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACtC,IAAI,KAAK,KAAK,SAAS,IAAI,QAAQ,GAAG,KAAK;YAAE,aAAa,CAAC,GAAG,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IACjF,CAAC;IACD,OAAO,CAAC,GAAG,aAAa,CAAC;SACtB,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;SAC/C,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AAClD,CAAC;AAOD,MAAM,UAAU,iBAAiB,CAC/B,MAAc,EACd,UAA8B,EAAE;IAEhC,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,GAC9B,OAAO,CAAC,KAAK,IAAI,gBAAgB,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,KAAK,EAAE,CAAC,CAAC;IAEnF,MAAM,OAAO,GAAG,IAAI,GAAG,CACrB,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,WAAW,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,CACzF,CAAC;IACF,MAAM,OAAO,GAA2B,EAAE,CAAC;IAC3C,KAAK,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,SAAS,EAAE,CAAC;QACxC,IAAI,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,SAAS;QAChC,KAAK,MAAM,MAAM,IAAI,OAAO;YAC1B,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC;gBAAE,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5E,CAAC;IACD,MAAM,UAAU,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;IAE5C,OAAO;QACL,MAAM,EAAE,IAAI;QACZ,UAAU,EAAE,OAAO,CAAC,IAAI;QACxB,OAAO,EAAE,OAAO,CAAC,IAAI,CACnB,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAC/E;QACD,aAAa,EAAE,UAAU,CAAC,MAAM;QAChC,IAAI,EAAE,YAAY,CAAC;YACjB,aAAa,EAAE,OAAO,CAAC,IAAI;YAC3B,kBAAkB,EAAE,UAAU,CAAC,MAAM;YACrC,cAAc,EAAE,CAAC;SAClB,CAAC;QACF,UAAU;KACX,CAAC;AACJ,CAAC"}
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import { type GateResult } from './confidence-gate.js';
|
|
2
|
+
/** The names of the workspace's packages, which count as declared. */
|
|
3
|
+
export declare const workspacePackageNames: (appDir: string) => string[];
|
|
4
|
+
/** The package.json files whose dependencies count as declared: the app's, and the workspace root's. */
|
|
5
|
+
export declare function declaringPackageJsons(appDir: string): string[];
|
|
2
6
|
export interface PhantomDependencyViolation {
|
|
3
7
|
file: string;
|
|
4
8
|
specifier: string;
|
|
@@ -7,6 +11,9 @@ export interface PhantomDependencyViolation {
|
|
|
7
11
|
export interface PhantomDependencyAnalysis {
|
|
8
12
|
appDir: string;
|
|
9
13
|
externalImporterCount: number;
|
|
14
|
+
/** The package.json files and workspace packages that count as declared. */
|
|
15
|
+
declaringPackageJsons: string[];
|
|
16
|
+
workspacePackages: string[];
|
|
10
17
|
offenderCount: number;
|
|
11
18
|
gate: GateResult;
|
|
12
19
|
violations: PhantomDependencyViolation[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"phantom-dependency-detector.d.ts","sourceRoot":"","sources":["../../src/detector/phantom-dependency-detector.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"phantom-dependency-detector.d.ts","sourceRoot":"","sources":["../../src/detector/phantom-dependency-detector.ts"],"names":[],"mappings":"AAYA,OAAO,EAAgB,KAAK,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAIrE,sEAAsE;AACtE,eAAO,MAAM,qBAAqB,GAAI,QAAQ,MAAM,KAAG,MAAM,EAC0B,CAAC;AAExF,wGAAwG;AACxG,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAM9D;AAKD,MAAM,WAAW,0BAA0B;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,yBAAyB;IACxC,MAAM,EAAE,MAAM,CAAC;IACf,qBAAqB,EAAE,MAAM,CAAC;IAC9B,4EAA4E;IAC5E,qBAAqB,EAAE,MAAM,EAAE,CAAC;IAChC,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,UAAU,CAAC;IACjB,UAAU,EAAE,0BAA0B,EAAE,CAAC;CAC1C;AAED,MAAM,WAAW,wBAAwB;IACvC,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,wBAA6B,GACrC,yBAAyB,CAsD3B"}
|
|
@@ -2,54 +2,31 @@ import { existsSync, readFileSync } from 'node:fs';
|
|
|
2
2
|
import { builtinModules } from 'node:module';
|
|
3
3
|
import * as path from 'node:path';
|
|
4
4
|
import { createImportAnalyzer, walkRepo, } from '../scanner/file-walker.js';
|
|
5
|
+
import { declaredPackages, packageName } from '../scanner/package-name.js';
|
|
5
6
|
import { buildWorkspaceMap } from '../scanner/workspace-resolver.js';
|
|
6
7
|
import { buildWorkspacePackageMap, findWorkspaceRoot } from '../scanner/workspace-packages.js';
|
|
7
8
|
import { evaluateGate } from './confidence-gate.js';
|
|
8
9
|
const BUILTINS = new Set(builtinModules);
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}
|
|
17
|
-
for (const prefix of aliasPrefixes) {
|
|
18
|
-
if (specifier === prefix || specifier.startsWith(`${prefix}/`))
|
|
19
|
-
return null;
|
|
20
|
-
}
|
|
21
|
-
const parts = specifier.split('/');
|
|
22
|
-
return specifier.startsWith('@') ? parts.slice(0, 2).join('/') : parts[0];
|
|
23
|
-
}
|
|
24
|
-
function declaredIn(packageJsonPath, into) {
|
|
25
|
-
if (!existsSync(packageJsonPath))
|
|
26
|
-
return;
|
|
27
|
-
try {
|
|
28
|
-
const json = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
|
|
29
|
-
for (const field of DEP_FIELDS) {
|
|
30
|
-
const deps = json[field];
|
|
31
|
-
if (deps && typeof deps === 'object') {
|
|
32
|
-
for (const name of Object.keys(deps))
|
|
33
|
-
into.add(name);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
catch {
|
|
38
|
-
/* v8 ignore next -- unreadable/invalid package.json is treated as declaring nothing */
|
|
39
|
-
}
|
|
10
|
+
/** The names of the workspace's packages, which count as declared. */
|
|
11
|
+
export const workspacePackageNames = (appDir) => Object.keys(buildWorkspacePackageMap(findWorkspaceRoot(path.resolve(appDir)))).sort();
|
|
12
|
+
/** The package.json files whose dependencies count as declared: the app's, and the workspace root's. */
|
|
13
|
+
export function declaringPackageJsons(appDir) {
|
|
14
|
+
const root = path.resolve(appDir);
|
|
15
|
+
const workspaceRoot = findWorkspaceRoot(root);
|
|
16
|
+
return [root, ...(workspaceRoot === root ? [] : [workspaceRoot])].map((dir) => path.join(dir, 'package.json'));
|
|
40
17
|
}
|
|
18
|
+
const readIfPresent = (file) => existsSync(file) ? readFileSync(file, 'utf-8') : '';
|
|
41
19
|
export function detectPhantomDependencies(appDir, options = {}) {
|
|
42
20
|
const root = path.resolve(appDir);
|
|
43
21
|
const resolve = options.resolve ?? false;
|
|
44
22
|
const files = walkRepo(root).filter((file) => file.role !== 'TEST');
|
|
45
23
|
const aliasPrefixes = Object.keys(buildWorkspaceMap(root)).map((key) => key.replace(/\/?\*$/, ''));
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
declared.add(name);
|
|
24
|
+
const packageJsons = declaringPackageJsons(root);
|
|
25
|
+
const workspacePackages = workspacePackageNames(root);
|
|
26
|
+
const declared = new Set([
|
|
27
|
+
...packageJsons.flatMap((file) => declaredPackages(readIfPresent(file))),
|
|
28
|
+
...workspacePackages,
|
|
29
|
+
]);
|
|
53
30
|
const analyze = createImportAnalyzer(root, { resolve });
|
|
54
31
|
const externalImporters = new Set();
|
|
55
32
|
const offenders = new Set();
|
|
@@ -66,7 +43,7 @@ export function detectPhantomDependencies(appDir, options = {}) {
|
|
|
66
43
|
for (const imp of imports) {
|
|
67
44
|
if (!imp.hasValueBinding)
|
|
68
45
|
continue;
|
|
69
|
-
const name = packageName(imp.specifier, aliasPrefixes);
|
|
46
|
+
const name = packageName(imp.specifier, aliasPrefixes, BUILTINS);
|
|
70
47
|
if (name === null)
|
|
71
48
|
continue;
|
|
72
49
|
externalImporters.add(file.relativePath);
|
|
@@ -79,6 +56,8 @@ export function detectPhantomDependencies(appDir, options = {}) {
|
|
|
79
56
|
return {
|
|
80
57
|
appDir: root,
|
|
81
58
|
externalImporterCount: externalImporters.size,
|
|
59
|
+
declaringPackageJsons: packageJsons,
|
|
60
|
+
workspacePackages,
|
|
82
61
|
offenderCount: offenders.size,
|
|
83
62
|
gate: evaluateGate({
|
|
84
63
|
roleFileCount: externalImporters.size,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"phantom-dependency-detector.js","sourceRoot":"","sources":["../../src/detector/phantom-dependency-detector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EACL,oBAAoB,EAEpB,QAAQ,GAET,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AACrE,OAAO,EAAE,wBAAwB,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AAC/F,OAAO,EAAE,YAAY,EAAmB,MAAM,sBAAsB,CAAC;AAErE,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,cAAc,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"phantom-dependency-detector.js","sourceRoot":"","sources":["../../src/detector/phantom-dependency-detector.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { type ImportGraph } from '../scanner/import-graph.js';
|
|
2
2
|
import { type GateResult } from './confidence-gate.js';
|
|
3
|
+
/** The package that marks a module as server-only in React Server Components (Next.js). */
|
|
4
|
+
export declare const SERVER_ONLY_PACKAGE = "server-only";
|
|
3
5
|
export interface ServerClientViolation {
|
|
4
6
|
file: string;
|
|
5
7
|
target: string;
|
|
@@ -7,6 +9,9 @@ export interface ServerClientViolation {
|
|
|
7
9
|
export interface ServerClientAnalysis {
|
|
8
10
|
appDir: string;
|
|
9
11
|
clientCount: number;
|
|
12
|
+
/** The "use client" files and the modules importing "server-only", relative to the app. */
|
|
13
|
+
clients: string[];
|
|
14
|
+
serverModules: string[];
|
|
10
15
|
offenderCount: number;
|
|
11
16
|
gate: GateResult;
|
|
12
17
|
violations: ServerClientViolation[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server-client-detector.d.ts","sourceRoot":"","sources":["../../src/detector/server-client-detector.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"server-client-detector.d.ts","sourceRoot":"","sources":["../../src/detector/server-client-detector.ts"],"names":[],"mappings":"AAEA,OAAO,EAAoB,KAAK,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAEhF,OAAO,EAAgB,KAAK,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAErE,2FAA2F;AAC3F,eAAO,MAAM,mBAAmB,gBAAgB,CAAC;AAEjD,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,2FAA2F;IAC3F,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,UAAU,CAAC;IACjB,UAAU,EAAE,qBAAqB,EAAE,CAAC;CACrC;AAED,MAAM,WAAW,mBAAmB;IAClC,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,mBAAwB,GAChC,oBAAoB,CAmDtB"}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { importLocations } from '../scanner/file-walker.js';
|
|
2
3
|
import { buildImportGraph } from '../scanner/import-graph.js';
|
|
3
4
|
import { hasUseClientDirective } from '../scanner/role-classifier.js';
|
|
4
5
|
import { evaluateGate } from './confidence-gate.js';
|
|
5
|
-
|
|
6
|
+
/** The package that marks a module as server-only in React Server Components (Next.js). */
|
|
7
|
+
export const SERVER_ONLY_PACKAGE = 'server-only';
|
|
6
8
|
export function detectServerClientBoundary(appDir, options = {}) {
|
|
7
9
|
const { root, files, adjacency } = options.graph ?? buildImportGraph(appDir, { resolve: options.resolve ?? false });
|
|
8
10
|
const clients = new Set();
|
|
@@ -18,15 +20,16 @@ export function detectServerClientBoundary(appDir, options = {}) {
|
|
|
18
20
|
}
|
|
19
21
|
if (hasUseClientDirective(text))
|
|
20
22
|
clients.add(file.relativePath);
|
|
21
|
-
if (
|
|
23
|
+
if (importLocations(file.absolutePath).some((imp) => imp.specifier === SERVER_ONLY_PACKAGE)) {
|
|
22
24
|
serverModules.add(file.relativePath);
|
|
25
|
+
}
|
|
23
26
|
}
|
|
24
27
|
const offenders = new Set();
|
|
25
28
|
const violations = [];
|
|
26
29
|
for (const file of clients) {
|
|
27
30
|
if (serverModules.has(file)) {
|
|
28
31
|
offenders.add(file);
|
|
29
|
-
violations.push({ file, target:
|
|
32
|
+
violations.push({ file, target: SERVER_ONLY_PACKAGE });
|
|
30
33
|
}
|
|
31
34
|
for (const target of adjacency.get(file) ?? []) {
|
|
32
35
|
if (serverModules.has(target)) {
|
|
@@ -38,6 +41,8 @@ export function detectServerClientBoundary(appDir, options = {}) {
|
|
|
38
41
|
return {
|
|
39
42
|
appDir: root,
|
|
40
43
|
clientCount: clients.size,
|
|
44
|
+
clients: [...clients].sort(),
|
|
45
|
+
serverModules: [...serverModules].sort(),
|
|
41
46
|
offenderCount: offenders.size,
|
|
42
47
|
gate: evaluateGate({
|
|
43
48
|
roleFileCount: clients.size,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server-client-detector.js","sourceRoot":"","sources":["../../src/detector/server-client-detector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,gBAAgB,EAAoB,MAAM,4BAA4B,CAAC;AAChF,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAE,YAAY,EAAmB,MAAM,sBAAsB,CAAC;AAErE,MAAM,
|
|
1
|
+
{"version":3,"file":"server-client-detector.js","sourceRoot":"","sources":["../../src/detector/server-client-detector.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { GenerationStatus } from '../detector/confidence-gate.js';
|
|
2
2
|
import type { AppIsolationGroup } from '../detector/app-isolation-detector.js';
|
|
3
|
+
export declare const appIsolationRuleName: (container: string) => string;
|
|
3
4
|
export interface CrossAppRule {
|
|
4
5
|
name: string;
|
|
5
6
|
comment: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-isolation-emitters.d.ts","sourceRoot":"","sources":["../../src/generator/app-isolation-emitters.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uCAAuC,CAAC;
|
|
1
|
+
{"version":3,"file":"app-isolation-emitters.d.ts","sourceRoot":"","sources":["../../src/generator/app-isolation-emitters.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uCAAuC,CAAC;AAO/E,eAAO,MAAM,oBAAoB,GAAI,WAAW,MAAM,KAAG,MACtB,CAAC;AAKpC,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;IACpC,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACvB,EAAE,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CACvC;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,YAAY,EAAE,CAAC;CAC3B;AAED,wBAAgB,+BAA+B,CAC7C,MAAM,EAAE,SAAS,iBAAiB,EAAE,EACpC,OAAO,GAAE,SAAS,gBAAgB,EAAa,GAC9C,cAAc,CAchB"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const escapeRegExp = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
2
2
|
const slug = (container) => container.replace(/[^a-zA-Z0-9]+/g, '-').replace(/^-|-$/g, '');
|
|
3
|
+
export const appIsolationRuleName = (container) => `no-cross-app-${slug(container)}`;
|
|
3
4
|
const confidencePct = (group) => `${(group.gate.conditions.confidence.value * 100).toFixed(0)}%`;
|
|
4
5
|
export function toDependencyCruiserAppIsolation(groups, include = ['AUTO']) {
|
|
5
6
|
const forbidden = groups
|
|
@@ -7,7 +8,7 @@ export function toDependencyCruiserAppIsolation(groups, include = ['AUTO']) {
|
|
|
7
8
|
.map((group) => {
|
|
8
9
|
const container = escapeRegExp(group.container);
|
|
9
10
|
return {
|
|
10
|
-
name:
|
|
11
|
+
name: appIsolationRuleName(group.container),
|
|
11
12
|
comment: `Archprint inferred app isolation: the ${group.appCount} apps under "${group.container}" do not import each other (${group.appFileCount - group.crossImporterCount}/${group.appFileCount} app files conform); cross-app imports are forbidden (confidence ${confidencePct(group)}).`,
|
|
12
13
|
severity: 'error',
|
|
13
14
|
from: { path: `^${container}/([^/]+)/` },
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-isolation-emitters.js","sourceRoot":"","sources":["../../src/generator/app-isolation-emitters.ts"],"names":[],"mappings":"AAGA,MAAM,YAAY,GAAG,CAAC,KAAa,EAAU,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;AAE7F,MAAM,IAAI,GAAG,CAAC,SAAiB,EAAU,EAAE,CACzC,SAAS,CAAC,OAAO,CAAC,gBAAgB,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;AAEjE,MAAM,aAAa,GAAG,CAAC,KAAwB,EAAU,EAAE,CACzD,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,KAAK,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;AAclE,MAAM,UAAU,+BAA+B,CAC7C,MAAoC,EACpC,UAAuC,CAAC,MAAM,CAAC;IAE/C,MAAM,SAAS,GAAG,MAAM;SACrB,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;SACtD,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;QACb,MAAM,SAAS,GAAG,YAAY,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QAChD,OAAO;YACL,IAAI,EAAE,
|
|
1
|
+
{"version":3,"file":"app-isolation-emitters.js","sourceRoot":"","sources":["../../src/generator/app-isolation-emitters.ts"],"names":[],"mappings":"AAGA,MAAM,YAAY,GAAG,CAAC,KAAa,EAAU,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;AAE7F,MAAM,IAAI,GAAG,CAAC,SAAiB,EAAU,EAAE,CACzC,SAAS,CAAC,OAAO,CAAC,gBAAgB,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;AAEjE,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,SAAiB,EAAU,EAAE,CAChE,gBAAgB,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;AAEpC,MAAM,aAAa,GAAG,CAAC,KAAwB,EAAU,EAAE,CACzD,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,KAAK,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;AAclE,MAAM,UAAU,+BAA+B,CAC7C,MAAoC,EACpC,UAAuC,CAAC,MAAM,CAAC;IAE/C,MAAM,SAAS,GAAG,MAAM;SACrB,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;SACtD,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;QACb,MAAM,SAAS,GAAG,YAAY,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QAChD,OAAO;YACL,IAAI,EAAE,oBAAoB,CAAC,KAAK,CAAC,SAAS,CAAC;YAC3C,OAAO,EAAE,yCAAyC,KAAK,CAAC,QAAQ,gBAAgB,KAAK,CAAC,SAAS,+BAA+B,KAAK,CAAC,YAAY,GAAG,KAAK,CAAC,kBAAkB,IAAI,KAAK,CAAC,YAAY,oEAAoE,aAAa,CAAC,KAAK,CAAC,IAAI;YAC7R,QAAQ,EAAE,OAAgB;YAC1B,IAAI,EAAE,EAAE,IAAI,EAAE,IAAI,SAAS,WAAW,EAAE;YACxC,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,SAAS,WAAW,EAAE,OAAO,EAAE,IAAI,SAAS,MAAM,EAAE;SACrE,CAAC;IACJ,CAAC,CAAC,CAAC;IACL,OAAO,EAAE,SAAS,EAAE,CAAC;AACvB,CAAC"}
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
/** The regex prefix for paths under the app, as dependency-cruiser reports them from where archprint ran. */
|
|
2
|
+
export declare const appPathPrefix: (appPath: string) => string;
|
|
3
|
+
/** A regex matching exactly these app-relative files. */
|
|
4
|
+
export declare const exactAppFiles: (files: readonly string[], appPath: string) => string;
|
|
1
5
|
export declare const TEST_ROLE_REGEX = "(\\.(test|spec|e2e-spec|e2e)\\.(ts|tsx)$)|((^|/)(__tests__|__mocks__|e2e|cypress|playwright|test|tests)/)";
|
|
2
6
|
export declare function exemptDepcruiseFrom(base: string | readonly string[], violations: readonly {
|
|
3
7
|
file: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"depcruise-exempt.d.ts","sourceRoot":"","sources":["../../src/generator/depcruise-exempt.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,eAAe,8GACiF,CAAC;AAE9G,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,EAChC,UAAU,EAAE,SAAS;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,GACtC,MAAM,GAAG,MAAM,EAAE,CAOnB"}
|
|
1
|
+
{"version":3,"file":"depcruise-exempt.d.ts","sourceRoot":"","sources":["../../src/generator/depcruise-exempt.ts"],"names":[],"mappings":"AAEA,6GAA6G;AAC7G,eAAO,MAAM,aAAa,GAAI,SAAS,MAAM,KAAG,MAG/C,CAAC;AAEF,yDAAyD;AACzD,eAAO,MAAM,aAAa,GAAI,OAAO,SAAS,MAAM,EAAE,EAAE,SAAS,MAAM,KAAG,MACH,CAAC;AAExE,eAAO,MAAM,eAAe,8GACiF,CAAC;AAE9G,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,EAChC,UAAU,EAAE,SAAS;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,GACtC,MAAM,GAAG,MAAM,EAAE,CAOnB"}
|
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
const escapeRegExp = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
2
|
+
/** The regex prefix for paths under the app, as dependency-cruiser reports them from where archprint ran. */
|
|
3
|
+
export const appPathPrefix = (appPath) => {
|
|
4
|
+
const normalized = appPath.replace(/\\/g, '/').replace(/\/+$/, '');
|
|
5
|
+
return normalized === '' || normalized === '.' ? '' : `${escapeRegExp(normalized)}/`;
|
|
6
|
+
};
|
|
7
|
+
/** A regex matching exactly these app-relative files. */
|
|
8
|
+
export const exactAppFiles = (files, appPath) => `^${appPathPrefix(appPath)}(?:${files.map(escapeRegExp).join('|')})$`;
|
|
2
9
|
export const TEST_ROLE_REGEX = '(\\.(test|spec|e2e-spec|e2e)\\.(ts|tsx)$)|((^|/)(__tests__|__mocks__|e2e|cypress|playwright|test|tests)/)';
|
|
3
10
|
export function exemptDepcruiseFrom(base, violations) {
|
|
4
11
|
const bases = typeof base === 'string' ? [base] : [...base];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"depcruise-exempt.js","sourceRoot":"","sources":["../../src/generator/depcruise-exempt.ts"],"names":[],"mappings":"AAAA,MAAM,YAAY,GAAG,CAAC,KAAa,EAAU,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;AAE7F,MAAM,CAAC,MAAM,eAAe,GAC1B,2GAA2G,CAAC;AAE9G,MAAM,UAAU,mBAAmB,CACjC,IAAgC,EAChC,UAAuC;IAEvC,MAAM,KAAK,GAAG,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IAC5D,MAAM,KAAK,GAAG;QACZ,GAAG,KAAK;QACR,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,QAAQ,YAAY,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC;KAC1E,CAAC;IACF,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,KAAK,CAAC;AAChD,CAAC"}
|
|
1
|
+
{"version":3,"file":"depcruise-exempt.js","sourceRoot":"","sources":["../../src/generator/depcruise-exempt.ts"],"names":[],"mappings":"AAAA,MAAM,YAAY,GAAG,CAAC,KAAa,EAAU,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;AAE7F,6GAA6G;AAC7G,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,OAAe,EAAU,EAAE;IACvD,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACnE,OAAO,UAAU,KAAK,EAAE,IAAI,UAAU,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,YAAY,CAAC,UAAU,CAAC,GAAG,CAAC;AACvF,CAAC,CAAC;AAEF,yDAAyD;AACzD,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,KAAwB,EAAE,OAAe,EAAU,EAAE,CACjF,IAAI,aAAa,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;AAExE,MAAM,CAAC,MAAM,eAAe,GAC1B,2GAA2G,CAAC;AAE9G,MAAM,UAAU,mBAAmB,CACjC,IAAgC,EAChC,UAAuC;IAEvC,MAAM,KAAK,GAAG,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IAC5D,MAAM,KAAK,GAAG;QACZ,GAAG,KAAK;QACR,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,QAAQ,YAAY,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC;KAC1E,CAAC;IACF,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,KAAK,CAAC;AAChD,CAAC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { DependencyInternalsAnalysis } from '../detector/dependency-internals-detector.js';
|
|
2
|
+
export declare const DEPENDENCY_INTERNALS_RULE = "no-dependency-internals";
|
|
2
3
|
export interface NoInternalsRule {
|
|
3
4
|
name: string;
|
|
4
5
|
comment: string;
|
|
@@ -13,5 +14,5 @@ export interface NoInternalsRule {
|
|
|
13
14
|
export interface NoInternalsConfig {
|
|
14
15
|
forbidden: NoInternalsRule[];
|
|
15
16
|
}
|
|
16
|
-
export declare function toDependencyCruiserDependencyInternals(analysis: DependencyInternalsAnalysis): NoInternalsConfig;
|
|
17
|
+
export declare function toDependencyCruiserDependencyInternals(analysis: DependencyInternalsAnalysis, allowedFor: (ruleId: string) => readonly string[]): NoInternalsConfig;
|
|
17
18
|
//# sourceMappingURL=dependency-internals-emitters.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dependency-internals-emitters.d.ts","sourceRoot":"","sources":["../../src/generator/dependency-internals-emitters.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,8CAA8C,CAAC;
|
|
1
|
+
{"version":3,"file":"dependency-internals-emitters.d.ts","sourceRoot":"","sources":["../../src/generator/dependency-internals-emitters.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,8CAA8C,CAAC;AAGhG,eAAO,MAAM,yBAAyB,4BAA4B,CAAC;AAInE,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;IACpC,IAAI,EAAE;QAAE,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;KAAE,CAAC;IACrC,EAAE,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;CACtB;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,eAAe,EAAE,CAAC;CAC9B;AAED,wBAAgB,sCAAsC,CACpD,QAAQ,EAAE,2BAA2B,EACrC,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,SAAS,MAAM,EAAE,GAChD,iBAAiB,CAyBnB"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { exemptDepcruiseFrom, TEST_ROLE_REGEX } from './depcruise-exempt.js';
|
|
2
|
+
export const DEPENDENCY_INTERNALS_RULE = 'no-dependency-internals';
|
|
2
3
|
const INTERNAL_PATH = 'node_modules/(?:@[^/]+/)?[^/]+/(?:src|internal|internals)/';
|
|
3
|
-
export function toDependencyCruiserDependencyInternals(analysis) {
|
|
4
|
+
export function toDependencyCruiserDependencyInternals(analysis, allowedFor) {
|
|
4
5
|
if (analysis.externalImporterCount === 0 || analysis.gate.status !== 'AUTO') {
|
|
5
6
|
return { forbidden: [] };
|
|
6
7
|
}
|
|
@@ -9,11 +10,14 @@ export function toDependencyCruiserDependencyInternals(analysis) {
|
|
|
9
10
|
return {
|
|
10
11
|
forbidden: [
|
|
11
12
|
{
|
|
12
|
-
name:
|
|
13
|
+
name: DEPENDENCY_INTERNALS_RULE,
|
|
13
14
|
comment: `Archprint inferred dependency hygiene: ${conform}/${analysis.externalImporterCount} files import third-party packages only by their public entry; reaching into a package's build/impl directory is forbidden (confidence ${floor}).`,
|
|
14
15
|
severity: 'error',
|
|
15
16
|
from: {
|
|
16
|
-
pathNot: exemptDepcruiseFrom([TEST_ROLE_REGEX, 'node_modules'],
|
|
17
|
+
pathNot: exemptDepcruiseFrom([TEST_ROLE_REGEX, 'node_modules'], [
|
|
18
|
+
...analysis.violations,
|
|
19
|
+
...allowedFor(DEPENDENCY_INTERNALS_RULE).map((file) => ({ file })),
|
|
20
|
+
]),
|
|
17
21
|
},
|
|
18
22
|
to: { path: INTERNAL_PATH },
|
|
19
23
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dependency-internals-emitters.js","sourceRoot":"","sources":["../../src/generator/dependency-internals-emitters.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAE7E,MAAM,aAAa,GAAG,4DAA4D,CAAC;AAcnF,MAAM,UAAU,sCAAsC,CACpD,QAAqC;
|
|
1
|
+
{"version":3,"file":"dependency-internals-emitters.js","sourceRoot":"","sources":["../../src/generator/dependency-internals-emitters.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAE7E,MAAM,CAAC,MAAM,yBAAyB,GAAG,yBAAyB,CAAC;AAEnE,MAAM,aAAa,GAAG,4DAA4D,CAAC;AAcnF,MAAM,UAAU,sCAAsC,CACpD,QAAqC,EACrC,UAAiD;IAEjD,IAAI,QAAQ,CAAC,qBAAqB,KAAK,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;QAC5E,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;IAC3B,CAAC;IACD,MAAM,OAAO,GAAG,QAAQ,CAAC,qBAAqB,GAAG,QAAQ,CAAC,aAAa,CAAC;IACxE,MAAM,KAAK,GAAG,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,KAAK,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;IACjF,OAAO;QACL,SAAS,EAAE;YACT;gBACE,IAAI,EAAE,yBAAyB;gBAC/B,OAAO,EAAE,0CAA0C,OAAO,IAAI,QAAQ,CAAC,qBAAqB,0IAA0I,KAAK,IAAI;gBAC/O,QAAQ,EAAE,OAAO;gBACjB,IAAI,EAAE;oBACJ,OAAO,EAAE,mBAAmB,CAC1B,CAAC,eAAe,EAAE,cAAc,CAAC,EACjC;wBACE,GAAG,QAAQ,CAAC,UAAU;wBACtB,GAAG,UAAU,CAAC,yBAAyB,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;qBACnE,CACF;iBACF;gBACD,EAAE,EAAE,EAAE,IAAI,EAAE,aAAa,EAAE;aAC5B;SACF;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -1,17 +1,21 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type EntryPurityAnalysis } from '../detector/entry-purity-detector.js';
|
|
2
|
+
export declare const ENTRY_PURITY_RULE = "no-import-framework-entry";
|
|
2
3
|
export interface EntryPurityRule {
|
|
3
4
|
name: string;
|
|
4
5
|
comment: string;
|
|
5
6
|
severity: 'error' | 'warn' | 'info';
|
|
6
7
|
from: {
|
|
7
|
-
pathNot: string;
|
|
8
|
+
pathNot: string | string[];
|
|
8
9
|
};
|
|
9
10
|
to: {
|
|
10
11
|
path: string;
|
|
12
|
+
pathNot?: string | string[];
|
|
13
|
+
dependencyTypesNot: string[];
|
|
11
14
|
};
|
|
12
15
|
}
|
|
13
16
|
export interface EntryPurityConfig {
|
|
14
17
|
forbidden: EntryPurityRule[];
|
|
15
18
|
}
|
|
16
|
-
|
|
19
|
+
/** Dependency-cruiser cannot exempt a single import, so an entry already imported is exempt as a target. */
|
|
20
|
+
export declare function toDependencyCruiserEntryPurity(analysis: EntryPurityAnalysis, allowedFor: (ruleId: string) => readonly string[]): EntryPurityConfig;
|
|
17
21
|
//# sourceMappingURL=entry-purity-emitters.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entry-purity-emitters.d.ts","sourceRoot":"","sources":["../../src/generator/entry-purity-emitters.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"entry-purity-emitters.d.ts","sourceRoot":"","sources":["../../src/generator/entry-purity-emitters.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,KAAK,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAI7F,eAAO,MAAM,iBAAiB,8BAA8B,CAAC;AAS7D,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;IACpC,IAAI,EAAE;QAAE,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;KAAE,CAAC;IACrC,EAAE,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;QAAC,kBAAkB,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;CACjF;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,eAAe,EAAE,CAAC;CAC9B;AAED,4GAA4G;AAC5G,wBAAgB,8BAA8B,CAC5C,QAAQ,EAAE,mBAAmB,EAC7B,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,SAAS,MAAM,EAAE,GAChD,iBAAiB,CA6BnB"}
|
|
@@ -1,22 +1,36 @@
|
|
|
1
|
+
import { ENTRY_ROLES } from '../detector/entry-purity-detector.js';
|
|
1
2
|
import { ROLE_PATTERNS } from '../scanner/role-classifier.js';
|
|
2
|
-
|
|
3
|
+
import { exemptDepcruiseFrom, TEST_ROLE_REGEX } from './depcruise-exempt.js';
|
|
4
|
+
export const ENTRY_PURITY_RULE = 'no-import-framework-entry';
|
|
3
5
|
const entryPath = () => {
|
|
4
6
|
const sources = ENTRY_ROLES.flatMap((role) => (ROLE_PATTERNS.get(role) ?? []).map((pattern) => pattern.source));
|
|
5
7
|
return `(${sources.join('|')})`;
|
|
6
8
|
};
|
|
7
|
-
|
|
9
|
+
/** Dependency-cruiser cannot exempt a single import, so an entry already imported is exempt as a target. */
|
|
10
|
+
export function toDependencyCruiserEntryPurity(analysis, allowedFor) {
|
|
8
11
|
if (analysis.entryCount === 0 || analysis.gate.status !== 'AUTO')
|
|
9
12
|
return { forbidden: [] };
|
|
10
13
|
const conform = analysis.entryCount - analysis.offenderCount;
|
|
11
14
|
const floor = `${(analysis.gate.conditions.confidence.value * 100).toFixed(0)}%`;
|
|
15
|
+
const importedEntries = [...new Set(analysis.imports.map((entry) => entry.file))].map((file) => ({
|
|
16
|
+
file,
|
|
17
|
+
}));
|
|
12
18
|
return {
|
|
13
19
|
forbidden: [
|
|
14
20
|
{
|
|
15
|
-
name:
|
|
21
|
+
name: ENTRY_PURITY_RULE,
|
|
16
22
|
comment: `Archprint inferred entry purity: ${conform}/${analysis.entryCount} framework entries (pages, routes) are loaded by the framework and imported by nothing; importing a framework entry from other code is forbidden (confidence ${floor}).`,
|
|
17
23
|
severity: 'error',
|
|
18
|
-
from: {
|
|
19
|
-
|
|
24
|
+
from: {
|
|
25
|
+
pathNot: exemptDepcruiseFrom(['node_modules', TEST_ROLE_REGEX, entryPath()], allowedFor(ENTRY_PURITY_RULE).map((file) => ({ file }))),
|
|
26
|
+
},
|
|
27
|
+
to: {
|
|
28
|
+
path: entryPath(),
|
|
29
|
+
...(importedEntries.length === 0
|
|
30
|
+
? {}
|
|
31
|
+
: { pathNot: exemptDepcruiseFrom([], importedEntries) }),
|
|
32
|
+
dependencyTypesNot: ['type-only'],
|
|
33
|
+
},
|
|
20
34
|
},
|
|
21
35
|
],
|
|
22
36
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entry-purity-emitters.js","sourceRoot":"","sources":["../../src/generator/entry-purity-emitters.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"entry-purity-emitters.js","sourceRoot":"","sources":["../../src/generator/entry-purity-emitters.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAA4B,MAAM,sCAAsC,CAAC;AAC7F,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAE7E,MAAM,CAAC,MAAM,iBAAiB,GAAG,2BAA2B,CAAC;AAE7D,MAAM,SAAS,GAAG,GAAW,EAAE;IAC7B,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAC3C,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CACjE,CAAC;IACF,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;AAClC,CAAC,CAAC;AAcF,4GAA4G;AAC5G,MAAM,UAAU,8BAA8B,CAC5C,QAA6B,EAC7B,UAAiD;IAEjD,IAAI,QAAQ,CAAC,UAAU,KAAK,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,MAAM,KAAK,MAAM;QAAE,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;IAC3F,MAAM,OAAO,GAAG,QAAQ,CAAC,UAAU,GAAG,QAAQ,CAAC,aAAa,CAAC;IAC7D,MAAM,KAAK,GAAG,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,KAAK,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;IACjF,MAAM,eAAe,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAC/F,IAAI;KACL,CAAC,CAAC,CAAC;IACJ,OAAO;QACL,SAAS,EAAE;YACT;gBACE,IAAI,EAAE,iBAAiB;gBACvB,OAAO,EAAE,oCAAoC,OAAO,IAAI,QAAQ,CAAC,UAAU,gKAAgK,KAAK,IAAI;gBACpP,QAAQ,EAAE,OAAO;gBACjB,IAAI,EAAE;oBACJ,OAAO,EAAE,mBAAmB,CAC1B,CAAC,cAAc,EAAE,eAAe,EAAE,SAAS,EAAE,CAAC,EAC9C,UAAU,CAAC,iBAAiB,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CACxD;iBACF;gBACD,EAAE,EAAE;oBACF,IAAI,EAAE,SAAS,EAAE;oBACjB,GAAG,CAAC,eAAe,CAAC,MAAM,KAAK,CAAC;wBAC9B,CAAC,CAAC,EAAE;wBACJ,CAAC,CAAC,EAAE,OAAO,EAAE,mBAAmB,CAAC,EAAE,EAAE,eAAe,CAAC,EAAE,CAAC;oBAC1D,kBAAkB,EAAE,CAAC,WAAW,CAAC;iBAClC;aACF;SACF;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { EnvAccessAnalysis } from '../detector/env-access-detector.js';
|
|
2
2
|
import { type EslintFlatConfigBlock } from './console-isolation-emitters.js';
|
|
3
|
+
export declare const ENV_ACCESS_RULE = "env-access";
|
|
3
4
|
export declare function toEslintEnvAccess(analysis: EnvAccessAnalysis): EslintFlatConfigBlock | null;
|
|
4
5
|
//# sourceMappingURL=env-access-emitters.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"env-access-emitters.d.ts","sourceRoot":"","sources":["../../src/generator/env-access-emitters.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AAC5E,OAAO,EAAuB,KAAK,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AAGlG,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,iBAAiB,GAAG,qBAAqB,GAAG,IAAI,CAgB3F"}
|
|
1
|
+
{"version":3,"file":"env-access-emitters.d.ts","sourceRoot":"","sources":["../../src/generator/env-access-emitters.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AAC5E,OAAO,EAAuB,KAAK,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AAGlG,eAAO,MAAM,eAAe,eAAe,CAAC;AAE5C,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,iBAAiB,GAAG,qBAAqB,GAAG,IAAI,CAgB3F"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { withMinedExemptions } from './console-isolation-emitters.js';
|
|
2
2
|
import { CONFIG_GLOBS, TEST_GLOBS } from './eslint-scope.js';
|
|
3
|
+
export const ENV_ACCESS_RULE = 'env-access';
|
|
3
4
|
export function toEslintEnvAccess(analysis) {
|
|
4
5
|
if (analysis.subjectFileCount === 0 || analysis.gate.status !== 'AUTO')
|
|
5
6
|
return null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"env-access-emitters.js","sourceRoot":"","sources":["../../src/generator/env-access-emitters.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAA8B,MAAM,iCAAiC,CAAC;AAClG,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE7D,MAAM,UAAU,iBAAiB,CAAC,QAA2B;IAC3D,IAAI,QAAQ,CAAC,gBAAgB,KAAK,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,MAAM,KAAK,MAAM;QAAE,OAAO,IAAI,CAAC;IACpF,OAAO;QACL,KAAK,EAAE,CAAC,eAAe,CAAC;QACxB,OAAO,EAAE,mBAAmB,CAAC,CAAC,GAAG,UAAU,EAAE,GAAG,YAAY,CAAC,EAAE,QAAQ,CAAC,UAAU,CAAC;QACnF,KAAK,EAAE;YACL,0BAA0B,EAAE;gBAC1B,OAAO;gBACP;oBACE,MAAM,EAAE,SAAS;oBACjB,QAAQ,EAAE,KAAK;oBACf,OAAO,EAAE,0DAA0D;iBACpE;aACF;SACF;KACF,CAAC;AACJ,CAAC"}
|
|
1
|
+
{"version":3,"file":"env-access-emitters.js","sourceRoot":"","sources":["../../src/generator/env-access-emitters.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAA8B,MAAM,iCAAiC,CAAC;AAClG,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE7D,MAAM,CAAC,MAAM,eAAe,GAAG,YAAY,CAAC;AAE5C,MAAM,UAAU,iBAAiB,CAAC,QAA2B;IAC3D,IAAI,QAAQ,CAAC,gBAAgB,KAAK,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,MAAM,KAAK,MAAM;QAAE,OAAO,IAAI,CAAC;IACpF,OAAO;QACL,KAAK,EAAE,CAAC,eAAe,CAAC;QACxB,OAAO,EAAE,mBAAmB,CAAC,CAAC,GAAG,UAAU,EAAE,GAAG,YAAY,CAAC,EAAE,QAAQ,CAAC,UAAU,CAAC;QACnF,KAAK,EAAE;YACL,0BAA0B,EAAE;gBAC1B,OAAO;gBACP;oBACE,MAAM,EAAE,SAAS;oBACjB,QAAQ,EAAE,KAAK;oBACf,OAAO,EAAE,0DAA0D;iBACpE;aACF;SACF;KACF,CAAC;AACJ,CAAC"}
|