archprint 0.13.1 → 0.14.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 +14 -0
- package/README.md +17 -8
- package/dist/cli/adopted-rules.d.ts +10 -1
- package/dist/cli/adopted-rules.d.ts.map +1 -1
- package/dist/cli/adopted-rules.js +63 -0
- package/dist/cli/adopted-rules.js.map +1 -1
- package/dist/cli/allow.d.ts.map +1 -1
- package/dist/cli/allow.js +11 -3
- package/dist/cli/allow.js.map +1 -1
- package/dist/cli/allowed-evidence.d.ts.map +1 -1
- package/dist/cli/allowed-evidence.js +78 -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 +46 -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 +70 -23
- package/dist/cli/generate.js.map +1 -1
- package/dist/cli/recommend.d.ts.map +1 -1
- package/dist/cli/recommend.js +12 -7
- package/dist/cli/recommend.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/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/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/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/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/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 +1 -1
- 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
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The npm package an import specifier names, or null for a relative path, a Node builtin, a tsconfig alias, a
|
|
3
|
+
* `#` subpath import, or a `scheme:` specifier. Self-contained: the generated ESLint rules embed it.
|
|
4
|
+
*/
|
|
5
|
+
export function packageName(specifier, aliasPrefixes, builtins) {
|
|
6
|
+
if (specifier.startsWith('.') || specifier.startsWith('#'))
|
|
7
|
+
return null;
|
|
8
|
+
if (/^[a-z][a-z0-9+.-]*:/i.test(specifier))
|
|
9
|
+
return null;
|
|
10
|
+
if (builtins.has(specifier) || builtins.has(specifier.split('/')[0]))
|
|
11
|
+
return null;
|
|
12
|
+
if (aliasPrefixes.some((prefix) => specifier === prefix || specifier.startsWith(`${prefix}/`))) {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
const parts = specifier.split('/');
|
|
16
|
+
return specifier.startsWith('@') ? parts.slice(0, 2).join('/') : parts[0];
|
|
17
|
+
}
|
|
18
|
+
/** The package names a package.json text declares in any dependency field. Self-contained: see packageName. */
|
|
19
|
+
export function declaredPackages(packageJsonText) {
|
|
20
|
+
let json;
|
|
21
|
+
try {
|
|
22
|
+
json = JSON.parse(packageJsonText);
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return [];
|
|
26
|
+
}
|
|
27
|
+
return ['dependencies', 'devDependencies', 'peerDependencies', 'optionalDependencies'].flatMap((field) => {
|
|
28
|
+
const deps = json[field];
|
|
29
|
+
return deps !== null && typeof deps === 'object' ? Object.keys(deps) : [];
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
/** Whether an import of package `name` reaches into its build or implementation folders. Self-contained. */
|
|
33
|
+
export function isPackageInternal(specifier, name) {
|
|
34
|
+
const subpath = specifier.slice(name.length + 1).split('/')[0] ?? '';
|
|
35
|
+
return ['src', 'internal', 'internals'].includes(subpath);
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=package-name.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"package-name.js","sourceRoot":"","sources":["../../src/scanner/package-name.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,UAAU,WAAW,CACzB,SAAiB,EACjB,aAAgC,EAChC,QAA6B;IAE7B,IAAI,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IACxE,IAAI,sBAAsB,CAAC,IAAI,CAAC,SAAS,CAAC;QAAE,OAAO,IAAI,CAAC;IACxD,IAAI,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC;QAAE,OAAO,IAAI,CAAC;IACnF,IAAI,aAAa,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,SAAS,KAAK,MAAM,IAAI,SAAS,CAAC,UAAU,CAAC,GAAG,MAAM,GAAG,CAAC,CAAC,EAAE,CAAC;QAC/F,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACnC,OAAO,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC;AAC7E,CAAC;AAED,+GAA+G;AAC/G,MAAM,UAAU,gBAAgB,CAAC,eAAuB;IACtD,IAAI,IAA6B,CAAC;IAClC,IAAI,CAAC;QACH,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,eAAe,CAA4B,CAAC;IAChE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,OAAO,CAAC,cAAc,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,sBAAsB,CAAC,CAAC,OAAO,CAC5F,CAAC,KAAK,EAAE,EAAE;QACR,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;QACzB,OAAO,IAAI,KAAK,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC5E,CAAC,CACF,CAAC;AACJ,CAAC;AAED,4GAA4G;AAC5G,MAAM,UAAU,iBAAiB,CAAC,SAAiB,EAAE,IAAY;IAC/D,MAAM,OAAO,GAAG,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACrE,OAAO,CAAC,KAAK,EAAE,UAAU,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;AAC5D,CAAC"}
|
|
@@ -2,5 +2,10 @@ export interface AliasEntry {
|
|
|
2
2
|
prefix: string;
|
|
3
3
|
dir: string;
|
|
4
4
|
}
|
|
5
|
+
/**
|
|
6
|
+
* The files an import of `base` (a path without resolution) can mean, in the order TypeScript-style resolution
|
|
7
|
+
* tries them. Self-contained: the generated ESLint rules embed it.
|
|
8
|
+
*/
|
|
9
|
+
export declare function firstPartyCandidates(base: string): string[];
|
|
5
10
|
export declare function resolveFirstPartyImport(specifier: string, fromAbsPath: string, aliases: readonly AliasEntry[]): string | null;
|
|
6
11
|
//# sourceMappingURL=resolve-import.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolve-import.d.ts","sourceRoot":"","sources":["../../src/scanner/resolve-import.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;CACb;
|
|
1
|
+
{"version":3,"file":"resolve-import.d.ts","sourceRoot":"","sources":["../../src/scanner/resolve-import.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAiB3D;AAkBD,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,SAAS,UAAU,EAAE,GAC7B,MAAM,GAAG,IAAI,CAOf"}
|
|
@@ -1,13 +1,25 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs';
|
|
2
2
|
import * as path from 'node:path';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
3
|
+
/**
|
|
4
|
+
* The files an import of `base` (a path without resolution) can mean, in the order TypeScript-style resolution
|
|
5
|
+
* tries them. Self-contained: the generated ESLint rules embed it.
|
|
6
|
+
*/
|
|
7
|
+
export function firstPartyCandidates(base) {
|
|
8
|
+
const jsToTs = {
|
|
9
|
+
'.js': ['.ts', '.tsx'],
|
|
10
|
+
'.jsx': ['.tsx'],
|
|
11
|
+
'.mjs': ['.ts', '.tsx'],
|
|
12
|
+
'.cjs': ['.ts', '.tsx'],
|
|
13
|
+
};
|
|
14
|
+
const name = base.slice(Math.max(base.lastIndexOf('/'), base.lastIndexOf('\\')) + 1);
|
|
15
|
+
const dot = name.lastIndexOf('.');
|
|
16
|
+
const extension = dot > 0 ? name.slice(dot) : '';
|
|
17
|
+
const candidates = (jsToTs[extension] ?? []).map((tsExtension) => base.slice(0, -extension.length) + tsExtension);
|
|
18
|
+
for (const suffix of ['', '.ts', '.tsx', '.vue', '.svelte', '/index.ts', '/index.tsx']) {
|
|
19
|
+
candidates.push(base + suffix);
|
|
20
|
+
}
|
|
21
|
+
return candidates.filter((candidate) => /\.(ts|tsx|vue|svelte)$/.test(candidate));
|
|
22
|
+
}
|
|
11
23
|
function specifierBase(specifier, fromAbsPath, aliases) {
|
|
12
24
|
if (specifier.startsWith('.')) {
|
|
13
25
|
return path.resolve(path.dirname(fromAbsPath), specifier);
|
|
@@ -23,17 +35,8 @@ export function resolveFirstPartyImport(specifier, fromAbsPath, aliases) {
|
|
|
23
35
|
const base = specifierBase(specifier, fromAbsPath, aliases);
|
|
24
36
|
if (base === null)
|
|
25
37
|
return null;
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
if (tsExtensions !== undefined) {
|
|
29
|
-
const stem = base.slice(0, -path.extname(base).length);
|
|
30
|
-
for (const tsExt of tsExtensions)
|
|
31
|
-
candidates.push(stem + tsExt);
|
|
32
|
-
}
|
|
33
|
-
for (const suffix of BARE_CANDIDATES)
|
|
34
|
-
candidates.push(base + suffix);
|
|
35
|
-
for (const candidate of candidates) {
|
|
36
|
-
if (FIRST_PARTY_TARGET.test(candidate) && existsSync(candidate))
|
|
38
|
+
for (const candidate of firstPartyCandidates(base)) {
|
|
39
|
+
if (existsSync(candidate))
|
|
37
40
|
return candidate;
|
|
38
41
|
}
|
|
39
42
|
return null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolve-import.js","sourceRoot":"","sources":["../../src/scanner/resolve-import.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAOlC,MAAM,
|
|
1
|
+
{"version":3,"file":"resolve-import.js","sourceRoot":"","sources":["../../src/scanner/resolve-import.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAOlC;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAAY;IAC/C,MAAM,MAAM,GAAsC;QAChD,KAAK,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC;QACtB,MAAM,EAAE,CAAC,MAAM,CAAC;QAChB,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC;QACvB,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC;KACxB,CAAC;IACF,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IACrF,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IAClC,MAAM,SAAS,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACjD,MAAM,UAAU,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG,CAC9C,CAAC,WAAW,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,WAAW,CAChE,CAAC;IACF,KAAK,MAAM,MAAM,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,YAAY,CAAC,EAAE,CAAC;QACvF,UAAU,CAAC,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC;IACjC,CAAC;IACD,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,wBAAwB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;AACpF,CAAC;AAED,SAAS,aAAa,CACpB,SAAiB,EACjB,WAAmB,EACnB,OAA8B;IAE9B,IAAI,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QAC9B,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,SAAS,CAAC,CAAC;IAC5D,CAAC;IACD,KAAK,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,OAAO,EAAE,CAAC;QACtC,IAAI,SAAS,KAAK,MAAM,IAAI,SAAS,CAAC,UAAU,CAAC,GAAG,MAAM,GAAG,CAAC,EAAE,CAAC;YAC/D,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC;QAC9E,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,uBAAuB,CACrC,SAAiB,EACjB,WAAmB,EACnB,OAA8B;IAE9B,MAAM,IAAI,GAAG,aAAa,CAAC,SAAS,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC;IAC5D,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAC/B,KAAK,MAAM,SAAS,IAAI,oBAAoB,CAAC,IAAI,CAAC,EAAE,CAAC;QACnD,IAAI,UAAU,CAAC,SAAS,CAAC;YAAE,OAAO,SAAS,CAAC;IAC9C,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -6,8 +6,17 @@ export interface RoleClassification {
|
|
|
6
6
|
}
|
|
7
7
|
export declare const ROLE_PATTERNS: ReadonlyMap<Role, readonly RegExp[]>;
|
|
8
8
|
export declare const REQUEST_ENTRY_ROLES: readonly Role[];
|
|
9
|
+
/** The index of the first rule whose pattern matches the path, or -1. Self-contained: the ESLint rules embed it. */
|
|
10
|
+
export declare function firstMatchingRule(relativePath: string, rules: readonly {
|
|
11
|
+
test: RegExp;
|
|
12
|
+
}[]): number;
|
|
13
|
+
/** The role rules in the order classifyFile tries them, as regex sources. */
|
|
14
|
+
export declare const ROLE_RULE_SOURCES: readonly {
|
|
15
|
+
role: Role;
|
|
16
|
+
source: string;
|
|
17
|
+
}[];
|
|
9
18
|
export declare function classifyFile(relativePath: string): RoleClassification;
|
|
10
|
-
export declare
|
|
11
|
-
export declare
|
|
19
|
+
export declare const hasUseServerDirective: (sourceHead: string) => boolean;
|
|
20
|
+
export declare const hasUseClientDirective: (sourceHead: string) => boolean;
|
|
12
21
|
export declare function classifyFileWithDirective(relativePath: string, hasServerDirective: boolean): RoleClassification;
|
|
13
22
|
//# sourceMappingURL=role-classifier.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"role-classifier.d.ts","sourceRoot":"","sources":["../../src/scanner/role-classifier.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"role-classifier.d.ts","sourceRoot":"","sources":["../../src/scanner/role-classifier.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,IAAI,GACZ,YAAY,GACZ,SAAS,GACT,YAAY,GACZ,eAAe,GACf,aAAa,GACb,eAAe,GACf,aAAa,GACb,aAAa,GACb,aAAa,GACb,WAAW,GACX,QAAQ,GACR,aAAa,GACb,QAAQ,GACR,MAAM,GACN,WAAW,GACX,SAAS,CAAC;AAEd,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,IAAI,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAoHD,eAAO,MAAM,aAAa,EAAE,WAAW,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAO9D,CAAC;AAEF,eAAO,MAAM,mBAAmB,EAAE,SAAS,IAAI,EAM9C,CAAC;AAEF,oHAAoH;AACpH,wBAAgB,iBAAiB,CAC/B,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,SAAS;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,GACjC,MAAM,CAGR;AAED,6EAA6E;AAC7E,eAAO,MAAM,iBAAiB,EAAE,SAAS;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,EAEtE,CAAC;AAEF,wBAAgB,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,kBAAkB,CAKrE;AAED,eAAO,MAAM,qBAAqB,GAAI,YAAY,MAAM,KAAG,OACZ,CAAC;AAEhD,eAAO,MAAM,qBAAqB,GAAI,YAAY,MAAM,KAAG,OACZ,CAAC;AAEhD,wBAAgB,yBAAyB,CACvC,YAAY,EAAE,MAAM,EACpB,kBAAkB,EAAE,OAAO,GAC1B,kBAAkB,CAOpB"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { hasLeadingDirective } from './directives.js';
|
|
1
2
|
const ROLE_RULES = [
|
|
2
3
|
{
|
|
3
4
|
role: 'TEST',
|
|
@@ -116,48 +117,21 @@ export const REQUEST_ENTRY_ROLES = [
|
|
|
116
117
|
'API_HANDLER',
|
|
117
118
|
'TRPC_ROUTER',
|
|
118
119
|
];
|
|
119
|
-
|
|
120
|
+
/** The index of the first rule whose pattern matches the path, or -1. Self-contained: the ESLint rules embed it. */
|
|
121
|
+
export function firstMatchingRule(relativePath, rules) {
|
|
120
122
|
const normalizedPath = relativePath.replace(/\\/g, '/');
|
|
121
|
-
|
|
122
|
-
if (rule.test.test(normalizedPath)) {
|
|
123
|
-
return { role: rule.role, confidence: rule.confidence, matchedRule: rule.id };
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
return { role: 'UNKNOWN', confidence: 0, matchedRule: null };
|
|
127
|
-
}
|
|
128
|
-
const USE_SERVER_LITERAL = /^["']use server["']/;
|
|
129
|
-
const USE_CLIENT_LITERAL = /^["']use client["']/;
|
|
130
|
-
const isWhitespace = (c) => c === ' ' || c === '\t' || c === '\n' || c === '\r' || c === '\f' || c === '\v';
|
|
131
|
-
function hasLeadingDirective(sourceHead, literal) {
|
|
132
|
-
let i = 0;
|
|
133
|
-
const n = sourceHead.length;
|
|
134
|
-
for (;;) {
|
|
135
|
-
while (i < n && isWhitespace(sourceHead[i]))
|
|
136
|
-
i++;
|
|
137
|
-
if (sourceHead.startsWith('//', i)) {
|
|
138
|
-
const newline = sourceHead.indexOf('\n', i);
|
|
139
|
-
if (newline === -1)
|
|
140
|
-
return false;
|
|
141
|
-
i = newline + 1;
|
|
142
|
-
}
|
|
143
|
-
else if (sourceHead.startsWith('/*', i)) {
|
|
144
|
-
const end = sourceHead.indexOf('*/', i + 2);
|
|
145
|
-
if (end === -1)
|
|
146
|
-
return false;
|
|
147
|
-
i = end + 2;
|
|
148
|
-
}
|
|
149
|
-
else {
|
|
150
|
-
break;
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
return literal.test(sourceHead.slice(i));
|
|
154
|
-
}
|
|
155
|
-
export function hasUseServerDirective(sourceHead) {
|
|
156
|
-
return hasLeadingDirective(sourceHead, USE_SERVER_LITERAL);
|
|
123
|
+
return rules.findIndex((rule) => rule.test.test(normalizedPath));
|
|
157
124
|
}
|
|
158
|
-
|
|
159
|
-
|
|
125
|
+
/** The role rules in the order classifyFile tries them, as regex sources. */
|
|
126
|
+
export const ROLE_RULE_SOURCES = ROLE_RULES.map((rule) => ({ role: rule.role, source: rule.test.source }));
|
|
127
|
+
export function classifyFile(relativePath) {
|
|
128
|
+
const rule = ROLE_RULES[firstMatchingRule(relativePath, ROLE_RULES)];
|
|
129
|
+
return rule === undefined
|
|
130
|
+
? { role: 'UNKNOWN', confidence: 0, matchedRule: null }
|
|
131
|
+
: { role: rule.role, confidence: rule.confidence, matchedRule: rule.id };
|
|
160
132
|
}
|
|
133
|
+
export const hasUseServerDirective = (sourceHead) => hasLeadingDirective(sourceHead, 'use server');
|
|
134
|
+
export const hasUseClientDirective = (sourceHead) => hasLeadingDirective(sourceHead, 'use client');
|
|
161
135
|
export function classifyFileWithDirective(relativePath, hasServerDirective) {
|
|
162
136
|
const base = classifyFile(relativePath);
|
|
163
137
|
const isTsx = /\.tsx$/.test(relativePath.replace(/\\/g, '/'));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"role-classifier.js","sourceRoot":"","sources":["../../src/scanner/role-classifier.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"role-classifier.js","sourceRoot":"","sources":["../../src/scanner/role-classifier.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import type { LayerBoundary } from '../detector/layer-detector.js';
|
|
2
|
-
import { type LayerAlias } from '../detector/layer-paths.js';
|
|
3
|
-
export interface EslintLayerRule {
|
|
4
|
-
name: string;
|
|
5
|
-
from: string;
|
|
6
|
-
to: string;
|
|
7
|
-
message: string;
|
|
8
|
-
ignore: string[];
|
|
9
|
-
}
|
|
10
|
-
/** The app the rules enforce: where it is, its import aliases, and the gitignored paths the scan left out. */
|
|
11
|
-
export interface LayerApp {
|
|
12
|
-
appDir: string;
|
|
13
|
-
aliases: LayerAlias[];
|
|
14
|
-
ignored: string[];
|
|
15
|
-
}
|
|
16
|
-
export interface EslintLayers extends LayerApp {
|
|
17
|
-
rules: EslintLayerRule[];
|
|
18
|
-
}
|
|
19
|
-
/** The given layer boundaries as ESLint rules, each exempting its known and allowed exceptions. */
|
|
20
|
-
export declare function buildEslintLayers(boundaries: readonly LayerBoundary[], app: LayerApp, allowedFor: (ruleId: string) => readonly string[]): EslintLayers | null;
|
|
21
|
-
export interface RenderedEslintLayers {
|
|
22
|
-
imports: string;
|
|
23
|
-
source: string;
|
|
24
|
-
rules: string;
|
|
25
|
-
config: string;
|
|
26
|
-
}
|
|
27
|
-
/** The pieces of the generated ESLint file that enforce layer boundaries, located relative to that file. */
|
|
28
|
-
export declare function renderEslintLayers(layers: EslintLayers, outDir: string): RenderedEslintLayers;
|
|
29
|
-
//# sourceMappingURL=eslint-layer-emitter.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"eslint-layer-emitter.d.ts","sourceRoot":"","sources":["../../src/generator/eslint-layer-emitter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,EAAE,KAAK,UAAU,EAAkC,MAAM,4BAA4B,CAAC;AAM7F,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,8GAA8G;AAC9G,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,YAAa,SAAQ,QAAQ;IAC5C,KAAK,EAAE,eAAe,EAAE,CAAC;CAC1B;AAED,mGAAmG;AACnG,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,SAAS,aAAa,EAAE,EACpC,GAAG,EAAE,QAAQ,EACb,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,SAAS,MAAM,EAAE,GAChD,YAAY,GAAG,IAAI,CAgBrB;AAkED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,4GAA4G;AAC5G,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,GAAG,oBAAoB,CA+B7F"}
|
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
import * as path from 'node:path';
|
|
2
|
-
import { layerRootOf, resolveImportPath } from '../detector/layer-paths.js';
|
|
3
|
-
import { ROLE_PATTERNS } from '../scanner/role-classifier.js';
|
|
4
|
-
import { isSkippedFolder, isSourceFileName } from '../scanner/source-paths.js';
|
|
5
|
-
import { LINTED_FILES } from './eslint-plugin-emitter.js';
|
|
6
|
-
import { layerRuleName } from './layer-emitters.js';
|
|
7
|
-
/** The given layer boundaries as ESLint rules, each exempting its known and allowed exceptions. */
|
|
8
|
-
export function buildEslintLayers(boundaries, app, allowedFor) {
|
|
9
|
-
const rules = boundaries.map((boundary) => {
|
|
10
|
-
const name = layerRuleName(boundary);
|
|
11
|
-
const exceptions = [
|
|
12
|
-
...boundary.violations.map((violation) => violation.file),
|
|
13
|
-
...allowedFor(name),
|
|
14
|
-
];
|
|
15
|
-
return {
|
|
16
|
-
name,
|
|
17
|
-
from: boundary.from,
|
|
18
|
-
to: boundary.to,
|
|
19
|
-
message: boundary.description,
|
|
20
|
-
ignore: [...new Set(exceptions)].sort(),
|
|
21
|
-
};
|
|
22
|
-
});
|
|
23
|
-
return rules.length === 0 ? null : { ...app, rules };
|
|
24
|
-
}
|
|
25
|
-
const LAYER_RULE_FUNCTIONS = `function isValueImport(node) {
|
|
26
|
-
return (
|
|
27
|
-
node.importKind !== 'type' &&
|
|
28
|
-
(node.specifiers.length === 0 ||
|
|
29
|
-
node.specifiers.some((specifier) => specifier.type !== 'ImportSpecifier' || specifier.importKind !== 'type'))
|
|
30
|
-
);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function realPathOf(filename) {
|
|
34
|
-
try {
|
|
35
|
-
return realpathSync(filename);
|
|
36
|
-
} catch {
|
|
37
|
-
try {
|
|
38
|
-
return join(realpathSync(dirname(filename)), basename(filename));
|
|
39
|
-
} catch {
|
|
40
|
-
return filename;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function isScanned(file) {
|
|
46
|
-
const segments = file.split('/');
|
|
47
|
-
return (
|
|
48
|
-
isSourceFileName(segments.pop()) &&
|
|
49
|
-
!segments.some(isSkippedFolder) &&
|
|
50
|
-
!LAYERS.ignored.some((path) => file === path || file.startsWith(path + '/'))
|
|
51
|
-
);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function appRelativePath(filename) {
|
|
55
|
-
const relativePath = relative(LAYER_APP_DIR, realPathOf(filename));
|
|
56
|
-
return relativePath.startsWith('..') || isAbsolute(relativePath)
|
|
57
|
-
? null
|
|
58
|
-
: relativePath.split(sep).join('/');
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
function makeLayerRule(spec) {
|
|
62
|
-
return {
|
|
63
|
-
meta: { type: 'problem', schema: [], messages: { forbidden: spec.message } },
|
|
64
|
-
create(context) {
|
|
65
|
-
const file = appRelativePath(context.physicalFilename);
|
|
66
|
-
if (file === null || !isScanned(file)) return {};
|
|
67
|
-
if (LAYER_TESTS.some((test) => test.test(file)) || spec.ignore.includes(file)) return {};
|
|
68
|
-
if (layerRootOf(file)?.layer !== spec.from) return {};
|
|
69
|
-
const check = (node, specifier) => {
|
|
70
|
-
const target = resolveImportPath(file, specifier, LAYERS.aliases);
|
|
71
|
-
if (target !== null && layerRootOf(target)?.layer === spec.to) {
|
|
72
|
-
context.report({ node, messageId: 'forbidden' });
|
|
73
|
-
}
|
|
74
|
-
};
|
|
75
|
-
return {
|
|
76
|
-
ImportDeclaration(node) {
|
|
77
|
-
if (node.parent.type === 'Program' && isValueImport(node)) check(node, node.source.value);
|
|
78
|
-
},
|
|
79
|
-
ImportExpression(node) {
|
|
80
|
-
if (node.source.type === 'Literal' && typeof node.source.value === 'string') {
|
|
81
|
-
check(node, node.source.value);
|
|
82
|
-
}
|
|
83
|
-
},
|
|
84
|
-
};
|
|
85
|
-
},
|
|
86
|
-
};
|
|
87
|
-
}`;
|
|
88
|
-
/** The pieces of the generated ESLint file that enforce layer boundaries, located relative to that file. */
|
|
89
|
-
export function renderEslintLayers(layers, outDir) {
|
|
90
|
-
const data = {
|
|
91
|
-
app: path.relative(outDir, layers.appDir).split(path.sep).join('/') || '.',
|
|
92
|
-
aliases: layers.aliases,
|
|
93
|
-
ignored: layers.ignored,
|
|
94
|
-
tests: (ROLE_PATTERNS.get('TEST') ?? []).map((pattern) => pattern.source),
|
|
95
|
-
rules: layers.rules,
|
|
96
|
-
};
|
|
97
|
-
return {
|
|
98
|
-
imports: [
|
|
99
|
-
"import { realpathSync } from 'node:fs';",
|
|
100
|
-
"import { basename, dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';",
|
|
101
|
-
"import { fileURLToPath } from 'node:url';",
|
|
102
|
-
].join('\n'),
|
|
103
|
-
source: [
|
|
104
|
-
`const LAYERS = ${JSON.stringify(data, null, 2)};`,
|
|
105
|
-
'const LAYER_APP_DIR = realPathOf(resolve(dirname(fileURLToPath(import.meta.url)), LAYERS.app));',
|
|
106
|
-
'const LAYER_TESTS = LAYERS.tests.map((source) => new RegExp(source));',
|
|
107
|
-
layerRootOf.toString(),
|
|
108
|
-
resolveImportPath.toString(),
|
|
109
|
-
isSkippedFolder.toString(),
|
|
110
|
-
isSourceFileName.toString(),
|
|
111
|
-
LAYER_RULE_FUNCTIONS,
|
|
112
|
-
].join('\n\n'),
|
|
113
|
-
rules: 'LAYERS.rules.map((spec) => [spec.name, makeLayerRule(spec)])',
|
|
114
|
-
config: `{
|
|
115
|
-
files: ${LINTED_FILES},
|
|
116
|
-
plugins: { archprint: plugin },
|
|
117
|
-
rules: Object.fromEntries(LAYERS.rules.map((spec) => ['archprint/' + spec.name, 'error'])),
|
|
118
|
-
}`,
|
|
119
|
-
};
|
|
120
|
-
}
|
|
121
|
-
//# sourceMappingURL=eslint-layer-emitter.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"eslint-layer-emitter.js","sourceRoot":"","sources":["../../src/generator/eslint-layer-emitter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,OAAO,EAAmB,WAAW,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC7F,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAC/E,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAqBpD,mGAAmG;AACnG,MAAM,UAAU,iBAAiB,CAC/B,UAAoC,EACpC,GAAa,EACb,UAAiD;IAEjD,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE;QACxC,MAAM,IAAI,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;QACrC,MAAM,UAAU,GAAG;YACjB,GAAG,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC;YACzD,GAAG,UAAU,CAAC,IAAI,CAAC;SACpB,CAAC;QACF,OAAO;YACL,IAAI;YACJ,IAAI,EAAE,QAAQ,CAAC,IAAI;YACnB,EAAE,EAAE,QAAQ,CAAC,EAAE;YACf,OAAO,EAAE,QAAQ,CAAC,WAAW;YAC7B,MAAM,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,EAAE;SACxC,CAAC;IACJ,CAAC,CAAC,CAAC;IACH,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,GAAG,EAAE,KAAK,EAAE,CAAC;AACvD,CAAC;AAED,MAAM,oBAAoB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA8D3B,CAAC;AASH,4GAA4G;AAC5G,MAAM,UAAU,kBAAkB,CAAC,MAAoB,EAAE,MAAc;IACrE,MAAM,IAAI,GAAG;QACX,GAAG,EAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG;QAC1E,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,KAAK,EAAE,CAAC,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC;QACzE,KAAK,EAAE,MAAM,CAAC,KAAK;KACpB,CAAC;IACF,OAAO;QACL,OAAO,EAAE;YACP,yCAAyC;YACzC,0FAA0F;YAC1F,2CAA2C;SAC5C,CAAC,IAAI,CAAC,IAAI,CAAC;QACZ,MAAM,EAAE;YACN,kBAAkB,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG;YAClD,iGAAiG;YACjG,uEAAuE;YACvE,WAAW,CAAC,QAAQ,EAAE;YACtB,iBAAiB,CAAC,QAAQ,EAAE;YAC5B,eAAe,CAAC,QAAQ,EAAE;YAC1B,gBAAgB,CAAC,QAAQ,EAAE;YAC3B,oBAAoB;SACrB,CAAC,IAAI,CAAC,MAAM,CAAC;QACd,KAAK,EAAE,8DAA8D;QACrE,MAAM,EAAE;WACD,YAAY;;;EAGrB;KACC,CAAC;AACJ,CAAC"}
|