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.
Files changed (93) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +17 -8
  3. package/dist/cli/adopted-rules.d.ts +10 -1
  4. package/dist/cli/adopted-rules.d.ts.map +1 -1
  5. package/dist/cli/adopted-rules.js +63 -0
  6. package/dist/cli/adopted-rules.js.map +1 -1
  7. package/dist/cli/allow.d.ts.map +1 -1
  8. package/dist/cli/allow.js +11 -3
  9. package/dist/cli/allow.js.map +1 -1
  10. package/dist/cli/allowed-evidence.d.ts.map +1 -1
  11. package/dist/cli/allowed-evidence.js +78 -1
  12. package/dist/cli/allowed-evidence.js.map +1 -1
  13. package/dist/cli/check-evaluate.d.ts.map +1 -1
  14. package/dist/cli/check-evaluate.js +46 -0
  15. package/dist/cli/check-evaluate.js.map +1 -1
  16. package/dist/cli/generate.d.ts +4 -4
  17. package/dist/cli/generate.d.ts.map +1 -1
  18. package/dist/cli/generate.js +70 -23
  19. package/dist/cli/generate.js.map +1 -1
  20. package/dist/cli/recommend.d.ts.map +1 -1
  21. package/dist/cli/recommend.js +12 -7
  22. package/dist/cli/recommend.js.map +1 -1
  23. package/dist/detector/cycle-detector.d.ts +5 -0
  24. package/dist/detector/cycle-detector.d.ts.map +1 -1
  25. package/dist/detector/cycle-detector.js +20 -0
  26. package/dist/detector/cycle-detector.js.map +1 -1
  27. package/dist/detector/dependency-internals-detector.d.ts.map +1 -1
  28. package/dist/detector/dependency-internals-detector.js +6 -20
  29. package/dist/detector/dependency-internals-detector.js.map +1 -1
  30. package/dist/detector/entry-purity-detector.d.ts +7 -0
  31. package/dist/detector/entry-purity-detector.d.ts.map +1 -1
  32. package/dist/detector/entry-purity-detector.js +21 -10
  33. package/dist/detector/entry-purity-detector.js.map +1 -1
  34. package/dist/detector/phantom-dependency-detector.d.ts +7 -0
  35. package/dist/detector/phantom-dependency-detector.d.ts.map +1 -1
  36. package/dist/detector/phantom-dependency-detector.js +18 -39
  37. package/dist/detector/phantom-dependency-detector.js.map +1 -1
  38. package/dist/detector/server-client-detector.d.ts +5 -0
  39. package/dist/detector/server-client-detector.d.ts.map +1 -1
  40. package/dist/detector/server-client-detector.js +8 -3
  41. package/dist/detector/server-client-detector.js.map +1 -1
  42. package/dist/generator/depcruise-exempt.d.ts +4 -0
  43. package/dist/generator/depcruise-exempt.d.ts.map +1 -1
  44. package/dist/generator/depcruise-exempt.js +7 -0
  45. package/dist/generator/depcruise-exempt.js.map +1 -1
  46. package/dist/generator/dependency-internals-emitters.d.ts +2 -1
  47. package/dist/generator/dependency-internals-emitters.d.ts.map +1 -1
  48. package/dist/generator/dependency-internals-emitters.js +7 -3
  49. package/dist/generator/dependency-internals-emitters.js.map +1 -1
  50. package/dist/generator/entry-purity-emitters.d.ts +7 -3
  51. package/dist/generator/entry-purity-emitters.d.ts.map +1 -1
  52. package/dist/generator/entry-purity-emitters.js +19 -5
  53. package/dist/generator/entry-purity-emitters.js.map +1 -1
  54. package/dist/generator/eslint-app-emitter.d.ts +59 -0
  55. package/dist/generator/eslint-app-emitter.d.ts.map +1 -0
  56. package/dist/generator/eslint-app-emitter.js +275 -0
  57. package/dist/generator/eslint-app-emitter.js.map +1 -0
  58. package/dist/generator/eslint-preset-emitter.d.ts +2 -2
  59. package/dist/generator/eslint-preset-emitter.d.ts.map +1 -1
  60. package/dist/generator/eslint-preset-emitter.js +6 -6
  61. package/dist/generator/eslint-preset-emitter.js.map +1 -1
  62. package/dist/generator/layer-emitters.d.ts.map +1 -1
  63. package/dist/generator/layer-emitters.js +2 -6
  64. package/dist/generator/layer-emitters.js.map +1 -1
  65. package/dist/generator/phantom-dependency-emitters.d.ts +2 -1
  66. package/dist/generator/phantom-dependency-emitters.d.ts.map +1 -1
  67. package/dist/generator/phantom-dependency-emitters.js +7 -3
  68. package/dist/generator/phantom-dependency-emitters.js.map +1 -1
  69. package/dist/generator/server-client-emitters.d.ts +10 -3
  70. package/dist/generator/server-client-emitters.d.ts.map +1 -1
  71. package/dist/generator/server-client-emitters.js +23 -4
  72. package/dist/generator/server-client-emitters.js.map +1 -1
  73. package/dist/scanner/directives.d.ts +6 -0
  74. package/dist/scanner/directives.d.ts.map +1 -0
  75. package/dist/scanner/directives.js +35 -0
  76. package/dist/scanner/directives.js.map +1 -0
  77. package/dist/scanner/package-name.d.ts +10 -0
  78. package/dist/scanner/package-name.d.ts.map +1 -0
  79. package/dist/scanner/package-name.js +37 -0
  80. package/dist/scanner/package-name.js.map +1 -0
  81. package/dist/scanner/resolve-import.d.ts +5 -0
  82. package/dist/scanner/resolve-import.d.ts.map +1 -1
  83. package/dist/scanner/resolve-import.js +22 -19
  84. package/dist/scanner/resolve-import.js.map +1 -1
  85. package/dist/scanner/role-classifier.d.ts +11 -2
  86. package/dist/scanner/role-classifier.d.ts.map +1 -1
  87. package/dist/scanner/role-classifier.js +13 -39
  88. package/dist/scanner/role-classifier.js.map +1 -1
  89. package/package.json +1 -1
  90. package/dist/generator/eslint-layer-emitter.d.ts +0 -29
  91. package/dist/generator/eslint-layer-emitter.d.ts.map +0 -1
  92. package/dist/generator/eslint-layer-emitter.js +0 -121
  93. package/dist/generator/eslint-layer-emitter.js.map +0 -1
