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
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { LayerBoundary } from '../detector/layer-detector.js';
|
|
2
|
+
import { type LayerAlias } from '../detector/layer-paths.js';
|
|
3
|
+
import { type ServerClientAnalysis } from '../detector/server-client-detector.js';
|
|
4
|
+
import type { DependencyInternalsAnalysis } from '../detector/dependency-internals-detector.js';
|
|
5
|
+
import { type EntryPurityAnalysis } from '../detector/entry-purity-detector.js';
|
|
6
|
+
import type { PhantomDependencyAnalysis } from '../detector/phantom-dependency-detector.js';
|
|
7
|
+
/** A rule that applies to the app's files, with the files it exempts (known and allowed exceptions). */
|
|
8
|
+
export interface AppRule {
|
|
9
|
+
name: string;
|
|
10
|
+
message: string;
|
|
11
|
+
ignore: string[];
|
|
12
|
+
}
|
|
13
|
+
export interface LayerRuleSpec extends AppRule {
|
|
14
|
+
from: string;
|
|
15
|
+
to: string;
|
|
16
|
+
}
|
|
17
|
+
export interface PhantomRuleSpec extends AppRule {
|
|
18
|
+
/** The package.json files read for declared dependencies when ESLint loads the config. */
|
|
19
|
+
packageJsons: string[];
|
|
20
|
+
workspacePackages: string[];
|
|
21
|
+
}
|
|
22
|
+
export interface ServerClientRuleSpec extends AppRule {
|
|
23
|
+
serverModules: string[];
|
|
24
|
+
}
|
|
25
|
+
export interface EntryRuleSpec extends AppRule {
|
|
26
|
+
entryRoles: string[];
|
|
27
|
+
/** The `importer -> entry` imports that existed when the rule was generated. */
|
|
28
|
+
exemptImports: string[];
|
|
29
|
+
}
|
|
30
|
+
/** The app the rules enforce: where it is, its import aliases, and the gitignored paths the scan left out. */
|
|
31
|
+
export interface AppScope {
|
|
32
|
+
appDir: string;
|
|
33
|
+
aliases: LayerAlias[];
|
|
34
|
+
ignored: string[];
|
|
35
|
+
}
|
|
36
|
+
export interface EslintAppRules extends AppScope {
|
|
37
|
+
layers: LayerRuleSpec[];
|
|
38
|
+
phantom: PhantomRuleSpec | null;
|
|
39
|
+
serverClient: ServerClientRuleSpec | null;
|
|
40
|
+
internals: AppRule | null;
|
|
41
|
+
entry: EntryRuleSpec | null;
|
|
42
|
+
}
|
|
43
|
+
type AllowedFor = (ruleId: string) => readonly string[];
|
|
44
|
+
export declare const layerRuleSpecs: (boundaries: readonly LayerBoundary[], allowedFor: AllowedFor) => LayerRuleSpec[];
|
|
45
|
+
export declare const phantomRuleSpec: (analysis: PhantomDependencyAnalysis, packageJsons: readonly string[], workspacePackages: readonly string[], allowedFor: AllowedFor) => PhantomRuleSpec;
|
|
46
|
+
export declare const serverClientRuleSpec: (analysis: ServerClientAnalysis, allowedFor: AllowedFor) => ServerClientRuleSpec;
|
|
47
|
+
export declare const internalsRuleSpec: (analysis: DependencyInternalsAnalysis, allowedFor: AllowedFor) => AppRule;
|
|
48
|
+
export declare const entryRuleSpec: (analysis: EntryPurityAnalysis, allowedFor: AllowedFor) => EntryRuleSpec;
|
|
49
|
+
export declare const hasAppRules: (rules: EslintAppRules) => boolean;
|
|
50
|
+
export interface RenderedAppRules {
|
|
51
|
+
imports: string;
|
|
52
|
+
source: string;
|
|
53
|
+
rules: string;
|
|
54
|
+
config: string;
|
|
55
|
+
}
|
|
56
|
+
/** The pieces of the generated ESLint file that enforce app-scoped rules, located relative to that file. */
|
|
57
|
+
export declare function renderEslintAppRules(rules: EslintAppRules, outDir: string): RenderedAppRules;
|
|
58
|
+
export {};
|
|
59
|
+
//# sourceMappingURL=eslint-app-emitter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eslint-app-emitter.d.ts","sourceRoot":"","sources":["../../src/generator/eslint-app-emitter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,EAAE,KAAK,UAAU,EAAkC,MAAM,4BAA4B,CAAC;AAC7F,OAAO,EAEL,KAAK,oBAAoB,EAC1B,MAAM,uCAAuC,CAAC;AAC/C,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,8CAA8C,CAAC;AAChG,OAAO,EAAe,KAAK,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAC7F,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,4CAA4C,CAAC;AAa5F,wGAAwG;AACxG,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,aAAc,SAAQ,OAAO;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,eAAgB,SAAQ,OAAO;IAC9C,0FAA0F;IAC1F,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,iBAAiB,EAAE,MAAM,EAAE,CAAC;CAC7B;AAED,MAAM,WAAW,oBAAqB,SAAQ,OAAO;IACnD,aAAa,EAAE,MAAM,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,aAAc,SAAQ,OAAO;IAC5C,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,gFAAgF;IAChF,aAAa,EAAE,MAAM,EAAE,CAAC;CACzB;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,cAAe,SAAQ,QAAQ;IAC9C,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB,OAAO,EAAE,eAAe,GAAG,IAAI,CAAC;IAChC,YAAY,EAAE,oBAAoB,GAAG,IAAI,CAAC;IAC1C,SAAS,EAAE,OAAO,GAAG,IAAI,CAAC;IAC1B,KAAK,EAAE,aAAa,GAAG,IAAI,CAAC;CAC7B;AAED,KAAK,UAAU,GAAG,CAAC,MAAM,EAAE,MAAM,KAAK,SAAS,MAAM,EAAE,CAAC;AAKxD,eAAO,MAAM,cAAc,GACzB,YAAY,SAAS,aAAa,EAAE,EACpC,YAAY,UAAU,KACrB,aAAa,EAcZ,CAAC;AAEL,eAAO,MAAM,eAAe,GAC1B,UAAU,yBAAyB,EACnC,cAAc,SAAS,MAAM,EAAE,EAC/B,mBAAmB,SAAS,MAAM,EAAE,EACpC,YAAY,UAAU,KACrB,eAUD,CAAC;AAEH,eAAO,MAAM,oBAAoB,GAC/B,UAAU,oBAAoB,EAC9B,YAAY,UAAU,KACrB,oBASD,CAAC;AAEH,eAAO,MAAM,iBAAiB,GAC5B,UAAU,2BAA2B,EACrC,YAAY,UAAU,KACrB,OASD,CAAC;AAIH,eAAO,MAAM,aAAa,GACxB,UAAU,mBAAmB,EAC7B,YAAY,UAAU,KACrB,aAOD,CAAC;AAEH,eAAO,MAAM,WAAW,GAAI,OAAO,cAAc,KAAG,OAE6C,CAAC;AA6JlG,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,4GAA4G;AAC5G,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,GAAG,gBAAgB,CAwE5F"}
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
import * as path from 'node:path';
|
|
2
|
+
import { layerRootOf, resolveImportPath } from '../detector/layer-paths.js';
|
|
3
|
+
import { SERVER_ONLY_PACKAGE, } from '../detector/server-client-detector.js';
|
|
4
|
+
import { ENTRY_ROLES } from '../detector/entry-purity-detector.js';
|
|
5
|
+
import { hasLeadingDirective } from '../scanner/directives.js';
|
|
6
|
+
import { declaredPackages, isPackageInternal, packageName } from '../scanner/package-name.js';
|
|
7
|
+
import { firstPartyCandidates } from '../scanner/resolve-import.js';
|
|
8
|
+
import { firstMatchingRule, ROLE_PATTERNS, ROLE_RULE_SOURCES } from '../scanner/role-classifier.js';
|
|
9
|
+
import { isSkippedFolder, isSourceFileName } from '../scanner/source-paths.js';
|
|
10
|
+
import { LINTED_FILES } from './eslint-plugin-emitter.js';
|
|
11
|
+
import { layerRuleName } from './layer-emitters.js';
|
|
12
|
+
import { DEPENDENCY_INTERNALS_RULE } from './dependency-internals-emitters.js';
|
|
13
|
+
import { ENTRY_PURITY_RULE } from './entry-purity-emitters.js';
|
|
14
|
+
import { PHANTOM_DEPENDENCY_RULE } from './phantom-dependency-emitters.js';
|
|
15
|
+
import { SERVER_CLIENT_RULE } from './server-client-emitters.js';
|
|
16
|
+
const exempting = (name, files, allowedFor) => [...new Set([...files, ...allowedFor(name)])].sort();
|
|
17
|
+
export const layerRuleSpecs = (boundaries, allowedFor) => boundaries.map((boundary) => {
|
|
18
|
+
const name = layerRuleName(boundary);
|
|
19
|
+
return {
|
|
20
|
+
name,
|
|
21
|
+
from: boundary.from,
|
|
22
|
+
to: boundary.to,
|
|
23
|
+
message: boundary.description,
|
|
24
|
+
ignore: exempting(name, boundary.violations.map((violation) => violation.file), allowedFor),
|
|
25
|
+
};
|
|
26
|
+
});
|
|
27
|
+
export const phantomRuleSpec = (analysis, packageJsons, workspacePackages, allowedFor) => ({
|
|
28
|
+
name: PHANTOM_DEPENDENCY_RULE,
|
|
29
|
+
message: 'Import only packages declared in package.json (archprint: the code already does).',
|
|
30
|
+
ignore: exempting(PHANTOM_DEPENDENCY_RULE, analysis.violations.map((violation) => violation.file), allowedFor),
|
|
31
|
+
packageJsons: [...packageJsons],
|
|
32
|
+
workspacePackages: [...workspacePackages],
|
|
33
|
+
});
|
|
34
|
+
export const serverClientRuleSpec = (analysis, allowedFor) => ({
|
|
35
|
+
name: SERVER_CLIENT_RULE,
|
|
36
|
+
message: `A "use client" module must not import a server-only module (archprint: the code already does not).`,
|
|
37
|
+
ignore: exempting(SERVER_CLIENT_RULE, analysis.violations.map((violation) => violation.file), allowedFor),
|
|
38
|
+
serverModules: [...analysis.serverModules],
|
|
39
|
+
});
|
|
40
|
+
export const internalsRuleSpec = (analysis, allowedFor) => ({
|
|
41
|
+
name: DEPENDENCY_INTERNALS_RULE,
|
|
42
|
+
message: 'Import a package by its public entry, not its src or internal folders (archprint: the code already does).',
|
|
43
|
+
ignore: exempting(DEPENDENCY_INTERNALS_RULE, analysis.violations.map((violation) => violation.file), allowedFor),
|
|
44
|
+
});
|
|
45
|
+
const importPair = (importer, entry) => `${importer} -> ${entry}`;
|
|
46
|
+
export const entryRuleSpec = (analysis, allowedFor) => ({
|
|
47
|
+
name: ENTRY_PURITY_RULE,
|
|
48
|
+
message: 'A page, layout or route handler is loaded by the framework; do not import it (archprint: the code already does not).',
|
|
49
|
+
ignore: exempting(ENTRY_PURITY_RULE, [], allowedFor),
|
|
50
|
+
entryRoles: [...ENTRY_ROLES],
|
|
51
|
+
exemptImports: analysis.imports.map(({ importer, file }) => importPair(importer, file)).sort(),
|
|
52
|
+
});
|
|
53
|
+
export const hasAppRules = (rules) => rules.layers.length > 0 ||
|
|
54
|
+
[rules.phantom, rules.serverClient, rules.internals, rules.entry].some((spec) => spec !== null);
|
|
55
|
+
const APP_RUNTIME = `function realPathOf(filename) {
|
|
56
|
+
try {
|
|
57
|
+
return realpathSync(filename);
|
|
58
|
+
} catch {
|
|
59
|
+
try {
|
|
60
|
+
return join(realpathSync(dirname(filename)), basename(filename));
|
|
61
|
+
} catch {
|
|
62
|
+
return filename;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function isValueImport(node) {
|
|
68
|
+
return (
|
|
69
|
+
node.importKind !== 'type' &&
|
|
70
|
+
(node.specifiers.length === 0 ||
|
|
71
|
+
node.specifiers.some((specifier) => specifier.type !== 'ImportSpecifier' || specifier.importKind !== 'type'))
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function isScanned(file) {
|
|
76
|
+
const segments = file.split('/');
|
|
77
|
+
return (
|
|
78
|
+
isSourceFileName(segments.pop()) &&
|
|
79
|
+
!segments.some(isSkippedFolder) &&
|
|
80
|
+
!APP.ignored.some((path) => file === path || file.startsWith(path + '/'))
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function appRelativePath(filename) {
|
|
85
|
+
const relativePath = relative(APP_DIR, realPathOf(filename));
|
|
86
|
+
return relativePath.startsWith('..') || isAbsolute(relativePath)
|
|
87
|
+
? null
|
|
88
|
+
: relativePath.split(sep).join('/');
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function importVisitors(check) {
|
|
92
|
+
return {
|
|
93
|
+
ImportDeclaration(node) {
|
|
94
|
+
if (node.parent.type === 'Program' && isValueImport(node)) check(node, node.source.value);
|
|
95
|
+
},
|
|
96
|
+
ImportExpression(node) {
|
|
97
|
+
if (node.source.type === 'Literal' && typeof node.source.value === 'string') {
|
|
98
|
+
check(node, node.source.value);
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function isTestFile(file) {
|
|
105
|
+
return APP_TESTS.some((test) => test.test(file));
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function appRule(spec, create) {
|
|
109
|
+
return {
|
|
110
|
+
meta: { type: 'problem', schema: [], messages: { forbidden: spec.message } },
|
|
111
|
+
create(context) {
|
|
112
|
+
const file = appRelativePath(context.physicalFilename);
|
|
113
|
+
if (file === null || !isScanned(file)) return {};
|
|
114
|
+
if (isTestFile(file) || spec.ignore.includes(file)) return {};
|
|
115
|
+
return create(context, file);
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
}`;
|
|
119
|
+
const LAYER_RUNTIME = `function makeLayerRule(spec) {
|
|
120
|
+
return appRule(spec, (context, file) =>
|
|
121
|
+
layerRootOf(file)?.layer !== spec.from
|
|
122
|
+
? {}
|
|
123
|
+
: importVisitors((node, specifier) => {
|
|
124
|
+
const target = resolveImportPath(file, specifier, APP.aliases);
|
|
125
|
+
if (target !== null && layerRootOf(target)?.layer === spec.to) {
|
|
126
|
+
context.report({ node, messageId: 'forbidden' });
|
|
127
|
+
}
|
|
128
|
+
}),
|
|
129
|
+
);
|
|
130
|
+
}`;
|
|
131
|
+
const PACKAGE_RUNTIME = `const APP_ALIAS_PREFIXES = APP.aliases.map((alias) => alias.prefix);
|
|
132
|
+
const BUILTINS = new Set(builtinModules);`;
|
|
133
|
+
const TARGET_RUNTIME = `function firstPartyTarget(file, specifier) {
|
|
134
|
+
const base = resolveImportPath(file, specifier, APP.aliases);
|
|
135
|
+
if (base === null) return null;
|
|
136
|
+
return firstPartyCandidates(base).find((candidate) => existsSync(join(APP_DIR, candidate))) ?? null;
|
|
137
|
+
}`;
|
|
138
|
+
const INTERNALS_RUNTIME = `function makeInternalsRule(spec) {
|
|
139
|
+
return appRule(spec, (context) =>
|
|
140
|
+
importVisitors((node, specifier) => {
|
|
141
|
+
const name = packageName(specifier, APP_ALIAS_PREFIXES, BUILTINS);
|
|
142
|
+
if (name !== null && isPackageInternal(specifier, name)) context.report({ node, messageId: 'forbidden' });
|
|
143
|
+
}),
|
|
144
|
+
);
|
|
145
|
+
}`;
|
|
146
|
+
const ENTRY_RUNTIME = `const APP_ROLES = APP_ROLE_RULES.map(({ role, source }) => ({ role, test: new RegExp(source) }));
|
|
147
|
+
|
|
148
|
+
function roleOf(file) {
|
|
149
|
+
return APP_ROLES[firstMatchingRule(file, APP_ROLES)]?.role ?? 'UNKNOWN';
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function makeEntryRule(spec) {
|
|
153
|
+
return appRule(spec, (context, file) =>
|
|
154
|
+
spec.entryRoles.includes(roleOf(file))
|
|
155
|
+
? {}
|
|
156
|
+
: importVisitors((node, specifier) => {
|
|
157
|
+
const target = firstPartyTarget(file, specifier);
|
|
158
|
+
if (
|
|
159
|
+
target !== null &&
|
|
160
|
+
isScanned(target) &&
|
|
161
|
+
!isTestFile(target) &&
|
|
162
|
+
spec.entryRoles.includes(roleOf(target)) &&
|
|
163
|
+
!spec.exemptImports.includes(file + ' -> ' + target)
|
|
164
|
+
) {
|
|
165
|
+
context.report({ node, messageId: 'forbidden' });
|
|
166
|
+
}
|
|
167
|
+
}),
|
|
168
|
+
);
|
|
169
|
+
}`;
|
|
170
|
+
const PHANTOM_RUNTIME = `const PHANTOM_DECLARED = new Set([
|
|
171
|
+
...PHANTOM.workspacePackages,
|
|
172
|
+
...PHANTOM.packageJsons.flatMap((file) => {
|
|
173
|
+
try {
|
|
174
|
+
return declaredPackages(readFileSync(resolve(CONFIG_DIR, file), 'utf8'));
|
|
175
|
+
} catch {
|
|
176
|
+
return [];
|
|
177
|
+
}
|
|
178
|
+
}),
|
|
179
|
+
]);
|
|
180
|
+
|
|
181
|
+
function makePhantomRule(spec) {
|
|
182
|
+
return appRule(spec, (context) =>
|
|
183
|
+
importVisitors((node, specifier) => {
|
|
184
|
+
const name = packageName(specifier, APP_ALIAS_PREFIXES, BUILTINS);
|
|
185
|
+
if (name !== null && !PHANTOM_DECLARED.has(name)) context.report({ node, messageId: 'forbidden' });
|
|
186
|
+
}),
|
|
187
|
+
);
|
|
188
|
+
}`;
|
|
189
|
+
const SERVER_CLIENT_RUNTIME = `const SERVER_MODULES = new Set(SERVER_CLIENT.serverModules);
|
|
190
|
+
|
|
191
|
+
function makeServerClientRule(spec) {
|
|
192
|
+
return appRule(spec, (context, file) =>
|
|
193
|
+
!hasLeadingDirective(context.sourceCode.text, 'use client')
|
|
194
|
+
? {}
|
|
195
|
+
: importVisitors((node, specifier) => {
|
|
196
|
+
if (specifier === ${JSON.stringify(SERVER_ONLY_PACKAGE)} || SERVER_MODULES.has(firstPartyTarget(file, specifier))) {
|
|
197
|
+
context.report({ node, messageId: 'forbidden' });
|
|
198
|
+
}
|
|
199
|
+
}),
|
|
200
|
+
);
|
|
201
|
+
}`;
|
|
202
|
+
/** The pieces of the generated ESLint file that enforce app-scoped rules, located relative to that file. */
|
|
203
|
+
export function renderEslintAppRules(rules, outDir) {
|
|
204
|
+
const relativeToConfig = (file) => path.relative(outDir, file).split(path.sep).join('/') || '.';
|
|
205
|
+
const app = {
|
|
206
|
+
app: relativeToConfig(rules.appDir),
|
|
207
|
+
aliases: rules.aliases,
|
|
208
|
+
ignored: rules.ignored,
|
|
209
|
+
tests: (ROLE_PATTERNS.get('TEST') ?? []).map((pattern) => pattern.source),
|
|
210
|
+
};
|
|
211
|
+
const { layers, phantom, serverClient, internals, entry } = rules;
|
|
212
|
+
const json = (value) => JSON.stringify(value, null, 2);
|
|
213
|
+
const specs = [
|
|
214
|
+
...layers.map((spec) => ({ spec, make: 'makeLayerRule' })),
|
|
215
|
+
...(phantom === null ? [] : [{ spec: phantom, make: 'makePhantomRule' }]),
|
|
216
|
+
...(serverClient === null ? [] : [{ spec: serverClient, make: 'makeServerClientRule' }]),
|
|
217
|
+
...(internals === null ? [] : [{ spec: internals, make: 'makeInternalsRule' }]),
|
|
218
|
+
...(entry === null ? [] : [{ spec: entry, make: 'makeEntryRule' }]),
|
|
219
|
+
];
|
|
220
|
+
const needsPackages = phantom !== null || internals !== null;
|
|
221
|
+
const needsTargets = serverClient !== null || entry !== null;
|
|
222
|
+
const source = [
|
|
223
|
+
`const APP = ${json(app)};`,
|
|
224
|
+
`const APP_RULES = ${json(specs.map(({ spec, make }) => ({ ...spec, make })))};`,
|
|
225
|
+
'const CONFIG_DIR = dirname(fileURLToPath(import.meta.url));',
|
|
226
|
+
'const APP_DIR = realPathOf(resolve(CONFIG_DIR, APP.app));',
|
|
227
|
+
'const APP_TESTS = APP.tests.map((source) => new RegExp(source));',
|
|
228
|
+
isSkippedFolder.toString(),
|
|
229
|
+
isSourceFileName.toString(),
|
|
230
|
+
resolveImportPath.toString(),
|
|
231
|
+
APP_RUNTIME,
|
|
232
|
+
...(layers.length === 0 ? [] : [layerRootOf.toString(), LAYER_RUNTIME]),
|
|
233
|
+
...(needsPackages ? [packageName.toString(), PACKAGE_RUNTIME] : []),
|
|
234
|
+
...(needsTargets ? [firstPartyCandidates.toString(), TARGET_RUNTIME] : []),
|
|
235
|
+
...(phantom === null
|
|
236
|
+
? []
|
|
237
|
+
: [
|
|
238
|
+
`const PHANTOM = ${json({ packageJsons: phantom.packageJsons.map(relativeToConfig), workspacePackages: phantom.workspacePackages })};`,
|
|
239
|
+
declaredPackages.toString(),
|
|
240
|
+
PHANTOM_RUNTIME,
|
|
241
|
+
]),
|
|
242
|
+
...(serverClient === null
|
|
243
|
+
? []
|
|
244
|
+
: [
|
|
245
|
+
`const SERVER_CLIENT = ${json({ serverModules: serverClient.serverModules })};`,
|
|
246
|
+
hasLeadingDirective.toString(),
|
|
247
|
+
SERVER_CLIENT_RUNTIME,
|
|
248
|
+
]),
|
|
249
|
+
...(internals === null ? [] : [isPackageInternal.toString(), INTERNALS_RUNTIME]),
|
|
250
|
+
...(entry === null
|
|
251
|
+
? []
|
|
252
|
+
: [
|
|
253
|
+
`const APP_ROLE_RULES = ${json(ROLE_RULE_SOURCES)};`,
|
|
254
|
+
firstMatchingRule.toString(),
|
|
255
|
+
ENTRY_RUNTIME,
|
|
256
|
+
]),
|
|
257
|
+
`const APP_MAKERS = { ${[...new Set(specs.map(({ make }) => make))].join(', ')} };`,
|
|
258
|
+
].join('\n\n');
|
|
259
|
+
return {
|
|
260
|
+
imports: [
|
|
261
|
+
"import { existsSync, readFileSync, realpathSync } from 'node:fs';",
|
|
262
|
+
"import { builtinModules } from 'node:module';",
|
|
263
|
+
"import { basename, dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';",
|
|
264
|
+
"import { fileURLToPath } from 'node:url';",
|
|
265
|
+
].join('\n'),
|
|
266
|
+
source,
|
|
267
|
+
rules: 'APP_RULES.map((spec) => [spec.name, APP_MAKERS[spec.make](spec)])',
|
|
268
|
+
config: `{
|
|
269
|
+
files: ${LINTED_FILES},
|
|
270
|
+
plugins: { archprint: plugin },
|
|
271
|
+
rules: Object.fromEntries(APP_RULES.map((spec) => ['archprint/' + spec.name, 'error'])),
|
|
272
|
+
}`,
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
//# sourceMappingURL=eslint-app-emitter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eslint-app-emitter.js","sourceRoot":"","sources":["../../src/generator/eslint-app-emitter.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { RenderedAppRules } from './eslint-app-emitter.js';
|
|
2
2
|
import { type ForbiddenImportSpec } from './eslint-plugin-emitter.js';
|
|
3
3
|
export declare function renderEslintPreset(specs: readonly ForbiddenImportSpec[], blocks: readonly unknown[], options?: {
|
|
4
4
|
ignore?: string;
|
|
5
5
|
adoptPath?: string;
|
|
6
|
-
|
|
6
|
+
app?: RenderedAppRules;
|
|
7
7
|
}): string;
|
|
8
8
|
//# sourceMappingURL=eslint-preset-emitter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eslint-preset-emitter.d.ts","sourceRoot":"","sources":["../../src/generator/eslint-preset-emitter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"eslint-preset-emitter.d.ts","sourceRoot":"","sources":["../../src/generator/eslint-preset-emitter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EACL,KAAK,mBAAmB,EAGzB,MAAM,4BAA4B,CAAC;AAEpC,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,SAAS,mBAAmB,EAAE,EACrC,MAAM,EAAE,SAAS,OAAO,EAAE,EAC1B,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,gBAAgB,CAAA;CAAO,GAC5E,MAAM,CAyBR"}
|
|
@@ -2,22 +2,22 @@ import { MAKE_RULE_FUNCTION, PLUGIN_CONFIGS, } from './eslint-plugin-emitter.js'
|
|
|
2
2
|
export function renderEslintPreset(specs, blocks, options = {}) {
|
|
3
3
|
const ignore = options.ignore ?? '**/.archprint/**';
|
|
4
4
|
const adoptPath = options.adoptPath ?? './.archprint/eslint.mjs';
|
|
5
|
-
const {
|
|
5
|
+
const { app } = options;
|
|
6
6
|
const header = `// archprint eslint rules (generated, self-contained). Regenerate with \`archprint generate\`; remove with \`archprint eject\`.
|
|
7
7
|
// Adopt it in one line: import archprint from '${adoptPath}'; export default [...archprint];
|
|
8
|
-
${
|
|
9
|
-
const rules =
|
|
8
|
+
${app ? `${app.imports}\n` : ''}`;
|
|
9
|
+
const rules = app
|
|
10
10
|
? `Object.fromEntries([
|
|
11
11
|
...SPECS.map((spec) => [spec.name, makeRule(spec)]),
|
|
12
|
-
...${
|
|
12
|
+
...${app.rules},
|
|
13
13
|
])`
|
|
14
14
|
: 'Object.fromEntries(SPECS.map((spec) => [spec.name, makeRule(spec)]))';
|
|
15
|
-
const configs =
|
|
15
|
+
const configs = app ? `[...${PLUGIN_CONFIGS}, ${app.config}]` : PLUGIN_CONFIGS;
|
|
16
16
|
return `${header}const SPECS = ${JSON.stringify(specs, null, 2)};
|
|
17
17
|
const BLOCKS = ${JSON.stringify(blocks, null, 2)};
|
|
18
18
|
|
|
19
19
|
${MAKE_RULE_FUNCTION}
|
|
20
|
-
${
|
|
20
|
+
${app ? `\n${app.source}\n` : ''}
|
|
21
21
|
const rules = ${rules};
|
|
22
22
|
const plugin = { rules };
|
|
23
23
|
const pluginConfigs = ${configs};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eslint-preset-emitter.js","sourceRoot":"","sources":["../../src/generator/eslint-preset-emitter.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,kBAAkB,EAClB,cAAc,GACf,MAAM,4BAA4B,CAAC;AAEpC,MAAM,UAAU,kBAAkB,CAChC,KAAqC,EACrC,MAA0B,EAC1B,
|
|
1
|
+
{"version":3,"file":"eslint-preset-emitter.js","sourceRoot":"","sources":["../../src/generator/eslint-preset-emitter.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,kBAAkB,EAClB,cAAc,GACf,MAAM,4BAA4B,CAAC;AAEpC,MAAM,UAAU,kBAAkB,CAChC,KAAqC,EACrC,MAA0B,EAC1B,UAA2E,EAAE;IAE7E,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,kBAAkB,CAAC;IACpD,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,yBAAyB,CAAC;IACjE,MAAM,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC;IACxB,MAAM,MAAM,GAAG;mDACkC,SAAS;EAC1D,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;IAChC,MAAM,KAAK,GAAG,GAAG;QACf,CAAC,CAAC;;OAEC,GAAG,CAAC,KAAK;GACb;QACC,CAAC,CAAC,sEAAsE,CAAC;IAC3E,MAAM,OAAO,GAAG,GAAG,CAAC,CAAC,CAAC,OAAO,cAAc,KAAK,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,cAAc,CAAC;IAC/E,OAAO,GAAG,MAAM,iBAAiB,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;iBAChD,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;;EAE9C,kBAAkB;EAClB,GAAG,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,EAAE;gBAChB,KAAK;;wBAEG,OAAO;;+BAEA,MAAM;CACpC,CAAC;AACF,CAAC"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { GenerationStatus } from '../detector/confidence-gate.js';
|
|
2
2
|
import type { FeatureSliceGroup } from '../detector/feature-slice-detector.js';
|
|
3
|
+
export declare const featureSliceRuleName: (container: string) => string;
|
|
3
4
|
export interface CrossSliceRule {
|
|
4
5
|
name: string;
|
|
5
6
|
comment: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"feature-slice-emitters.d.ts","sourceRoot":"","sources":["../../src/generator/feature-slice-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":"feature-slice-emitters.d.ts","sourceRoot":"","sources":["../../src/generator/feature-slice-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,MACpB,CAAC;AAKtC,MAAM,WAAW,cAAc;IAC7B,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,gBAAgB;IAC/B,SAAS,EAAE,cAAc,EAAE,CAAC;CAC7B;AAED,wBAAgB,+BAA+B,CAC7C,MAAM,EAAE,SAAS,iBAAiB,EAAE,EACpC,OAAO,GAAE,SAAS,gBAAgB,EAAa,GAC9C,gBAAgB,CAclB"}
|
|
@@ -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 featureSliceRuleName = (container) => `no-cross-slice-${slug(container)}`;
|
|
3
4
|
const confidencePct = (group) => `${(group.gate.conditions.confidence.value * 100).toFixed(0)}%`;
|
|
4
5
|
export function toDependencyCruiserFeatureSlice(groups, include = ['AUTO']) {
|
|
5
6
|
const forbidden = groups
|
|
@@ -7,7 +8,7 @@ export function toDependencyCruiserFeatureSlice(groups, include = ['AUTO']) {
|
|
|
7
8
|
.map((group) => {
|
|
8
9
|
const container = escapeRegExp(group.container);
|
|
9
10
|
return {
|
|
10
|
-
name:
|
|
11
|
+
name: featureSliceRuleName(group.container),
|
|
11
12
|
comment: `Archprint inferred slice isolation: the ${group.sliceCount} slices under "${group.container}" do not import each other (${group.sliceFileCount - group.crossImporterCount}/${group.sliceFileCount} slice files conform); cross-slice imports are forbidden (confidence ${confidencePct(group)}).`,
|
|
12
13
|
severity: 'error',
|
|
13
14
|
from: { path: `^${container}/([^/]+)/` },
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"feature-slice-emitters.js","sourceRoot":"","sources":["../../src/generator/feature-slice-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":"feature-slice-emitters.js","sourceRoot":"","sources":["../../src/generator/feature-slice-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,kBAAkB,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;AAEtC,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,2CAA2C,KAAK,CAAC,UAAU,kBAAkB,KAAK,CAAC,SAAS,+BAA+B,KAAK,CAAC,cAAc,GAAG,KAAK,CAAC,kBAAkB,IAAI,KAAK,CAAC,cAAc,wEAAwE,aAAa,CAAC,KAAK,CAAC,IAAI;YAC3S,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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"layer-emitters.d.ts","sourceRoot":"","sources":["../../src/generator/layer-emitters.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAKnE,eAAO,MAAM,aAAa,GAAI,cAAc;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,KAAG,MACpD,CAAC;
|
|
1
|
+
{"version":3,"file":"layer-emitters.d.ts","sourceRoot":"","sources":["../../src/generator/layer-emitters.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAKnE,eAAO,MAAM,aAAa,GAAI,cAAc;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,KAAG,MACpD,CAAC;AAaxB,MAAM,WAAW,qBAAqB;IACpC,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,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;KAAE,CAAC;IACpD,EAAE,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;CACrD;AAED,MAAM,WAAW,uBAAuB;IACtC,SAAS,EAAE,qBAAqB,EAAE,CAAC;CACpC;AAED,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,SAAS,aAAa,EAAE,EACpC,OAAO,GAAE,SAAS,gBAAgB,EAAa,EAC/C,OAAO,SAAM,EACb,UAAU,GAAE,CAAC,MAAM,EAAE,MAAM,KAAK,SAAS,MAAM,EAAa,GAC3D,uBAAuB,CAkBzB;AAED,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE;QAAE,qBAAqB,EAAE,uBAAuB,EAAE,CAAA;KAAE,CAAC;IAC/D,KAAK,EAAE;QACL,0BAA0B,EAAE,CAAC,OAAO,EAAE;YAAE,OAAO,EAAE,OAAO,CAAC;YAAC,KAAK,EAAE,oBAAoB,EAAE,CAAA;SAAE,CAAC,CAAC;KAC5F,CAAC;CACH;AAED,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,SAAS,aAAa,EAAE,EACpC,OAAO,GAAE,SAAS,gBAAgB,EAAa,GAC9C,sBAAsB,CA6BxB"}
|
|
@@ -1,11 +1,7 @@
|
|
|
1
|
-
import { exemptDepcruiseFrom, TEST_ROLE_REGEX } from './depcruise-exempt.js';
|
|
1
|
+
import { appPathPrefix, exemptDepcruiseFrom, TEST_ROLE_REGEX } from './depcruise-exempt.js';
|
|
2
2
|
const escapeRegExp = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
3
3
|
export const layerRuleName = ({ from, to }) => `no-${from}-to-${to}`;
|
|
4
|
-
const
|
|
5
|
-
const normalized = appPath.replace(/\\/g, '/').replace(/\/+$/, '');
|
|
6
|
-
return normalized === '' || normalized === '.' ? '' : `${escapeRegExp(normalized)}/`;
|
|
7
|
-
};
|
|
8
|
-
const layerPath = (dirs, appPath) => `^${appPrefix(appPath)}(?:${dirs.map(escapeRegExp).join('|')})/`;
|
|
4
|
+
const layerPath = (dirs, appPath) => `^${appPathPrefix(appPath)}(?:${dirs.map(escapeRegExp).join('|')})/`;
|
|
9
5
|
const confidencePct = (boundary) => `${(boundary.gate.conditions.confidence.value * 100).toFixed(0)}%`;
|
|
10
6
|
const selected = (boundaries, include) => boundaries.filter((boundary) => include.includes(boundary.gate.status));
|
|
11
7
|
export function toDependencyCruiser(boundaries, include = ['AUTO'], appPath = '.', allowedFor = () => []) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"layer-emitters.js","sourceRoot":"","sources":["../../src/generator/layer-emitters.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"layer-emitters.js","sourceRoot":"","sources":["../../src/generator/layer-emitters.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAE5F,MAAM,YAAY,GAAG,CAAC,KAAa,EAAU,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;AAE7F,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,EAAE,IAAI,EAAE,EAAE,EAAgC,EAAU,EAAE,CAClF,MAAM,IAAI,OAAO,EAAE,EAAE,CAAC;AAExB,MAAM,SAAS,GAAG,CAAC,IAAuB,EAAE,OAAe,EAAU,EAAE,CACrE,IAAI,aAAa,CAAC,OAAO,CAAC,MAAM,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;AAEvE,MAAM,aAAa,GAAG,CAAC,QAAuB,EAAU,EAAE,CACxD,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,KAAK,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;AAErE,MAAM,QAAQ,GAAG,CACf,UAAoC,EACpC,OAAoC,EACnB,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;AAc9F,MAAM,UAAU,mBAAmB,CACjC,UAAoC,EACpC,UAAuC,CAAC,MAAM,CAAC,EAC/C,OAAO,GAAG,GAAG,EACb,aAAoD,GAAG,EAAE,CAAC,EAAE;IAE5D,MAAM,SAAS,GAAG,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QACjE,IAAI,EAAE,aAAa,CAAC,QAAQ,CAAC;QAC7B,OAAO,EAAE,qCAAqC,QAAQ,CAAC,EAAE,uBAAuB,QAAQ,CAAC,IAAI,YAAY,QAAQ,CAAC,WAAW,kDAAkD,aAAa,CAAC,QAAQ,CAAC,IAAI;QAC1M,QAAQ,EAAE,OAAgB;QAC1B,IAAI,EAAE;YACJ,IAAI,EAAE,SAAS,CAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;YAC3C,OAAO,EAAE,mBAAmB,CAAC,eAAe,EAAE;gBAC5C,GAAG,QAAQ,CAAC,UAAU;gBACtB,GAAG,UAAU,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;aACjE,CAAC;SACH;QACD,EAAE,EAAE;YACF,IAAI,EAAE,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;YACzC,kBAAkB,EAAE,CAAC,WAAW,CAAC;SAClC;KACF,CAAC,CAAC,CAAC;IACJ,OAAO,EAAE,SAAS,EAAE,CAAC;AACvB,CAAC;AAoBD,MAAM,UAAU,kBAAkB,CAChC,UAAoC,EACpC,UAAuC,CAAC,MAAM,CAAC;IAE/C,MAAM,MAAM,GAAG,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IAC7C,MAAM,MAAM,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC/F,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC;IAErF,MAAM,cAAc,GAAG,IAAI,GAAG,EAAuB,CAAC;IACtD,KAAK,MAAM,QAAQ,IAAI,MAAM,EAAE,CAAC;QAC9B,IAAI,OAAO,GAAG,cAAc,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAChD,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC1B,OAAO,GAAG,IAAI,GAAG,EAAE,CAAC;YACpB,cAAc,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC7C,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IAC3B,CAAC;IACD,MAAM,KAAK,GAAG,CAAC,GAAG,cAAc,CAAC,OAAO,EAAE,CAAC;SACxC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;SACtC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,EAAE;QACvB,MAAM,QAAQ,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;QACrC,OAAO;YACL,IAAI,EAAE,CAAC,IAAI,CAAC;YACZ,QAAQ;YACR,OAAO,EAAE,QAAQ,IAAI,4BAA4B,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,8DAA8D;SACnI,CAAC;IACJ,CAAC,CAAC,CAAC;IAEL,OAAO;QACL,QAAQ,EAAE,EAAE,qBAAqB,EAAE,QAAQ,EAAE;QAC7C,KAAK,EAAE,EAAE,0BAA0B,EAAE,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE;KAC9E,CAAC;AACJ,CAAC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { PhantomDependencyAnalysis } from '../detector/phantom-dependency-detector.js';
|
|
2
|
+
export declare const PHANTOM_DEPENDENCY_RULE = "no-phantom-dependencies";
|
|
2
3
|
export interface PhantomDependencyRule {
|
|
3
4
|
name: string;
|
|
4
5
|
comment: string;
|
|
@@ -13,5 +14,5 @@ export interface PhantomDependencyRule {
|
|
|
13
14
|
export interface PhantomDependencyConfig {
|
|
14
15
|
forbidden: PhantomDependencyRule[];
|
|
15
16
|
}
|
|
16
|
-
export declare function toDependencyCruiserPhantomDependencies(analysis: PhantomDependencyAnalysis): PhantomDependencyConfig;
|
|
17
|
+
export declare function toDependencyCruiserPhantomDependencies(analysis: PhantomDependencyAnalysis, allowedFor?: (ruleId: string) => readonly string[]): PhantomDependencyConfig;
|
|
17
18
|
//# sourceMappingURL=phantom-dependency-emitters.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"phantom-dependency-emitters.d.ts","sourceRoot":"","sources":["../../src/generator/phantom-dependency-emitters.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,4CAA4C,CAAC;AAG5F,MAAM,WAAW,qBAAqB;IACpC,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,eAAe,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;CACnC;AAED,MAAM,WAAW,uBAAuB;IACtC,SAAS,EAAE,qBAAqB,EAAE,CAAC;CACpC;AAED,wBAAgB,sCAAsC,CACpD,QAAQ,EAAE,yBAAyB,
|
|
1
|
+
{"version":3,"file":"phantom-dependency-emitters.d.ts","sourceRoot":"","sources":["../../src/generator/phantom-dependency-emitters.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,4CAA4C,CAAC;AAG5F,eAAO,MAAM,uBAAuB,4BAA4B,CAAC;AAEjE,MAAM,WAAW,qBAAqB;IACpC,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,eAAe,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;CACnC;AAED,MAAM,WAAW,uBAAuB;IACtC,SAAS,EAAE,qBAAqB,EAAE,CAAC;CACpC;AAED,wBAAgB,sCAAsC,CACpD,QAAQ,EAAE,yBAAyB,EACnC,UAAU,GAAE,CAAC,MAAM,EAAE,MAAM,KAAK,SAAS,MAAM,EAAa,GAC3D,uBAAuB,CAyBzB"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { exemptDepcruiseFrom, TEST_ROLE_REGEX } from './depcruise-exempt.js';
|
|
2
|
-
export
|
|
2
|
+
export const PHANTOM_DEPENDENCY_RULE = 'no-phantom-dependencies';
|
|
3
|
+
export function toDependencyCruiserPhantomDependencies(analysis, allowedFor = () => []) {
|
|
3
4
|
if (analysis.externalImporterCount === 0 || analysis.gate.status !== 'AUTO') {
|
|
4
5
|
return { forbidden: [] };
|
|
5
6
|
}
|
|
@@ -8,11 +9,14 @@ export function toDependencyCruiserPhantomDependencies(analysis) {
|
|
|
8
9
|
return {
|
|
9
10
|
forbidden: [
|
|
10
11
|
{
|
|
11
|
-
name:
|
|
12
|
+
name: PHANTOM_DEPENDENCY_RULE,
|
|
12
13
|
comment: `Archprint inferred dependency declaration: ${conform}/${analysis.externalImporterCount} files import only packages declared in package.json; importing an undeclared (phantom/transitive) dependency is forbidden (confidence ${floor}).`,
|
|
13
14
|
severity: 'error',
|
|
14
15
|
from: {
|
|
15
|
-
pathNot: exemptDepcruiseFrom([TEST_ROLE_REGEX, 'node_modules'],
|
|
16
|
+
pathNot: exemptDepcruiseFrom([TEST_ROLE_REGEX, 'node_modules'], [
|
|
17
|
+
...analysis.violations,
|
|
18
|
+
...allowedFor(PHANTOM_DEPENDENCY_RULE).map((file) => ({ file })),
|
|
19
|
+
]),
|
|
16
20
|
},
|
|
17
21
|
to: { dependencyTypes: ['npm-no-pkg', 'npm-unknown'] },
|
|
18
22
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"phantom-dependency-emitters.js","sourceRoot":"","sources":["../../src/generator/phantom-dependency-emitters.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"phantom-dependency-emitters.js","sourceRoot":"","sources":["../../src/generator/phantom-dependency-emitters.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAE7E,MAAM,CAAC,MAAM,uBAAuB,GAAG,yBAAyB,CAAC;AAcjE,MAAM,UAAU,sCAAsC,CACpD,QAAmC,EACnC,aAAoD,GAAG,EAAE,CAAC,EAAE;IAE5D,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,uBAAuB;gBAC7B,OAAO,EAAE,8CAA8C,OAAO,IAAI,QAAQ,CAAC,qBAAqB,0IAA0I,KAAK,IAAI;gBACnP,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,uBAAuB,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;qBACjE,CACF;iBACF;gBACD,EAAE,EAAE,EAAE,eAAe,EAAE,CAAC,YAAY,EAAE,aAAa,CAAC,EAAE;aACvD;SACF;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { GenerationStatus } from '../detector/confidence-gate.js';
|
|
2
2
|
import type { RoleBoundary } from '../detector/role-layering-detector.js';
|
|
3
|
+
import type { Role } from '../scanner/role-classifier.js';
|
|
4
|
+
export declare const roleLayeringRuleName: (from: Role, to: Role) => string;
|
|
3
5
|
export interface RoleLayeringRule {
|
|
4
6
|
name: string;
|
|
5
7
|
comment: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"role-layering-emitters.d.ts","sourceRoot":"","sources":["../../src/generator/role-layering-emitters.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uCAAuC,CAAC;
|
|
1
|
+
{"version":3,"file":"role-layering-emitters.d.ts","sourceRoot":"","sources":["../../src/generator/role-layering-emitters.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uCAAuC,CAAC;AAE1E,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,+BAA+B,CAAC;AAO1D,eAAO,MAAM,oBAAoB,GAAI,MAAM,IAAI,EAAE,IAAI,IAAI,KAAG,MACT,CAAC;AAKpD,MAAM,WAAW,gBAAgB;IAC/B,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,CAAA;KAAE,CAAC;CACtB;AAED,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,gBAAgB,EAAE,CAAC;CAC/B;AAED,wBAAgB,+BAA+B,CAC7C,UAAU,EAAE,SAAS,YAAY,EAAE,EACnC,OAAO,GAAE,SAAS,gBAAgB,EAAa,GAC9C,kBAAkB,CAWpB"}
|
|
@@ -3,12 +3,13 @@ const rolePath = (role) => {
|
|
|
3
3
|
const sources = (ROLE_PATTERNS.get(role) ?? []).map((pattern) => pattern.source);
|
|
4
4
|
return sources.length === 1 ? sources[0] : `(${sources.join('|')})`;
|
|
5
5
|
};
|
|
6
|
+
export const roleLayeringRuleName = (from, to) => `no-${from.toLowerCase()}-to-${to.toLowerCase()}`;
|
|
6
7
|
const confidencePct = (boundary) => `${(boundary.gate.conditions.confidence.value * 100).toFixed(0)}%`;
|
|
7
8
|
export function toDependencyCruiserRoleLayering(boundaries, include = ['AUTO']) {
|
|
8
9
|
const forbidden = boundaries
|
|
9
10
|
.filter((boundary) => include.includes(boundary.gate.status))
|
|
10
11
|
.map((boundary) => ({
|
|
11
|
-
name:
|
|
12
|
+
name: roleLayeringRuleName(boundary.from, boundary.to),
|
|
12
13
|
comment: `Archprint inferred role layering: ${boundary.reverseFlow} ${boundary.to} file(s) depend on ${boundary.from}, not the reverse; a ${boundary.from} must not import a ${boundary.to} (confidence ${confidencePct(boundary)}).`,
|
|
13
14
|
severity: 'error',
|
|
14
15
|
from: { path: rolePath(boundary.from) },
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"role-layering-emitters.js","sourceRoot":"","sources":["../../src/generator/role-layering-emitters.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAG9D,MAAM,QAAQ,GAAG,CAAC,IAAU,EAAU,EAAE;IACtC,MAAM,OAAO,GAAG,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACjF,OAAO,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;AACvE,CAAC,CAAC;AAEF,MAAM,aAAa,GAAG,CAAC,QAAsB,EAAU,EAAE,CACvD,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,KAAK,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;AAcrE,MAAM,UAAU,+BAA+B,CAC7C,UAAmC,EACnC,UAAuC,CAAC,MAAM,CAAC;IAE/C,MAAM,SAAS,GAAG,UAAU;SACzB,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;SAC5D,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QAClB,IAAI,EAAE,
|
|
1
|
+
{"version":3,"file":"role-layering-emitters.js","sourceRoot":"","sources":["../../src/generator/role-layering-emitters.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAG9D,MAAM,QAAQ,GAAG,CAAC,IAAU,EAAU,EAAE;IACtC,MAAM,OAAO,GAAG,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACjF,OAAO,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;AACvE,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,IAAU,EAAE,EAAQ,EAAU,EAAE,CACnE,MAAM,IAAI,CAAC,WAAW,EAAE,OAAO,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC;AAEpD,MAAM,aAAa,GAAG,CAAC,QAAsB,EAAU,EAAE,CACvD,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,KAAK,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;AAcrE,MAAM,UAAU,+BAA+B,CAC7C,UAAmC,EACnC,UAAuC,CAAC,MAAM,CAAC;IAE/C,MAAM,SAAS,GAAG,UAAU;SACzB,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;SAC5D,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QAClB,IAAI,EAAE,oBAAoB,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,EAAE,CAAC;QACtD,OAAO,EAAE,qCAAqC,QAAQ,CAAC,WAAW,IAAI,QAAQ,CAAC,EAAE,sBAAsB,QAAQ,CAAC,IAAI,wBAAwB,QAAQ,CAAC,IAAI,sBAAsB,QAAQ,CAAC,EAAE,gBAAgB,aAAa,CAAC,QAAQ,CAAC,IAAI;QACrO,QAAQ,EAAE,OAAgB;QAC1B,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE;QACvC,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE;KACpC,CAAC,CAAC,CAAC;IACN,OAAO,EAAE,SAAS,EAAE,CAAC;AACvB,CAAC"}
|
|
@@ -1,17 +1,24 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type ServerClientAnalysis } from '../detector/server-client-detector.js';
|
|
2
|
+
export declare const SERVER_CLIENT_RULE = "no-server-only-in-client";
|
|
2
3
|
export interface ServerClientRule {
|
|
3
4
|
name: string;
|
|
4
5
|
comment: string;
|
|
5
6
|
severity: 'error' | 'warn' | 'info';
|
|
6
7
|
from: {
|
|
7
8
|
path: string;
|
|
9
|
+
pathNot: string | string[];
|
|
8
10
|
};
|
|
9
11
|
to: {
|
|
10
|
-
path: string;
|
|
12
|
+
path: string | string[];
|
|
13
|
+
dependencyTypesNot: string[];
|
|
11
14
|
};
|
|
12
15
|
}
|
|
13
16
|
export interface ServerClientConfig {
|
|
14
17
|
forbidden: ServerClientRule[];
|
|
15
18
|
}
|
|
16
|
-
|
|
19
|
+
/**
|
|
20
|
+
* The "use client" files the scan found must not import a server-only module or the server-only package. Files
|
|
21
|
+
* that become client components after generation are not covered until the next generate.
|
|
22
|
+
*/
|
|
23
|
+
export declare function toDependencyCruiserServerClient(analysis: ServerClientAnalysis, appPath: string, allowedFor: (ruleId: string) => readonly string[]): ServerClientConfig;
|
|
17
24
|
//# sourceMappingURL=server-client-emitters.d.ts.map
|