@@ -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 { RenderedEslintLayers } from './eslint-layer-emitter.js';
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
- layers?: RenderedEslintLayers;
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,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACtE,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,MAAM,CAAC,EAAE,oBAAoB,CAAA;CAAO,GACnF,MAAM,CAyBR"}
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 { layers } = options;
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
- ${layers ? `${layers.imports}\n` : ''}`;
9
- const rules = layers
8
+ ${app ? `${app.imports}\n` : ''}`;
9
+ const rules = app
10
10
  ? `Object.fromEntries([
11
11
  ...SPECS.map((spec) => [spec.name, makeRule(spec)]),
12
- ...${layers.rules},
12
+ ...${app.rules},
13
13
  ])`
14
14
  : 'Object.fromEntries(SPECS.map((spec) => [spec.name, makeRule(spec)]))';
15
- const configs = layers ? `[...${PLUGIN_CONFIGS}, ${layers.config}]` : PLUGIN_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
- ${layers ? `\n${layers.source}\n` : ''}
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,UAAkF,EAAE;IAEpF,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,kBAAkB,CAAC;IACpD,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,yBAAyB,CAAC;IACjE,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IAC3B,MAAM,MAAM,GAAG;mDACkC,SAAS;EAC1D,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;IACtC,MAAM,KAAK,GAAG,MAAM;QAClB,CAAC,CAAC;;OAEC,MAAM,CAAC,KAAK;GAChB;QACC,CAAC,CAAC,sEAAsE,CAAC;IAC3E,MAAM,OAAO,GAAG,MAAM,CAAC,CAAC,CAAC,OAAO,cAAc,KAAK,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,cAAc,CAAC;IACrF,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,MAAM,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,EAAE;gBACtB,KAAK;;wBAEG,OAAO;;+BAEA,MAAM;CACpC,CAAC;AACF,CAAC"}
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 +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;AAkBxB,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
+ {"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 appPrefix = (appPath) => {
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":"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"}
1
+ {"version":3,"file":"layer-emitters.js","sourceRoot":"","sources":["../../src/generator/layer-emitters.ts"],"names":[],"mappings":"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"}
@@ -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,GAClC,uBAAuB,CAmBzB"}
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 function toDependencyCruiserPhantomDependencies(analysis) {
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: 'no-phantom-dependencies',
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'], analysis.violations),
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;AAc7E,MAAM,UAAU,sCAAsC,CACpD,QAAmC;IAEnC,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,8CAA8C,OAAO,IAAI,QAAQ,CAAC,qBAAqB,0IAA0I,KAAK,IAAI;gBACnP,QAAQ,EAAE,OAAO;gBACjB,IAAI,EAAE;oBACJ,OAAO,EAAE,mBAAmB,CAAC,CAAC,eAAe,EAAE,cAAc,CAAC,EAAE,QAAQ,CAAC,UAAU,CAAC;iBACrF;gBACD,EAAE,EAAE,EAAE,eAAe,EAAE,CAAC,YAAY,EAAE,aAAa,CAAC,EAAE;aACvD;SACF;KACF,CAAC;AACJ,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,17 +1,24 @@
1
- import type { ServerClientAnalysis } from '../detector/server-client-detector.js';
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
- export declare function toDependencyCruiserServerClient(analysis: ServerClientAnalysis): ServerClientConfig;
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
@@ -1 +1 @@
1
- {"version":3,"file":"server-client-emitters.d.ts","sourceRoot":"","sources":["../../src/generator/server-client-emitters.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,uCAAuC,CAAC;AAElF,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,QAAQ,EAAE,oBAAoB,GAC7B,kBAAkB,CAepB"}
1
+ {"version":3,"file":"server-client-emitters.d.ts","sourceRoot":"","sources":["../../src/generator/server-client-emitters.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,oBAAoB,EAC1B,MAAM,uCAAuC,CAAC;AAG/C,eAAO,MAAM,kBAAkB,6BAA6B,CAAC;AAE7D,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,CAAC;QAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;KAAE,CAAC;IACnD,EAAE,EAAE;QAAE,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;QAAC,kBAAkB,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;CAC/D;AAED,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,gBAAgB,EAAE,CAAC;CAC/B;AAED;;;GAGG;AACH,wBAAgB,+BAA+B,CAC7C,QAAQ,EAAE,oBAAoB,EAC9B,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,SAAS,MAAM,EAAE,GAChD,kBAAkB,CA4BpB"}
@@ -1,16 +1,35 @@
1
- export function toDependencyCruiserServerClient(analysis) {
1
+ import { SERVER_ONLY_PACKAGE, } from '../detector/server-client-detector.js';
2
+ import { exactAppFiles, exemptDepcruiseFrom, TEST_ROLE_REGEX } from './depcruise-exempt.js';
3
+ export const SERVER_CLIENT_RULE = 'no-server-only-in-client';
4
+ /**
5
+ * The "use client" files the scan found must not import a server-only module or the server-only package. Files
6
+ * that become client components after generation are not covered until the next generate.
7
+ */
8
+ export function toDependencyCruiserServerClient(analysis, appPath, allowedFor) {
2
9
  if (analysis.clientCount === 0 || analysis.gate.status !== 'AUTO')
3
10
  return { forbidden: [] };
4
11
  const conform = analysis.clientCount - analysis.offenderCount;
5
12
  const floor = `${(analysis.gate.conditions.confidence.value * 100).toFixed(0)}%`;
13
+ const serverOnlyPackage = `(^|/)node_modules/${SERVER_ONLY_PACKAGE}/`;
6
14
  return {
7
15
  forbidden: [
8
16
  {
9
- name: 'no-server-only-in-client',
17
+ name: SERVER_CLIENT_RULE,
10
18
  comment: `Archprint inferred server/client boundary: ${conform}/${analysis.clientCount} "use client" modules import no server-only code; a client component importing a server-only module is forbidden (confidence ${floor}).`,
11
19
  severity: 'error',
12
- from: { path: '\\.(ts|tsx)$' },
13
- to: { path: 'node_modules/server-only' },
20
+ from: {
21
+ path: exactAppFiles(analysis.clients, appPath),
22
+ pathNot: exemptDepcruiseFrom(TEST_ROLE_REGEX, [
23
+ ...analysis.violations,
24
+ ...allowedFor(SERVER_CLIENT_RULE).map((file) => ({ file })),
25
+ ]),
26
+ },
27
+ to: {
28
+ path: analysis.serverModules.length === 0
29
+ ? serverOnlyPackage
30
+ : [exactAppFiles(analysis.serverModules, appPath), serverOnlyPackage],
31
+ dependencyTypesNot: ['type-only'],
32
+ },
14
33
  },
15
34
  ],
16
35
  };
@@ -1 +1 @@
1
- {"version":3,"file":"server-client-emitters.js","sourceRoot":"","sources":["../../src/generator/server-client-emitters.ts"],"names":[],"mappings":"AAcA,MAAM,UAAU,+BAA+B,CAC7C,QAA8B;IAE9B,IAAI,QAAQ,CAAC,WAAW,KAAK,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,MAAM,KAAK,MAAM;QAAE,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;IAC5F,MAAM,OAAO,GAAG,QAAQ,CAAC,WAAW,GAAG,QAAQ,CAAC,aAAa,CAAC;IAC9D,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,0BAA0B;gBAChC,OAAO,EAAE,8CAA8C,OAAO,IAAI,QAAQ,CAAC,WAAW,gIAAgI,KAAK,IAAI;gBAC/N,QAAQ,EAAE,OAAO;gBACjB,IAAI,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE;gBAC9B,EAAE,EAAE,EAAE,IAAI,EAAE,0BAA0B,EAAE;aACzC;SACF;KACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"server-client-emitters.js","sourceRoot":"","sources":["../../src/generator/server-client-emitters.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,GAEpB,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAE5F,MAAM,CAAC,MAAM,kBAAkB,GAAG,0BAA0B,CAAC;AAc7D;;;GAGG;AACH,MAAM,UAAU,+BAA+B,CAC7C,QAA8B,EAC9B,OAAe,EACf,UAAiD;IAEjD,IAAI,QAAQ,CAAC,WAAW,KAAK,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,MAAM,KAAK,MAAM;QAAE,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;IAC5F,MAAM,OAAO,GAAG,QAAQ,CAAC,WAAW,GAAG,QAAQ,CAAC,aAAa,CAAC;IAC9D,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,iBAAiB,GAAG,qBAAqB,mBAAmB,GAAG,CAAC;IACtE,OAAO;QACL,SAAS,EAAE;YACT;gBACE,IAAI,EAAE,kBAAkB;gBACxB,OAAO,EAAE,8CAA8C,OAAO,IAAI,QAAQ,CAAC,WAAW,gIAAgI,KAAK,IAAI;gBAC/N,QAAQ,EAAE,OAAO;gBACjB,IAAI,EAAE;oBACJ,IAAI,EAAE,aAAa,CAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;oBAC9C,OAAO,EAAE,mBAAmB,CAAC,eAAe,EAAE;wBAC5C,GAAG,QAAQ,CAAC,UAAU;wBACtB,GAAG,UAAU,CAAC,kBAAkB,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;qBAC5D,CAAC;iBACH;gBACD,EAAE,EAAE;oBACF,IAAI,EACF,QAAQ,CAAC,aAAa,CAAC,MAAM,KAAK,CAAC;wBACjC,CAAC,CAAC,iBAAiB;wBACnB,CAAC,CAAC,CAAC,aAAa,CAAC,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC,EAAE,iBAAiB,CAAC;oBACzE,kBAAkB,EAAE,CAAC,WAAW,CAAC;iBAClC;aACF;SACF;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Whether source text starts with a directive such as "use client", after a BOM, a shebang line, whitespace and
3
+ * comments. Self-contained: the generated ESLint rules embed it.
4
+ */
5
+ export declare function hasLeadingDirective(source: string, directive: string): boolean;
6
+ //# sourceMappingURL=directives.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"directives.d.ts","sourceRoot":"","sources":["../../src/scanner/directives.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAwB9E"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Whether source text starts with a directive such as "use client", after a BOM, a shebang line, whitespace and
3
+ * comments. Self-contained: the generated ESLint rules embed it.
4
+ */
5
+ export function hasLeadingDirective(source, directive) {
6
+ const isWhitespace = (c) => c === ' ' || c === '\t' || c === '\n' || c === '\r' || c === '\f' || c === '\v';
7
+ let i = source.charCodeAt(0) === 0xfeff ? 1 : 0;
8
+ if (source.startsWith('#!', i)) {
9
+ const newline = source.indexOf('\n', i);
10
+ if (newline === -1)
11
+ return false;
12
+ i = newline + 1;
13
+ }
14
+ for (;;) {
15
+ while (i < source.length && isWhitespace(source[i]))
16
+ i++;
17
+ if (source.startsWith('//', i)) {
18
+ const newline = source.indexOf('\n', i);
19
+ if (newline === -1)
20
+ return false;
21
+ i = newline + 1;
22
+ }
23
+ else if (source.startsWith('/*', i)) {
24
+ const end = source.indexOf('*/', i + 2);
25
+ if (end === -1)
26
+ return false;
27
+ i = end + 2;
28
+ }
29
+ else {
30
+ break;
31
+ }
32
+ }
33
+ return new RegExp(`^["']${directive}["']`).test(source.slice(i));
34
+ }
35
+ //# sourceMappingURL=directives.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"directives.js","sourceRoot":"","sources":["../../src/scanner/directives.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAAc,EAAE,SAAiB;IACnE,MAAM,YAAY,GAAG,CAAC,CAAS,EAAW,EAAE,CAC1C,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,IAAI,CAAC;IAClF,IAAI,CAAC,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAChD,IAAI,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;QAC/B,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QACxC,IAAI,OAAO,KAAK,CAAC,CAAC;YAAE,OAAO,KAAK,CAAC;QACjC,CAAC,GAAG,OAAO,GAAG,CAAC,CAAC;IAClB,CAAC;IACD,SAAS,CAAC;QACR,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,IAAI,YAAY,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC;YAAE,CAAC,EAAE,CAAC;QAC1D,IAAI,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;YAC/B,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;YACxC,IAAI,OAAO,KAAK,CAAC,CAAC;gBAAE,OAAO,KAAK,CAAC;YACjC,CAAC,GAAG,OAAO,GAAG,CAAC,CAAC;QAClB,CAAC;aAAM,IAAI,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;YACtC,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;YACxC,IAAI,GAAG,KAAK,CAAC,CAAC;gBAAE,OAAO,KAAK,CAAC;YAC7B,CAAC,GAAG,GAAG,GAAG,CAAC,CAAC;QACd,CAAC;aAAM,CAAC;YACN,MAAM;QACR,CAAC;IACH,CAAC;IACD,OAAO,IAAI,MAAM,CAAC,QAAQ,SAAS,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AACnE,CAAC"}
@@ -0,0 +1,10 @@
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 declare function packageName(specifier: string, aliasPrefixes: readonly string[], builtins: ReadonlySet<string>): string | null;
6
+ /** The package names a package.json text declares in any dependency field. Self-contained: see packageName. */
7
+ export declare function declaredPackages(packageJsonText: string): string[];
8
+ /** Whether an import of package `name` reaches into its build or implementation folders. Self-contained. */
9
+ export declare function isPackageInternal(specifier: string, name: string): boolean;
10
+ //# sourceMappingURL=package-name.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package-name.d.ts","sourceRoot":"","sources":["../../src/scanner/package-name.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,WAAW,CACzB,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,SAAS,MAAM,EAAE,EAChC,QAAQ,EAAE,WAAW,CAAC,MAAM,CAAC,GAC5B,MAAM,GAAG,IAAI,CASf;AAED,+GAA+G;AAC/G,wBAAgB,gBAAgB,CAAC,eAAe,EAAE,MAAM,GAAG,MAAM,EAAE,CAalE;AAED,4GAA4G;AAC5G,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAG1E"}