@webpieces/nx-webpieces-rules 0.4.853 → 0.4.855
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/README.md +14 -0
- package/executors.json +5 -0
- package/package.json +7 -7
- package/src/executors/generate/executor.js +31 -55
- package/src/executors/generate/executor.js.map +1 -1
- package/src/executors/runtime-wiring-check/executor.d.ts +10 -0
- package/src/executors/runtime-wiring-check/executor.js +42 -0
- package/src/executors/runtime-wiring-check/executor.js.map +1 -0
- package/src/executors/runtime-wiring-check/schema.json +14 -0
- package/src/executors/validate-api-lib-tag/executor.js +5 -3
- package/src/executors/validate-api-lib-tag/executor.js.map +1 -1
- package/src/executors/validate-api-relations/executor.js +11 -8
- package/src/executors/validate-api-relations/executor.js.map +1 -1
- package/src/executors/validate-architecture-unchanged/executor.d.ts +1 -1
- package/src/executors/validate-architecture-unchanged/executor.js +22 -24
- package/src/executors/validate-architecture-unchanged/executor.js.map +1 -1
- package/src/index.d.ts +1 -0
- package/src/index.js +5 -1
- package/src/index.js.map +1 -1
- package/src/lib/api-usage/api-contract-approval.d.ts +7 -0
- package/src/lib/api-usage/api-contract-approval.js +50 -0
- package/src/lib/api-usage/api-contract-approval.js.map +1 -0
- package/src/lib/api-usage/api-contract-evidence.d.ts +6 -0
- package/src/lib/api-usage/api-contract-evidence.js +41 -0
- package/src/lib/api-usage/api-contract-evidence.js.map +1 -0
- package/src/lib/api-usage/api-relations-validator.d.ts +13 -2
- package/src/lib/api-usage/api-relations-validator.js +23 -0
- package/src/lib/api-usage/api-relations-validator.js.map +1 -1
- package/src/lib/api-usage/api-relations.d.ts +3 -0
- package/src/lib/api-usage/api-relations.js.map +1 -1
- package/src/lib/api-usage/api-scanner.d.ts +40 -0
- package/src/lib/api-usage/api-scanner.js +7 -1
- package/src/lib/api-usage/api-scanner.js.map +1 -1
- package/src/lib/graph-comparator.js +11 -1
- package/src/lib/graph-comparator.js.map +1 -1
- package/src/lib/graph-filter.client.d.ts +40 -0
- package/src/lib/graph-filter.client.js +190 -0
- package/src/lib/graph-filter.client.js.map +1 -0
- package/src/lib/graph-level-bands.d.ts +0 -18
- package/src/lib/graph-level-bands.js +4 -3
- package/src/lib/graph-level-bands.js.map +1 -1
- package/src/lib/graph-loader.js +12 -6
- package/src/lib/graph-loader.js.map +1 -1
- package/src/lib/graph-navigation.d.ts +5 -0
- package/src/lib/graph-navigation.js +102 -0
- package/src/lib/graph-navigation.js.map +1 -0
- package/src/lib/graph-node-menu.d.ts +1 -0
- package/src/lib/graph-node-menu.js +29 -0
- package/src/lib/graph-node-menu.js.map +1 -1
- package/src/lib/graph-render-model.d.ts +32 -0
- package/src/lib/graph-render-model.js +76 -0
- package/src/lib/graph-render-model.js.map +1 -0
- package/src/lib/graph-sorter.d.ts +2 -0
- package/src/lib/graph-sorter.js.map +1 -1
- package/src/lib/graph-visualizer.client.d.ts +14 -73
- package/src/lib/graph-visualizer.client.js +71 -243
- package/src/lib/graph-visualizer.client.js.map +1 -1
- package/src/lib/graph-visualizer.d.ts +8 -15
- package/src/lib/graph-visualizer.js +48 -26
- package/src/lib/graph-visualizer.js.map +1 -1
- package/src/lib/runtime-details.d.ts +13 -0
- package/src/lib/runtime-details.js +191 -0
- package/src/lib/runtime-details.js.map +1 -0
- package/src/lib/runtime-graph-model.d.ts +4 -1
- package/src/lib/runtime-graph-model.js.map +1 -1
- package/src/lib/runtime-graph.js +10 -4
- package/src/lib/runtime-graph.js.map +1 -1
- package/src/lib/runtime-html-page.d.ts +7 -3
- package/src/lib/runtime-html-page.js +19 -6
- package/src/lib/runtime-html-page.js.map +1 -1
- package/src/lib/runtime-visualizer.client.d.ts +8 -19
- package/src/lib/runtime-visualizer.client.js +28 -41
- package/src/lib/runtime-visualizer.client.js.map +1 -1
- package/src/lib/runtime-visualizer.d.ts +3 -45
- package/src/lib/runtime-visualizer.js +77 -79
- package/src/lib/runtime-visualizer.js.map +1 -1
- package/src/lib/runtime-viz-theme.js +4 -3
- package/src/lib/runtime-viz-theme.js.map +1 -1
- package/src/lib/runtime-wiring/DeclarationCompileAssertions.d.ts +4 -0
- package/src/lib/runtime-wiring/DeclarationCompileAssertions.js +27 -0
- package/src/lib/runtime-wiring/DeclarationCompileAssertions.js.map +1 -0
- package/src/lib/runtime-wiring/approved-graph.d.ts +8 -0
- package/src/lib/runtime-wiring/approved-graph.js +115 -0
- package/src/lib/runtime-wiring/approved-graph.js.map +1 -0
- package/src/lib/runtime-wiring/assembler.d.ts +24 -0
- package/src/lib/runtime-wiring/assembler.js +116 -0
- package/src/lib/runtime-wiring/assembler.js.map +1 -0
- package/src/lib/runtime-wiring/codec.d.ts +14 -0
- package/src/lib/runtime-wiring/codec.js +162 -0
- package/src/lib/runtime-wiring/codec.js.map +1 -0
- package/src/lib/runtime-wiring/declaration.d.ts +68 -0
- package/src/lib/runtime-wiring/declaration.js +88 -0
- package/src/lib/runtime-wiring/declaration.js.map +1 -0
- package/src/lib/runtime-wiring/source-extractor.d.ts +28 -0
- package/src/lib/runtime-wiring/source-extractor.js +253 -0
- package/src/lib/runtime-wiring/source-extractor.js.map +1 -0
- package/src/lib/runtime-wiring/source-values.d.ts +21 -0
- package/src/lib/runtime-wiring/source-values.js +204 -0
- package/src/lib/runtime-wiring/source-values.js.map +1 -0
- package/src/lib/runtime-wiring/verification.d.ts +9 -0
- package/src/lib/runtime-wiring/verification.js +56 -0
- package/src/lib/runtime-wiring/verification.js.map +1 -0
- package/src/plugin.d.ts +0 -21
- package/src/plugin.js +12 -7
- package/src/plugin.js.map +1 -1
- package/src/runtime-wiring-targets.d.ts +7 -0
- package/src/runtime-wiring-targets.js +58 -0
- package/src/runtime-wiring-targets.js.map +1 -0
- package/src/validation-targets.js +10 -2
- package/src/validation-targets.js.map +1 -1
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.WiringSourceValues = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const path = tslib_1.__importStar(require("path"));
|
|
6
|
+
const ts = tslib_1.__importStar(require("typescript"));
|
|
7
|
+
const rules_config_1 = require("@webpieces/rules-config");
|
|
8
|
+
const declaration_1 = require("./declaration");
|
|
9
|
+
/** Resolves imported symbols and bounded literal expressions without invoking application code. */
|
|
10
|
+
class WiringSourceValues {
|
|
11
|
+
workspaceRoot;
|
|
12
|
+
infos;
|
|
13
|
+
checker;
|
|
14
|
+
constructor(workspaceRoot, infos, checker) {
|
|
15
|
+
this.workspaceRoot = workspaceRoot;
|
|
16
|
+
this.infos = infos;
|
|
17
|
+
this.checker = checker;
|
|
18
|
+
}
|
|
19
|
+
symbolName(node) {
|
|
20
|
+
const symbol = this.symbol(node);
|
|
21
|
+
const declaration = symbol?.declarations?.[0];
|
|
22
|
+
if (declaration !== undefined &&
|
|
23
|
+
ts.isVariableDeclaration(declaration) &&
|
|
24
|
+
declaration.initializer !== undefined &&
|
|
25
|
+
(ts.isPropertyAccessExpression(declaration.initializer) ||
|
|
26
|
+
ts.isElementAccessExpression(declaration.initializer)))
|
|
27
|
+
return this.symbolName(declaration.initializer);
|
|
28
|
+
return symbol?.getName() ?? node.getText().split('.').pop();
|
|
29
|
+
}
|
|
30
|
+
identity(node) {
|
|
31
|
+
const symbol = this.symbol(node);
|
|
32
|
+
const declaration = symbol?.declarations?.[0];
|
|
33
|
+
if (declaration === undefined)
|
|
34
|
+
this.fail(`Cannot resolve canonical identity for ${node.getText()}.`);
|
|
35
|
+
const file = path.resolve(declaration.getSourceFile().fileName);
|
|
36
|
+
const owners = [...this.infos.values()].filter((info) => info.root !== '.' &&
|
|
37
|
+
info.root !== '' &&
|
|
38
|
+
file.startsWith(path.resolve(this.workspaceRoot, info.root) + path.sep));
|
|
39
|
+
owners.sort((left, right) => right.root.length - left.root.length);
|
|
40
|
+
if (owners.length === 0)
|
|
41
|
+
this.fail(`No workspace owner for ${node.getText()} at ${file}; configure source tsconfig paths.`);
|
|
42
|
+
return new declaration_1.ContractIdentity(owners[0].name, symbol.getName());
|
|
43
|
+
}
|
|
44
|
+
target(expression, depth = 0) {
|
|
45
|
+
if (expression === undefined || depth > 20)
|
|
46
|
+
this.fail('Missing or cyclic runtime target expression.');
|
|
47
|
+
const value = expression;
|
|
48
|
+
if (ts.isStringLiteralLike(value))
|
|
49
|
+
return { kind: 'service', service: value.text };
|
|
50
|
+
if (ts.isCallExpression(value) && this.symbolName(value.expression) === 'rpcTarget') {
|
|
51
|
+
const target = this.target(value.arguments[1], depth + 1);
|
|
52
|
+
if (target.kind !== 'service')
|
|
53
|
+
this.fail('rpcTarget requires a literal deployment identity.');
|
|
54
|
+
return { ...target, contract: this.identity(value.arguments[0]) };
|
|
55
|
+
}
|
|
56
|
+
if (ts.isNewExpression(value) &&
|
|
57
|
+
['RpcTarget', 'ClientConfig', 'TaskClientConfig'].includes(this.symbolName(value.expression)))
|
|
58
|
+
return this.target(value.arguments?.[this.symbolName(value.expression) === 'RpcTarget' ? 1 : 0], depth + 1);
|
|
59
|
+
const declaration = this.symbol(value)?.declarations?.[0];
|
|
60
|
+
if (declaration !== undefined && ts.isVariableDeclaration(declaration))
|
|
61
|
+
return this.target(declaration.initializer, depth + 1);
|
|
62
|
+
if (declaration !== undefined && ts.isPropertyAssignment(declaration))
|
|
63
|
+
return this.target(declaration.initializer, depth + 1);
|
|
64
|
+
if (declaration !== undefined && ts.isParameter(declaration))
|
|
65
|
+
return { kind: 'parameter', parameter: declaration.name.getText() };
|
|
66
|
+
this.fail(`Unsupported target ${value.getText()}; use a literal service, rpcTarget, or an explicit typed target parameter.`);
|
|
67
|
+
}
|
|
68
|
+
transport(expression) {
|
|
69
|
+
const declaration = this.symbol(expression)?.declarations?.[0];
|
|
70
|
+
if (declaration === undefined || !ts.isClassDeclaration(declaration))
|
|
71
|
+
this.fail(`API ${expression.getText()} must resolve to its source contract class.`);
|
|
72
|
+
for (const decorator of ts.getDecorators(declaration) ?? []) {
|
|
73
|
+
const expression = decorator.expression;
|
|
74
|
+
const name = this.symbolName(ts.isCallExpression(expression) ? expression.expression : expression);
|
|
75
|
+
if (name === 'PubSub')
|
|
76
|
+
return 'pubsub';
|
|
77
|
+
}
|
|
78
|
+
return 'rpc';
|
|
79
|
+
}
|
|
80
|
+
arguments(invocation) {
|
|
81
|
+
const targets = {};
|
|
82
|
+
const signature = this.checker.getResolvedSignature(invocation);
|
|
83
|
+
for (const [index, parameter] of (signature?.getParameters() ?? []).entries()) {
|
|
84
|
+
const declaration = parameter.valueDeclaration;
|
|
85
|
+
if (declaration === undefined)
|
|
86
|
+
continue;
|
|
87
|
+
const type = this.checker.typeToString(this.checker.getTypeOfSymbolAtLocation(parameter, declaration));
|
|
88
|
+
if (type.includes('RpcTarget') ||
|
|
89
|
+
(type === 'string' && /target/i.test(parameter.getName()))) {
|
|
90
|
+
targets[parameter.getName()] = this.target(invocation.arguments?.[index]);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return targets;
|
|
94
|
+
}
|
|
95
|
+
hasExternalConsumer(owner, project, exportedName, program) {
|
|
96
|
+
const info = this.infos.get(owner);
|
|
97
|
+
if (info === undefined)
|
|
98
|
+
return false;
|
|
99
|
+
const root = path.resolve(this.workspaceRoot, info.root) + path.sep;
|
|
100
|
+
let found = false;
|
|
101
|
+
const visit = (node) => {
|
|
102
|
+
if (ts.isClassDeclaration(node)) {
|
|
103
|
+
// An adapter implements a seam; it does not prove a business caller uses that seam.
|
|
104
|
+
const adapter = node.heritageClauses?.some((clause) => clause.token === ts.SyntaxKind.ImplementsKeyword &&
|
|
105
|
+
clause.types.some((type) => {
|
|
106
|
+
if (this.symbol(type.expression)?.getName() !== exportedName)
|
|
107
|
+
return false;
|
|
108
|
+
return this.identity(type.expression).project === project;
|
|
109
|
+
}));
|
|
110
|
+
if (adapter)
|
|
111
|
+
return;
|
|
112
|
+
for (const member of node.members) {
|
|
113
|
+
if (!ts.isConstructorDeclaration(member))
|
|
114
|
+
continue;
|
|
115
|
+
for (const parameter of member.parameters) {
|
|
116
|
+
if (parameter.type === undefined || !ts.isTypeReferenceNode(parameter.type))
|
|
117
|
+
continue;
|
|
118
|
+
const symbol = this.symbol(parameter.type.typeName);
|
|
119
|
+
const declaration = symbol?.declarations?.[0];
|
|
120
|
+
if (declaration === undefined ||
|
|
121
|
+
symbol?.getName() !== exportedName ||
|
|
122
|
+
!(ts.isInterfaceDeclaration(declaration) ||
|
|
123
|
+
ts.isClassDeclaration(declaration)))
|
|
124
|
+
continue;
|
|
125
|
+
const identity = this.identity(parameter.type.typeName);
|
|
126
|
+
if (identity.project === project && identity.exportedName === exportedName)
|
|
127
|
+
found = true;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
ts.forEachChild(node, visit);
|
|
132
|
+
};
|
|
133
|
+
for (const file of program.getSourceFiles()) {
|
|
134
|
+
if (file.isDeclarationFile ||
|
|
135
|
+
!file.fileName.startsWith(root) ||
|
|
136
|
+
/(?:\.spec\.|\.test\.|\/__tests__\/)/.test(file.fileName))
|
|
137
|
+
continue;
|
|
138
|
+
visit(file);
|
|
139
|
+
}
|
|
140
|
+
return found;
|
|
141
|
+
}
|
|
142
|
+
policies(invocation) {
|
|
143
|
+
const policies = {};
|
|
144
|
+
const signature = this.checker.getResolvedSignature(invocation);
|
|
145
|
+
for (const [index, parameter] of (signature?.getParameters() ?? []).entries()) {
|
|
146
|
+
const declaration = parameter.valueDeclaration;
|
|
147
|
+
if (declaration === undefined)
|
|
148
|
+
continue;
|
|
149
|
+
const type = this.checker.typeToString(this.checker.getTypeOfSymbolAtLocation(parameter, declaration));
|
|
150
|
+
if (!type.includes('WiringPolicy'))
|
|
151
|
+
continue;
|
|
152
|
+
const argument = invocation.arguments?.[index];
|
|
153
|
+
if (argument === undefined ||
|
|
154
|
+
!ts.isNewExpression(argument) ||
|
|
155
|
+
this.symbolName(argument.expression) !== 'WiringPolicy')
|
|
156
|
+
this.fail('Pass an explicit named WiringPolicy to conditional modules.');
|
|
157
|
+
const condition = argument.arguments?.[1];
|
|
158
|
+
policies[parameter.getName()] =
|
|
159
|
+
condition?.kind === ts.SyntaxKind.TrueKeyword
|
|
160
|
+
? true
|
|
161
|
+
: condition?.kind === ts.SyntaxKind.FalseKeyword
|
|
162
|
+
? false
|
|
163
|
+
: 'runtime';
|
|
164
|
+
}
|
|
165
|
+
return policies;
|
|
166
|
+
}
|
|
167
|
+
condition(call) {
|
|
168
|
+
let child = call;
|
|
169
|
+
let node = call.parent;
|
|
170
|
+
let policy;
|
|
171
|
+
while (node !== undefined &&
|
|
172
|
+
!ts.isClassDeclaration(node) &&
|
|
173
|
+
!ts.isFunctionDeclaration(node)) {
|
|
174
|
+
if (ts.isIfStatement(node)) {
|
|
175
|
+
if (policy !== undefined || child === node.elseStatement)
|
|
176
|
+
this.fail('Nested topology policies and else branches require separate explicitly selected modules.');
|
|
177
|
+
const condition = node.expression;
|
|
178
|
+
if (!ts.isPropertyAccessExpression(condition) || condition.name.text !== 'enabled')
|
|
179
|
+
this.fail('Topology conditions must use a named WiringPolicy.enabled.');
|
|
180
|
+
policy = this.symbolName(condition.expression);
|
|
181
|
+
}
|
|
182
|
+
if (ts.isConditionalExpression(node) ||
|
|
183
|
+
ts.isSwitchStatement(node) ||
|
|
184
|
+
ts.isIterationStatement(node, false))
|
|
185
|
+
this.fail('Dynamic topology branches and loops require explicit selected modules.');
|
|
186
|
+
child = node;
|
|
187
|
+
node = node.parent;
|
|
188
|
+
}
|
|
189
|
+
return policy;
|
|
190
|
+
}
|
|
191
|
+
symbol(node) {
|
|
192
|
+
const symbol = this.checker.getSymbolAtLocation(node);
|
|
193
|
+
return symbol !== undefined && (symbol.flags & ts.SymbolFlags.Alias) !== 0
|
|
194
|
+
? this.checker.getAliasedSymbol(symbol)
|
|
195
|
+
: symbol;
|
|
196
|
+
}
|
|
197
|
+
fail(message) {
|
|
198
|
+
throw new rules_config_1.RuleFailError('validate-runtime-architecture', message, undefined, undefined, [
|
|
199
|
+
new rules_config_1.Option('Use qualified imports and bounded target declarations in src/wiring.ts.', true),
|
|
200
|
+
]);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
exports.WiringSourceValues = WiringSourceValues;
|
|
204
|
+
//# sourceMappingURL=source-values.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"source-values.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/nx-webpieces-rules/src/lib/runtime-wiring/source-values.ts"],"names":[],"mappings":"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","sourcesContent":["import * as path from 'path';\nimport * as ts from 'typescript';\nimport { Option, RuleFailError } from '@webpieces/rules-config';\nimport type { ProjectInfo } from '../project-info';\nimport { ContractIdentity } from './declaration';\nimport type { DeclaredTarget } from './declaration';\n\n/** Resolves imported symbols and bounded literal expressions without invoking application code. */\nexport class WiringSourceValues {\n constructor(\n private readonly workspaceRoot: string,\n private readonly infos: ReadonlyMap<string, ProjectInfo>,\n private readonly checker: ts.TypeChecker,\n ) {}\n\n symbolName(node: ts.Node): string {\n const symbol = this.symbol(node);\n const declaration = symbol?.declarations?.[0];\n if (\n declaration !== undefined &&\n ts.isVariableDeclaration(declaration) &&\n declaration.initializer !== undefined &&\n (ts.isPropertyAccessExpression(declaration.initializer) ||\n ts.isElementAccessExpression(declaration.initializer))\n )\n return this.symbolName(declaration.initializer);\n return symbol?.getName() ?? node.getText().split('.').pop()!;\n }\n\n identity(node: ts.Node): ContractIdentity {\n const symbol = this.symbol(node);\n const declaration = symbol?.declarations?.[0];\n if (declaration === undefined)\n this.fail(`Cannot resolve canonical identity for ${node.getText()}.`);\n const file = path.resolve(declaration!.getSourceFile().fileName);\n const owners = [...this.infos.values()].filter(\n (info) =>\n info.root !== '.' &&\n info.root !== '' &&\n file.startsWith(path.resolve(this.workspaceRoot, info.root) + path.sep),\n );\n owners.sort((left, right) => right.root.length - left.root.length);\n if (owners.length === 0)\n this.fail(\n `No workspace owner for ${node.getText()} at ${file}; configure source tsconfig paths.`,\n );\n return new ContractIdentity(owners[0].name, symbol!.getName());\n }\n\n target(expression: ts.Expression | undefined, depth: number = 0): DeclaredTarget {\n if (expression === undefined || depth > 20)\n this.fail('Missing or cyclic runtime target expression.');\n const value = expression!;\n if (ts.isStringLiteralLike(value)) return { kind: 'service', service: value.text };\n if (ts.isCallExpression(value) && this.symbolName(value.expression) === 'rpcTarget') {\n const target = this.target(value.arguments[1], depth + 1);\n if (target.kind !== 'service')\n this.fail('rpcTarget requires a literal deployment identity.');\n return { ...target, contract: this.identity(value.arguments[0]) };\n }\n if (\n ts.isNewExpression(value) &&\n ['RpcTarget', 'ClientConfig', 'TaskClientConfig'].includes(\n this.symbolName(value.expression),\n )\n )\n return this.target(\n value.arguments?.[this.symbolName(value.expression) === 'RpcTarget' ? 1 : 0],\n depth + 1,\n );\n const declaration = this.symbol(value)?.declarations?.[0];\n if (declaration !== undefined && ts.isVariableDeclaration(declaration))\n return this.target(declaration.initializer, depth + 1);\n if (declaration !== undefined && ts.isPropertyAssignment(declaration))\n return this.target(declaration.initializer, depth + 1);\n if (declaration !== undefined && ts.isParameter(declaration))\n return { kind: 'parameter', parameter: declaration.name.getText() };\n this.fail(\n `Unsupported target ${value.getText()}; use a literal service, rpcTarget, or an explicit typed target parameter.`,\n );\n }\n\n transport(expression: ts.Expression): 'rpc' | 'pubsub' {\n const declaration = this.symbol(expression)?.declarations?.[0];\n if (declaration === undefined || !ts.isClassDeclaration(declaration))\n this.fail(`API ${expression.getText()} must resolve to its source contract class.`);\n for (const decorator of ts.getDecorators(declaration as ts.ClassDeclaration) ?? []) {\n const expression = decorator.expression;\n const name = this.symbolName(\n ts.isCallExpression(expression) ? expression.expression : expression,\n );\n if (name === 'PubSub') return 'pubsub';\n }\n return 'rpc';\n }\n\n arguments(invocation: ts.NewExpression | ts.CallExpression): Record<string, DeclaredTarget> {\n const targets: Record<string, DeclaredTarget> = {};\n const signature = this.checker.getResolvedSignature(invocation);\n for (const [index, parameter] of (signature?.getParameters() ?? []).entries()) {\n const declaration = parameter.valueDeclaration;\n if (declaration === undefined) continue;\n const type = this.checker.typeToString(\n this.checker.getTypeOfSymbolAtLocation(parameter, declaration),\n );\n if (\n type.includes('RpcTarget') ||\n (type === 'string' && /target/i.test(parameter.getName()))\n ) {\n targets[parameter.getName()] = this.target(invocation.arguments?.[index]);\n }\n }\n return targets;\n }\n\n hasExternalConsumer(\n owner: string,\n project: string,\n exportedName: string,\n program: ts.Program,\n ): boolean {\n const info = this.infos.get(owner);\n if (info === undefined) return false;\n const root = path.resolve(this.workspaceRoot, info.root) + path.sep;\n let found = false;\n const visit = (node: ts.Node): void => {\n if (ts.isClassDeclaration(node)) {\n // An adapter implements a seam; it does not prove a business caller uses that seam.\n const adapter = node.heritageClauses?.some(\n (clause) =>\n clause.token === ts.SyntaxKind.ImplementsKeyword &&\n clause.types.some((type) => {\n if (this.symbol(type.expression)?.getName() !== exportedName)\n return false;\n return this.identity(type.expression).project === project;\n }),\n );\n if (adapter) return;\n for (const member of node.members) {\n if (!ts.isConstructorDeclaration(member)) continue;\n for (const parameter of member.parameters) {\n if (parameter.type === undefined || !ts.isTypeReferenceNode(parameter.type))\n continue;\n const symbol = this.symbol(parameter.type.typeName);\n const declaration = symbol?.declarations?.[0];\n if (\n declaration === undefined ||\n symbol?.getName() !== exportedName ||\n !(\n ts.isInterfaceDeclaration(declaration) ||\n ts.isClassDeclaration(declaration)\n )\n )\n continue;\n const identity = this.identity(parameter.type.typeName);\n if (identity.project === project && identity.exportedName === exportedName)\n found = true;\n }\n }\n }\n ts.forEachChild(node, visit);\n };\n for (const file of program.getSourceFiles()) {\n if (\n file.isDeclarationFile ||\n !file.fileName.startsWith(root) ||\n /(?:\\.spec\\.|\\.test\\.|\\/__tests__\\/)/.test(file.fileName)\n )\n continue;\n visit(file);\n }\n return found;\n }\n\n policies(\n invocation: ts.NewExpression | ts.CallExpression,\n ): Record<string, boolean | 'runtime'> {\n const policies: Record<string, boolean | 'runtime'> = {};\n const signature = this.checker.getResolvedSignature(invocation);\n for (const [index, parameter] of (signature?.getParameters() ?? []).entries()) {\n const declaration = parameter.valueDeclaration;\n if (declaration === undefined) continue;\n const type = this.checker.typeToString(\n this.checker.getTypeOfSymbolAtLocation(parameter, declaration),\n );\n if (!type.includes('WiringPolicy')) continue;\n const argument = invocation.arguments?.[index];\n if (\n argument === undefined ||\n !ts.isNewExpression(argument) ||\n this.symbolName(argument.expression) !== 'WiringPolicy'\n )\n this.fail('Pass an explicit named WiringPolicy to conditional modules.');\n const condition = argument.arguments?.[1];\n policies[parameter.getName()] =\n condition?.kind === ts.SyntaxKind.TrueKeyword\n ? true\n : condition?.kind === ts.SyntaxKind.FalseKeyword\n ? false\n : 'runtime';\n }\n return policies;\n }\n\n condition(call: ts.Node): string | undefined {\n let child = call;\n let node: ts.Node | undefined = call.parent;\n let policy: string | undefined;\n while (\n node !== undefined &&\n !ts.isClassDeclaration(node) &&\n !ts.isFunctionDeclaration(node)\n ) {\n if (ts.isIfStatement(node)) {\n if (policy !== undefined || child === node.elseStatement)\n this.fail(\n 'Nested topology policies and else branches require separate explicitly selected modules.',\n );\n const condition = node.expression;\n if (!ts.isPropertyAccessExpression(condition) || condition.name.text !== 'enabled')\n this.fail('Topology conditions must use a named WiringPolicy.enabled.');\n policy = this.symbolName((condition as ts.PropertyAccessExpression).expression);\n }\n if (\n ts.isConditionalExpression(node) ||\n ts.isSwitchStatement(node) ||\n ts.isIterationStatement(node, false)\n )\n this.fail('Dynamic topology branches and loops require explicit selected modules.');\n child = node;\n node = node.parent;\n }\n return policy;\n }\n\n private symbol(node: ts.Node): ts.Symbol | undefined {\n const symbol = this.checker.getSymbolAtLocation(node);\n return symbol !== undefined && (symbol.flags & ts.SymbolFlags.Alias) !== 0\n ? this.checker.getAliasedSymbol(symbol)\n : symbol;\n }\n\n private fail(message: string): never {\n throw new RuleFailError('validate-runtime-architecture', message, undefined, undefined, [\n new Option(\n 'Use qualified imports and bounded target declarations in src/wiring.ts.',\n true,\n ),\n ]);\n }\n}\n"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ProjectInfo } from '../project-info';
|
|
2
|
+
import { RuntimeDeclaration } from './declaration';
|
|
3
|
+
/** Candidates are build outputs. The verifier has no code path that writes the approved file. */
|
|
4
|
+
export declare class RuntimeWiringVerification {
|
|
5
|
+
verify(workspaceRoot: string, info: ProjectInfo, infos: ReadonlyMap<string, ProjectInfo>, outputPath: string): void;
|
|
6
|
+
format(declaration: RuntimeDeclaration): string;
|
|
7
|
+
private diff;
|
|
8
|
+
private fail;
|
|
9
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RuntimeWiringVerification = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const fs = tslib_1.__importStar(require("fs"));
|
|
6
|
+
const path = tslib_1.__importStar(require("path"));
|
|
7
|
+
const rules_config_1 = require("@webpieces/rules-config");
|
|
8
|
+
const codec_1 = require("./codec");
|
|
9
|
+
const source_extractor_1 = require("./source-extractor");
|
|
10
|
+
const declaration_1 = require("./declaration");
|
|
11
|
+
/** Candidates are build outputs. The verifier has no code path that writes the approved file. */
|
|
12
|
+
class RuntimeWiringVerification {
|
|
13
|
+
verify(workspaceRoot, info, infos, outputPath) {
|
|
14
|
+
const candidate = new source_extractor_1.WiringSourceExtractor(workspaceRoot, info, infos, new source_extractor_1.WiringProjectProgram().create(workspaceRoot, info)).extract();
|
|
15
|
+
const candidatePath = path.join(workspaceRoot, outputPath, 'runtime-deps.candidate.json');
|
|
16
|
+
const approvedPath = path.join(workspaceRoot, info.root, 'runtime-deps.json');
|
|
17
|
+
fs.mkdirSync(path.dirname(candidatePath), { recursive: true });
|
|
18
|
+
const actual = this.format(candidate);
|
|
19
|
+
fs.writeFileSync(candidatePath, actual, 'utf8');
|
|
20
|
+
if (!fs.existsSync(approvedPath))
|
|
21
|
+
this.fail(`Missing approved declaration ${approvedPath}. Candidate: ${candidatePath}.`);
|
|
22
|
+
const approved = new codec_1.RuntimeDeclarationCodec().decode(fs.readFileSync(approvedPath, 'utf8'), info.name);
|
|
23
|
+
const expected = this.format(approved);
|
|
24
|
+
if (expected !== actual)
|
|
25
|
+
this.fail(`${info.name} runtime wiring changed. Approved: ${approvedPath}. Candidate: ${candidatePath}.\n${this.diff(expected, actual)}`);
|
|
26
|
+
}
|
|
27
|
+
format(declaration) {
|
|
28
|
+
const exports = Object.fromEntries(Object.entries(declaration.exports).sort((left, right) => left[0].localeCompare(right[0])));
|
|
29
|
+
return JSON.stringify(newDeclaration(declaration, exports), null, 4) + '\n';
|
|
30
|
+
}
|
|
31
|
+
diff(expected, actual) {
|
|
32
|
+
const before = expected.split('\n');
|
|
33
|
+
const after = actual.split('\n');
|
|
34
|
+
const lines = [];
|
|
35
|
+
for (let index = 0; index < Math.max(before.length, after.length); index++) {
|
|
36
|
+
if (before[index] === after[index])
|
|
37
|
+
continue;
|
|
38
|
+
if (before[index] !== undefined)
|
|
39
|
+
lines.push(`- ${before[index]}`);
|
|
40
|
+
if (after[index] !== undefined)
|
|
41
|
+
lines.push(`+ ${after[index]}`);
|
|
42
|
+
}
|
|
43
|
+
return lines.join('\n');
|
|
44
|
+
}
|
|
45
|
+
fail(message) {
|
|
46
|
+
throw new rules_config_1.RuleFailError('validate-runtime-architecture', message, undefined, undefined, [
|
|
47
|
+
new rules_config_1.Option('Review the candidate diff, fix incorrect wiring, then explicitly copy the reviewed candidate to runtime-deps.json. Builds never approve it automatically.', true),
|
|
48
|
+
]);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
exports.RuntimeWiringVerification = RuntimeWiringVerification;
|
|
52
|
+
// webpieces-disable no-function-outside-class -- canonical serialization of a reviewed declaration
|
|
53
|
+
function newDeclaration(declaration, exports) {
|
|
54
|
+
return new declaration_1.RuntimeDeclaration(declaration.project, declaration.framework, exports, declaration.entry, declaration.host);
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=verification.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verification.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/nx-webpieces-rules/src/lib/runtime-wiring/verification.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from 'fs';\nimport * as path from 'path';\nimport { Option, RuleFailError } from '@webpieces/rules-config';\nimport type { ProjectInfo } from '../project-info';\nimport { RuntimeDeclarationCodec } from './codec';\nimport { WiringProjectProgram, WiringSourceExtractor } from './source-extractor';\nimport { RuntimeDeclaration } from './declaration';\n\n/** Candidates are build outputs. The verifier has no code path that writes the approved file. */\nexport class RuntimeWiringVerification {\n verify(\n workspaceRoot: string,\n info: ProjectInfo,\n infos: ReadonlyMap<string, ProjectInfo>,\n outputPath: string,\n ): void {\n const candidate = new WiringSourceExtractor(\n workspaceRoot,\n info,\n infos,\n new WiringProjectProgram().create(workspaceRoot, info),\n ).extract();\n const candidatePath = path.join(workspaceRoot, outputPath, 'runtime-deps.candidate.json');\n const approvedPath = path.join(workspaceRoot, info.root, 'runtime-deps.json');\n fs.mkdirSync(path.dirname(candidatePath), { recursive: true });\n const actual = this.format(candidate);\n fs.writeFileSync(candidatePath, actual, 'utf8');\n if (!fs.existsSync(approvedPath))\n this.fail(`Missing approved declaration ${approvedPath}. Candidate: ${candidatePath}.`);\n const approved = new RuntimeDeclarationCodec().decode(\n fs.readFileSync(approvedPath, 'utf8'),\n info.name,\n );\n const expected = this.format(approved);\n if (expected !== actual)\n this.fail(\n `${info.name} runtime wiring changed. Approved: ${approvedPath}. Candidate: ${candidatePath}.\\n${this.diff(expected, actual)}`,\n );\n }\n\n format(declaration: RuntimeDeclaration): string {\n const exports = Object.fromEntries(\n Object.entries(declaration.exports).sort((left, right) =>\n left[0].localeCompare(right[0]),\n ),\n );\n return JSON.stringify(newDeclaration(declaration, exports), null, 4) + '\\n';\n }\n\n private diff(expected: string, actual: string): string {\n const before = expected.split('\\n');\n const after = actual.split('\\n');\n const lines: string[] = [];\n for (let index = 0; index < Math.max(before.length, after.length); index++) {\n if (before[index] === after[index]) continue;\n if (before[index] !== undefined) lines.push(`- ${before[index]}`);\n if (after[index] !== undefined) lines.push(`+ ${after[index]}`);\n }\n return lines.join('\\n');\n }\n\n private fail(message: string): never {\n throw new RuleFailError('validate-runtime-architecture', message, undefined, undefined, [\n new Option(\n 'Review the candidate diff, fix incorrect wiring, then explicitly copy the reviewed candidate to runtime-deps.json. Builds never approve it automatically.',\n true,\n ),\n ]);\n }\n}\n\n// webpieces-disable no-function-outside-class -- canonical serialization of a reviewed declaration\nfunction newDeclaration(\n declaration: RuntimeDeclaration,\n exports: RuntimeDeclaration['exports'],\n): RuntimeDeclaration {\n return new RuntimeDeclaration(\n declaration.project,\n declaration.framework,\n exports,\n declaration.entry,\n declaration.host,\n );\n}\n"]}
|
package/src/plugin.d.ts
CHANGED
|
@@ -1,24 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Unified Nx Inference Plugin for @webpieces/nx-webpieces-rules
|
|
3
|
-
*
|
|
4
|
-
* This plugin automatically creates targets for:
|
|
5
|
-
* 1. Workspace-level architecture validation (generate, visualize, validate-*)
|
|
6
|
-
* 2. Per-project circular dependency checking
|
|
7
|
-
* 3. Per-project API documents, opted into with a TAG: `generate:openapi` infers `openapi-generate`,
|
|
8
|
-
* `generate:openapi-components` infers `openapi-components-generate` (a DTO library's
|
|
9
|
-
* components.openapi.json), `generate:docs-site` infers `openapi-generate` + `docs-generate`
|
|
10
|
-
* (see generate-targets.ts)
|
|
11
|
-
*
|
|
12
|
-
* Install with: nx add @webpieces/nx-webpieces-rules
|
|
13
|
-
*
|
|
14
|
-
* Usage:
|
|
15
|
-
* Add to nx.json plugins array:
|
|
16
|
-
* {
|
|
17
|
-
* "plugins": ["@webpieces/nx-webpieces-rules"]
|
|
18
|
-
* }
|
|
19
|
-
*
|
|
20
|
-
* Then all targets appear automatically without manual project.json configuration.
|
|
21
|
-
*/
|
|
22
1
|
import type { CreateNodesV2, TargetConfiguration } from '@nx/devkit';
|
|
23
2
|
/**
|
|
24
3
|
* Circular dependency checking options
|
package/src/plugin.js
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createNodesV2 = void 0;
|
|
4
|
+
exports.isInsideNestedGitRepo = isInsideNestedGitRepo;
|
|
5
|
+
exports.createCiTarget = createCiTarget;
|
|
6
|
+
exports.createHotfixCiTarget = createHotfixCiTarget;
|
|
7
|
+
const runtime_wiring_targets_1 = require("./runtime-wiring-targets");
|
|
2
8
|
/**
|
|
3
9
|
* Unified Nx Inference Plugin for @webpieces/nx-webpieces-rules
|
|
4
10
|
*
|
|
@@ -20,11 +26,6 @@
|
|
|
20
26
|
*
|
|
21
27
|
* Then all targets appear automatically without manual project.json configuration.
|
|
22
28
|
*/
|
|
23
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
|
-
exports.createNodesV2 = void 0;
|
|
25
|
-
exports.isInsideNestedGitRepo = isInsideNestedGitRepo;
|
|
26
|
-
exports.createCiTarget = createCiTarget;
|
|
27
|
-
exports.createHotfixCiTarget = createHotfixCiTarget;
|
|
28
29
|
const path_1 = require("path");
|
|
29
30
|
const fs_1 = require("fs");
|
|
30
31
|
const runtime_targets_1 = require("./runtime-targets");
|
|
@@ -225,10 +226,14 @@ function buildPerProjectTargets(isProjectJson, projectRoot, opts, architectureEn
|
|
|
225
226
|
// costs this one in-memory tag check. They ride ci like every other build step — generation is
|
|
226
227
|
// ordinary BUILD work, not a side channel (#1021).
|
|
227
228
|
if (rawProject !== undefined) {
|
|
228
|
-
const generated =
|
|
229
|
+
const generated = {
|
|
230
|
+
...new generate_targets_1.GenerateTargets(projectRoot, rawProject).infer(),
|
|
231
|
+
...new runtime_wiring_targets_1.RuntimeWiringTargets().infer(rawProject),
|
|
232
|
+
};
|
|
229
233
|
for (const [name, target] of Object.entries(generated)) {
|
|
230
234
|
targets[name] = target;
|
|
231
|
-
|
|
235
|
+
if (name !== 'build')
|
|
236
|
+
validationTargets.push(name);
|
|
232
237
|
}
|
|
233
238
|
}
|
|
234
239
|
// Add ci target to ALL projects (both project.json and package.json). ci aggregates
|
package/src/plugin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../../../../packages/tooling/nx-webpieces-rules/src/plugin.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Unified Nx Inference Plugin for @webpieces/nx-webpieces-rules\n *\n * This plugin automatically creates targets for:\n * 1. Workspace-level architecture validation (generate, visualize, validate-*)\n * 2. Per-project circular dependency checking\n * 3. Per-project API documents, opted into with a TAG: `generate:openapi` infers `openapi-generate`,\n * `generate:openapi-components` infers `openapi-components-generate` (a DTO library's\n * components.openapi.json), `generate:docs-site` infers `openapi-generate` + `docs-generate`\n * (see generate-targets.ts)\n *\n * Install with: nx add @webpieces/nx-webpieces-rules\n *\n * Usage:\n * Add to nx.json plugins array:\n * {\n * \"plugins\": [\"@webpieces/nx-webpieces-rules\"]\n * }\n *\n * Then all targets appear automatically without manual project.json configuration.\n */\n\nimport { dirname, join } from 'path';\nimport { existsSync } from 'fs';\nimport type {\n CreateNodesV2,\n CreateNodesContextV2,\n CreateNodesResultV2,\n CreateNodesResult,\n TargetConfiguration,\n} from '@nx/devkit';\nimport {\n createVisualizeRuntimeTarget,\n createValidateRuntimeArchitectureTarget,\n} from './runtime-targets';\nimport { BRANCH_IDENTITY_INPUTS } from './branch-identity-inputs';\nimport { ValidationTargets } from './validation-targets';\nimport { createDiGraphGenerateTarget } from './di-graph-targets';\nimport { GenerateTargets, RawProjectJson, RawProjectJsonReader } from './generate-targets';\nimport { RulesTarget } from './rules-target';\n\n/**\n * Circular dependency checking options\n */\nexport interface CircularDepsOptions {\n enabled?: boolean;\n targetName?: string;\n excludePatterns?: string[];\n}\n\n/**\n * Validation options for architecture checks\n */\nexport interface ValidationOptions {\n noCycles?: boolean;\n architectureUnchanged?: boolean;\n validatePackageJson?: boolean;\n validateNewMethods?: boolean;\n validateModifiedMethods?: boolean;\n validateModifiedFiles?: boolean;\n validateVersionsLocked?: boolean;\n validateTsInSrc?: boolean;\n validateNxWiring?: boolean;\n runtimeArchitecture?: boolean;\n validateApiRelations?: boolean;\n validateApiLibTag?: boolean;\n diGraph?: boolean;\n newMethodsMaxLines?: number;\n modifiedAndNewMethodsMaxLines?: number;\n modifiedFilesMaxLines?: number;\n /**\n * Validation mode for method/file size limits:\n * - STRICT: All limits enforced, disable comments ignored\n * - NORMAL: Limits enforced, disable comments with dates work\n * - OFF: Skip size validations entirely (for fast iteration)\n */\n validationMode?: 'STRICT' | 'NORMAL' | 'OFF';\n}\n\n/**\n * Feature flags for workspace targets\n */\nexport interface FeatureOptions {\n generate?: boolean;\n visualize?: boolean;\n visualizeRuntime?: boolean;\n}\n\n/**\n * Workspace-level configuration options\n */\nexport interface WorkspaceOptions {\n enabled?: boolean;\n targetPrefix?: string;\n graphPath?: string;\n validations?: ValidationOptions;\n features?: FeatureOptions;\n}\n\n/**\n * Configuration for @webpieces/nx-webpieces-rules Nx plugin\n */\nexport interface ArchitecturePluginOptions {\n circularDeps?: CircularDepsOptions;\n workspace?: WorkspaceOptions;\n}\n\nconst DEFAULT_OPTIONS: Required<ArchitecturePluginOptions> = {\n circularDeps: {\n enabled: true,\n targetName: 'validate-no-file-import-cycles',\n excludePatterns: [],\n },\n workspace: {\n enabled: true,\n targetPrefix: 'arch:',\n graphPath: 'architecture/dependencies.json',\n validations: {\n noCycles: true,\n architectureUnchanged: true,\n validatePackageJson: true,\n validateNewMethods: true,\n validateModifiedMethods: true,\n validateModifiedFiles: true,\n validateVersionsLocked: true,\n validateTsInSrc: true,\n validateNxWiring: true,\n runtimeArchitecture: true,\n validateApiRelations: true,\n validateApiLibTag: true,\n diGraph: true,\n newMethodsMaxLines: 30,\n modifiedAndNewMethodsMaxLines: 80,\n modifiedFilesMaxLines: 900,\n validationMode: 'NORMAL',\n },\n features: {\n generate: true,\n visualize: true,\n visualizeRuntime: true,\n },\n },\n};\n\nfunction normalizeOptions(\n options: ArchitecturePluginOptions | undefined,\n): Required<ArchitecturePluginOptions> {\n const circularDeps = {\n ...DEFAULT_OPTIONS.circularDeps,\n ...options?.circularDeps,\n };\n\n const workspace = {\n ...DEFAULT_OPTIONS.workspace,\n ...options?.workspace,\n validations: {\n ...DEFAULT_OPTIONS.workspace.validations,\n ...options?.workspace?.validations,\n },\n features: {\n ...DEFAULT_OPTIONS.workspace.features,\n ...options?.workspace?.features,\n },\n };\n\n return {\n circularDeps,\n workspace,\n } as Required<ArchitecturePluginOptions>;\n}\n\nasync function createNodesFunction(\n projectFiles: readonly string[],\n options: ArchitecturePluginOptions | undefined,\n context: CreateNodesContextV2,\n): Promise<CreateNodesResultV2> {\n const opts = normalizeOptions(options);\n const results: CreateNodesResultV2 = [];\n\n // Add workspace-level architecture targets\n addArchitectureProject(results, projectFiles, opts, context);\n\n // One root policy target. webpieces.config.json is not a shared input of every product project;\n // this virtual project is its sole Nx owner and the gate runs it before affected CI.\n // Add per-project targets (circular-deps, ci, di-graph)\n addPerProjectTargets(results, projectFiles, opts, context);\n\n // Append the virtual root project after concrete projects so callers that select the first result\n // for a project.json still receive that project's inferred targets.\n new RulesTarget().add(results, projectFiles);\n\n return results;\n}\n\nfunction addArchitectureProject(\n results: CreateNodesResultV2,\n projectFiles: readonly string[],\n opts: Required<ArchitecturePluginOptions>,\n context: CreateNodesContextV2,\n): void {\n if (!opts.workspace.enabled) return;\n\n const archDirPath = join(context.workspaceRoot, 'architecture');\n if (!existsSync(archDirPath)) return;\n\n const workspaceTargets = createWorkspaceTargetsWithoutPrefix(opts);\n if (Object.keys(workspaceTargets).length === 0) return;\n\n const result: CreateNodesResult = {\n projects: {\n architecture: {\n name: 'architecture',\n root: 'architecture',\n targets: workspaceTargets,\n },\n },\n };\n\n const firstProjectFile = projectFiles[0];\n if (firstProjectFile) {\n results.push([firstProjectFile, result] as const);\n }\n}\n\n// A project sits inside a NESTED git repo (e.g. a clone under repositories/) when any of its\n// ancestor dirs — up to but NOT including the workspace root — contains a `.git`. Such projects are\n// separate repos, not part of THIS workspace's graph, so they must not get inferred targets (that is\n// what drags foreign clones into `nx affected`). Same repo-boundary signal the AI guards use.\nexport function isInsideNestedGitRepo(workspaceRoot: string, projectRoot: string): boolean {\n let dir = projectRoot;\n while (dir && dir !== '.' && dir !== '/') {\n if (existsSync(join(workspaceRoot, dir, '.git'))) return true;\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n return false;\n}\n\nfunction addPerProjectTargets(\n results: CreateNodesResultV2,\n projectFiles: readonly string[],\n opts: Required<ArchitecturePluginOptions>,\n context: CreateNodesContextV2,\n): void {\n // Track processed project roots to avoid duplicates when both files exist\n const processedRoots = new Set<string>();\n\n for (const projectFile of projectFiles) {\n const isProjectJson = projectFile.endsWith('project.json');\n const isPackageJson = projectFile.endsWith('package.json');\n\n if (!isProjectJson && !isPackageJson) continue;\n\n const projectRoot = dirname(projectFile);\n\n // Skip root (workspace manifest, not a project)\n if (projectRoot === '.') continue;\n // The scoped root policy project declares check/ci itself. It has no product source to lint,\n // compile or test, so the ordinary per-project aggregate would recreate irrelevant fan-out.\n if (projectRoot === 'rules') continue;\n\n // Skip projects inside a nested git repo (vendored clones under repositories/): they are\n // separate repos and must not be swept into this workspace's `nx affected` graph.\n if (isInsideNestedGitRepo(context.workspaceRoot, projectRoot)) continue;\n\n // Skip if we've already processed this project root\n if (processedRoots.has(projectRoot)) continue;\n\n // For package.json, skip if project.json also exists in same directory\n // (prefer project.json - it will be processed separately)\n if (isPackageJson) {\n const projectJsonPath = join(context.workspaceRoot, projectRoot, 'project.json');\n if (existsSync(projectJsonPath)) continue;\n }\n\n processedRoots.add(projectRoot);\n\n const architectureEnabled =\n opts.workspace.enabled === true &&\n existsSync(join(context.workspaceRoot, 'architecture'));\n const targets = buildPerProjectTargets(\n isProjectJson,\n projectRoot,\n opts,\n architectureEnabled,\n isProjectJson\n ? new RawProjectJsonReader().read(context.workspaceRoot, projectFile, projectRoot)\n : undefined,\n );\n\n if (Object.keys(targets).length === 0) continue;\n\n const result: CreateNodesResult = {\n projects: {\n [projectRoot]: {\n targets,\n },\n },\n };\n\n results.push([projectFile, result] as const);\n }\n}\n\n/**\n * Build the target map for one project. Most targets are project.json-only\n * (package.json-only projects may not have TypeScript source); `ci` goes on all.\n */\n// webpieces-disable no-function-outside-class -- Nx requires its inference callback and target-map assembly at module scope; this existing functional plugin is invoked by Nx, not DI.\nfunction buildPerProjectTargets(\n isProjectJson: boolean,\n projectRoot: string,\n opts: Required<ArchitecturePluginOptions>,\n architectureEnabled: boolean,\n rawProject: RawProjectJson | undefined,\n): Record<string, TargetConfiguration> {\n const targets: Record<string, TargetConfiguration> = {};\n\n // Per-project validation gates that `ci` must depend on. Collected as they are added\n // so `ci` references only gates that actually exist on THIS project (a package.json-only\n // project has none).\n const validationTargets: string[] = [];\n\n // Add circular-deps target ONLY for project.json projects\n if (isProjectJson && opts.circularDeps.enabled) {\n if (!isExcluded(projectRoot, opts.circularDeps.excludePatterns!)) {\n const targetName = opts.circularDeps.targetName!;\n targets[targetName] = createCircularDepsTarget(projectRoot, targetName);\n validationTargets.push(targetName);\n }\n }\n\n // Per-project DI design DAG: regenerate design.json/design.md/design.html on every build.\n //\n // `di-graph-generate` is itself pushed onto validationTargets so `ci` still RUNS it — it used to ride\n // in only as the `dependsOn` of the deleted `validate-di-graph-unchanged` gate. There is no staleness\n // gate here any more: \"the regenerated design files are committed\" is now one repo-wide check in\n // `wp-review-upsert-pr` (see di-graph-targets.ts for why the per-project gate could not work).\n if (isProjectJson && opts.workspace.validations!.diGraph) {\n targets['di-graph-generate'] = createDiGraphGenerateTarget();\n validationTargets.push('di-graph-generate');\n }\n\n // API documents, opted into with a TAG (generate:openapi / generate:docs-site). An untagged project\n // costs this one in-memory tag check. They ride ci like every other build step — generation is\n // ordinary BUILD work, not a side channel (#1021).\n if (rawProject !== undefined) {\n const generated = new GenerateTargets(projectRoot, rawProject).infer();\n for (const [name, target] of Object.entries(generated)) {\n targets[name] = target;\n validationTargets.push(name);\n }\n }\n\n // Add ci target to ALL projects (both project.json and package.json). ci aggregates\n // lint + build + test + the validation gates that formerly rode on the compile\n // executor's targetDefaults, so a bare `build` stays a fast compile-only step.\n targets['ci'] = createCiTarget(validationTargets, architectureEnabled);\n targets['hotfix-ci'] = createHotfixCiTarget();\n\n return targets;\n}\n\n/**\n * Nx V2 Inference Plugin\n * Matches project.json and package.json files to create targets\n */\nexport const createNodesV2: CreateNodesV2<ArchitecturePluginOptions> = [\n // Pattern to match project.json and package.json files\n '**/{project,package}.json',\n\n // Inference function\n createNodesFunction,\n];\n\n/**\n * Build list of enabled validation target names for validate-complete dependency chain\n */\nfunction buildValidationTargetsList(\n validations: Required<ArchitecturePluginOptions>['workspace']['validations'],\n): string[] {\n const targets: string[] = [];\n if (validations!.noCycles) targets.push('validate-no-architecture-cycles');\n if (validations!.architectureUnchanged) targets.push('validate-architecture-unchanged');\n if (validations!.validatePackageJson) targets.push('validate-packagejson');\n // Use combined validate-code instead of 3 separate targets\n if (\n validations!.validateNewMethods ||\n validations!.validateModifiedMethods ||\n validations!.validateModifiedFiles\n ) {\n targets.push('validate-code');\n }\n if (validations!.validateVersionsLocked) targets.push('validate-versions-locked');\n if (validations!.validateTsInSrc) targets.push('validate-ts-in-src');\n if (validations!.validateNxWiring) targets.push('validate-nx-wiring');\n if (validations!.runtimeArchitecture) targets.push('validate-runtime-architecture');\n if (validations!.validateApiRelations) targets.push('validate-api-relations');\n if (validations!.validateApiLibTag) targets.push('validate-api-lib-tag');\n return targets;\n}\n\n/**\n * Create workspace-level architecture validation targets WITHOUT prefix\n * Used for virtual 'architecture' project\n */\nfunction createWorkspaceTargetsWithoutPrefix(\n opts: Required<ArchitecturePluginOptions>,\n): Record<string, TargetConfiguration> {\n const targets: Record<string, TargetConfiguration> = {};\n const graphPath = opts.workspace.graphPath!;\n const validations = opts.workspace.validations!;\n // One ValidationTargets instance, injected below to build each target config.\n const targetFactory = new ValidationTargets();\n\n // Add help target (always available)\n targets['help'] = createHelpTarget();\n\n if (opts.workspace.features!.generate) {\n targets['generate'] = createGenerateTarget(graphPath);\n }\n if (opts.workspace.features!.visualize) {\n targets['visualize'] = createVisualizeTargetWithoutPrefix(graphPath);\n }\n if (opts.workspace.features!.visualizeRuntime) {\n targets['visualize-runtime'] = createVisualizeRuntimeTarget();\n }\n if (validations.noCycles) {\n targets['validate-no-architecture-cycles'] = targetFactory.noCycles();\n }\n if (validations.architectureUnchanged) {\n targets['validate-architecture-unchanged'] = createValidateUnchangedTarget(graphPath);\n }\n if (validations.validatePackageJson) {\n targets['validate-packagejson'] = targetFactory.packageJson();\n }\n // Always available (cheap; success when a repo has no checklists). Kept out of the validate-complete /\n // ci aggregate so it does not change existing gate behavior — consumers point a required check at it.\n targets['validate-checklist-docs'] = targetFactory.checklistDocs();\n // Use combined validate-code instead of 3 separate targets\n // Options come from declared owner files' direct policy-ID maps, resolved by\n // @webpieces/rules-config from the root rulePacks declaration.\n if (\n validations.validateNewMethods ||\n validations.validateModifiedMethods ||\n validations.validateModifiedFiles\n ) {\n targets['validate-code'] = targetFactory.code();\n }\n if (validations.validateVersionsLocked) {\n targets['validate-versions-locked'] = targetFactory.versionsLocked();\n }\n if (validations.validateTsInSrc) {\n targets['validate-ts-in-src'] = targetFactory.tsInSrc();\n }\n if (validations.validateNxWiring) {\n targets['validate-nx-wiring'] = targetFactory.nxWiring();\n }\n if (validations.runtimeArchitecture) {\n targets['validate-runtime-architecture'] = createValidateRuntimeArchitectureTarget();\n }\n if (validations.validateApiRelations) {\n targets['validate-api-relations'] = targetFactory.apiRelations();\n }\n if (validations.validateApiLibTag) {\n targets['validate-api-lib-tag'] = targetFactory.apiLibTag();\n }\n\n // Add validate-complete target that runs all enabled validations\n const validationTargets = buildValidationTargetsList(validations);\n if (validationTargets.length > 0) {\n targets['validate-complete'] = createValidateCompleteTarget(validationTargets);\n }\n\n return targets;\n}\n\nfunction createGenerateTarget(graphPath: string): TargetConfiguration {\n return {\n executor: '@webpieces/nx-webpieces-rules:generate',\n cache: false,\n outputs: [\n '{workspaceRoot}/architecture/dependencies.json',\n '{workspaceRoot}/architecture/dependencies.html',\n '{workspaceRoot}/architecture/apis',\n '{workspaceRoot}/architecture/runtime-dependencies.json',\n ],\n options: { graphPath },\n metadata: {\n technologies: ['nx'],\n description:\n 'Generate the architecture dependency graph (+ clickable dependencies.html) and the runtime microservice graph',\n },\n };\n}\n\nfunction createVisualizeTargetWithoutPrefix(graphPath: string): TargetConfiguration {\n return {\n executor: '@webpieces/nx-webpieces-rules:visualize',\n cache: false,\n options: { graphPath },\n metadata: {\n technologies: ['nx'],\n description: 'View saved architecture without refreshing; refresh: pnpm nx run architecture:generate',\n },\n };\n}\n\nfunction createValidateUnchangedTarget(graphPath: string): TargetConfiguration {\n return {\n executor: '@webpieces/nx-webpieces-rules:validate-architecture-unchanged',\n cache: false,\n inputs: ['default', '{workspaceRoot}/architecture/dependencies.json'],\n options: { graphPath },\n metadata: {\n technologies: ['nx'],\n description: 'Validate the architecture matches the saved blessed graph',\n },\n };\n}\n\nfunction createValidateCompleteTarget(validationTargets: string[]): TargetConfiguration {\n return {\n executor: 'nx:noop',\n cache: true,\n dependsOn: validationTargets,\n metadata: {\n technologies: ['nx'],\n description:\n 'Run all architecture validations (cycles, unchanged, package.json, code rules)',\n },\n };\n}\n\n/**\n * Create per-project ci target - Gradle-style composite target\n * Composite CI target: runs lint, build, test, and every validation gate.\n *\n * Validation (architecture graph completeness, per-project file-import cycles, DI-graph\n * unchanged) lives HERE, not on the build/compile target. That keeps `nx build` a fast\n * compile-only step for local iteration while `nx ci` is the full gate the PR check runs.\n *\n * The per-project gates are passed in because they exist only on project.json projects;\n * `architecture:validate-complete` is a cross-project dep added only when the workspace\n * `architecture` project exists.\n *\n * NOTE: Type checking is done by the build target (@nx/js:tsc) during compilation.\n */\n// webpieces-disable no-function-outside-class -- Nx inference plugin: createNodes invokes these as module-scope target factories; the entire plugin is intentionally functional (matching the surrounding 18 factories), a DI class is not how the Nx plugin API is called.\nexport function createCiTarget(\n perProjectValidation: string[],\n architectureEnabled: boolean,\n): TargetConfiguration {\n const dependsOn: string[] = ['lint', 'build', 'test', ...perProjectValidation];\n if (architectureEnabled) {\n dependsOn.push('architecture:validate-complete');\n }\n return {\n executor: 'nx:noop',\n cache: true,\n // The branch is part of what `ci` asserts, because the rules it aggregates can be switched off by\n // turnOffRuleWhileOnBranch. Its own cache entry is a noop, but a `ci` hash that ignores the branch\n // is a green claim about a branch that was never checked. See branch-identity-inputs.ts.\n inputs: ['default', ...BRANCH_IDENTITY_INPUTS],\n dependsOn,\n metadata: {\n technologies: ['nx'],\n description:\n 'Run all CI checks: lint, build, test, and validation (Gradle-style composite target)',\n },\n };\n}\n\n/** Emergency profile: retain compilation/typechecking and tests, schedule no lint or policy target. */\n// webpieces-disable no-function-outside-class -- Nx inference target factory, matching createCiTarget and invoked by the module-scope plugin callback.\nexport function createHotfixCiTarget(): TargetConfiguration {\n return {\n executor: 'nx:noop',\n cache: true,\n inputs: ['default', ...BRANCH_IDENTITY_INPUTS],\n dependsOn: ['build', 'test'],\n metadata: {\n technologies: ['nx'],\n description:\n 'Hotfix CI: compilation/typechecking and tests only; lint and Webpieces validators bypassed',\n },\n };\n}\n\nfunction createHelpTarget(): TargetConfiguration {\n return {\n executor: '@webpieces/nx-webpieces-rules:help',\n cache: false, // Never cache - always show help output\n metadata: {\n technologies: ['nx'],\n description: 'Display help for @webpieces/nx-webpieces-rules commands and targets',\n },\n };\n}\n\n/**\n * Create per-project circular dependency checking target.\n *\n * Uses the `validate-no-file-import-cycles` executor (which bundles madge as a\n * dependency) rather than a runtime `npx madge` fetch. The executor reads\n * the declared Nx owner file's direct policy-ID map to turn the gate on/off (`mode`) and\n * time-boxed (`turnOffRuleUntilEpoch`) like every other webpieces rule.\n *\n * Note `projectRoot` is intentionally unused now — the executor derives the\n * project root from the Nx context — but the param is kept for call-site\n * symmetry with the rest of the per-project target factories.\n */\nfunction createCircularDepsTarget(_projectRoot: string, _targetName: string): TargetConfiguration {\n return {\n executor: '@webpieces/nx-webpieces-rules:validate-no-file-import-cycles',\n cache: true,\n // BRANCH_IDENTITY_INPUTS: this gate honors turnOffRuleWhileOnBranch, and it is CACHED, so without\n // the branch in its hash a hatched green replays onto branches the hatch never covered.\n inputs: ['default', ...BRANCH_IDENTITY_INPUTS],\n outputs: [] as string[],\n metadata: {\n technologies: ['madge'],\n description: 'Check for circular file-import dependencies using madge',\n },\n };\n}\n\n/**\n * Check if a project should be excluded based on patterns\n */\nfunction isExcluded(projectRoot: string, excludePatterns: string[]): boolean {\n if (excludePatterns.length === 0) {\n return false;\n }\n\n // Simple glob matching (could be enhanced with minimatch if needed)\n return excludePatterns.some((pattern: string) => {\n // Convert glob pattern to regex\n const regexPattern = pattern\n .replace(/\\*\\*/g, '.*') // ** matches any path\n .replace(/\\*/g, '[^/]*'); // * matches any string except /\n\n const regex = new RegExp(`^${regexPattern}$`);\n return regex.test(projectRoot);\n });\n}\n\n/**\n * Export plugin as default for Nx\n */\nexport default { createNodesV2 };\n"]}
|
|
1
|
+
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../../../../packages/tooling/nx-webpieces-rules/src/plugin.ts"],"names":[],"mappings":"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","sourcesContent":["import { RuntimeWiringTargets } from './runtime-wiring-targets';\n/**\n * Unified Nx Inference Plugin for @webpieces/nx-webpieces-rules\n *\n * This plugin automatically creates targets for:\n * 1. Workspace-level architecture validation (generate, visualize, validate-*)\n * 2. Per-project circular dependency checking\n * 3. Per-project API documents, opted into with a TAG: `generate:openapi` infers `openapi-generate`,\n * `generate:openapi-components` infers `openapi-components-generate` (a DTO library's\n * components.openapi.json), `generate:docs-site` infers `openapi-generate` + `docs-generate`\n * (see generate-targets.ts)\n *\n * Install with: nx add @webpieces/nx-webpieces-rules\n *\n * Usage:\n * Add to nx.json plugins array:\n * {\n * \"plugins\": [\"@webpieces/nx-webpieces-rules\"]\n * }\n *\n * Then all targets appear automatically without manual project.json configuration.\n */\n\nimport { dirname, join } from 'path';\nimport { existsSync } from 'fs';\nimport type {\n CreateNodesV2,\n CreateNodesContextV2,\n CreateNodesResultV2,\n CreateNodesResult,\n TargetConfiguration,\n} from '@nx/devkit';\nimport {\n createVisualizeRuntimeTarget,\n createValidateRuntimeArchitectureTarget,\n} from './runtime-targets';\nimport { BRANCH_IDENTITY_INPUTS } from './branch-identity-inputs';\nimport { ValidationTargets } from './validation-targets';\nimport { createDiGraphGenerateTarget } from './di-graph-targets';\nimport { GenerateTargets, RawProjectJson, RawProjectJsonReader } from './generate-targets';\nimport { RulesTarget } from './rules-target';\n\n/**\n * Circular dependency checking options\n */\nexport interface CircularDepsOptions {\n enabled?: boolean;\n targetName?: string;\n excludePatterns?: string[];\n}\n\n/**\n * Validation options for architecture checks\n */\nexport interface ValidationOptions {\n noCycles?: boolean;\n architectureUnchanged?: boolean;\n validatePackageJson?: boolean;\n validateNewMethods?: boolean;\n validateModifiedMethods?: boolean;\n validateModifiedFiles?: boolean;\n validateVersionsLocked?: boolean;\n validateTsInSrc?: boolean;\n validateNxWiring?: boolean;\n runtimeArchitecture?: boolean;\n validateApiRelations?: boolean;\n validateApiLibTag?: boolean;\n diGraph?: boolean;\n newMethodsMaxLines?: number;\n modifiedAndNewMethodsMaxLines?: number;\n modifiedFilesMaxLines?: number;\n /**\n * Validation mode for method/file size limits:\n * - STRICT: All limits enforced, disable comments ignored\n * - NORMAL: Limits enforced, disable comments with dates work\n * - OFF: Skip size validations entirely (for fast iteration)\n */\n validationMode?: 'STRICT' | 'NORMAL' | 'OFF';\n}\n\n/**\n * Feature flags for workspace targets\n */\nexport interface FeatureOptions {\n generate?: boolean;\n visualize?: boolean;\n visualizeRuntime?: boolean;\n}\n\n/**\n * Workspace-level configuration options\n */\nexport interface WorkspaceOptions {\n enabled?: boolean;\n targetPrefix?: string;\n graphPath?: string;\n validations?: ValidationOptions;\n features?: FeatureOptions;\n}\n\n/**\n * Configuration for @webpieces/nx-webpieces-rules Nx plugin\n */\nexport interface ArchitecturePluginOptions {\n circularDeps?: CircularDepsOptions;\n workspace?: WorkspaceOptions;\n}\n\nconst DEFAULT_OPTIONS: Required<ArchitecturePluginOptions> = {\n circularDeps: {\n enabled: true,\n targetName: 'validate-no-file-import-cycles',\n excludePatterns: [],\n },\n workspace: {\n enabled: true,\n targetPrefix: 'arch:',\n graphPath: 'architecture/dependencies.json',\n validations: {\n noCycles: true,\n architectureUnchanged: true,\n validatePackageJson: true,\n validateNewMethods: true,\n validateModifiedMethods: true,\n validateModifiedFiles: true,\n validateVersionsLocked: true,\n validateTsInSrc: true,\n validateNxWiring: true,\n runtimeArchitecture: true,\n validateApiRelations: true,\n validateApiLibTag: true,\n diGraph: true,\n newMethodsMaxLines: 30,\n modifiedAndNewMethodsMaxLines: 80,\n modifiedFilesMaxLines: 900,\n validationMode: 'NORMAL',\n },\n features: {\n generate: true,\n visualize: true,\n visualizeRuntime: true,\n },\n },\n};\n\nfunction normalizeOptions(\n options: ArchitecturePluginOptions | undefined,\n): Required<ArchitecturePluginOptions> {\n const circularDeps = {\n ...DEFAULT_OPTIONS.circularDeps,\n ...options?.circularDeps,\n };\n\n const workspace = {\n ...DEFAULT_OPTIONS.workspace,\n ...options?.workspace,\n validations: {\n ...DEFAULT_OPTIONS.workspace.validations,\n ...options?.workspace?.validations,\n },\n features: {\n ...DEFAULT_OPTIONS.workspace.features,\n ...options?.workspace?.features,\n },\n };\n\n return {\n circularDeps,\n workspace,\n } as Required<ArchitecturePluginOptions>;\n}\n\nasync function createNodesFunction(\n projectFiles: readonly string[],\n options: ArchitecturePluginOptions | undefined,\n context: CreateNodesContextV2,\n): Promise<CreateNodesResultV2> {\n const opts = normalizeOptions(options);\n const results: CreateNodesResultV2 = [];\n\n // Add workspace-level architecture targets\n addArchitectureProject(results, projectFiles, opts, context);\n\n // One root policy target. webpieces.config.json is not a shared input of every product project;\n // this virtual project is its sole Nx owner and the gate runs it before affected CI.\n // Add per-project targets (circular-deps, ci, di-graph)\n addPerProjectTargets(results, projectFiles, opts, context);\n\n // Append the virtual root project after concrete projects so callers that select the first result\n // for a project.json still receive that project's inferred targets.\n new RulesTarget().add(results, projectFiles);\n\n return results;\n}\n\nfunction addArchitectureProject(\n results: CreateNodesResultV2,\n projectFiles: readonly string[],\n opts: Required<ArchitecturePluginOptions>,\n context: CreateNodesContextV2,\n): void {\n if (!opts.workspace.enabled) return;\n\n const archDirPath = join(context.workspaceRoot, 'architecture');\n if (!existsSync(archDirPath)) return;\n\n const workspaceTargets = createWorkspaceTargetsWithoutPrefix(opts);\n if (Object.keys(workspaceTargets).length === 0) return;\n\n const result: CreateNodesResult = {\n projects: {\n architecture: {\n name: 'architecture',\n root: 'architecture',\n targets: workspaceTargets,\n },\n },\n };\n\n const firstProjectFile = projectFiles[0];\n if (firstProjectFile) {\n results.push([firstProjectFile, result] as const);\n }\n}\n\n// A project sits inside a NESTED git repo (e.g. a clone under repositories/) when any of its\n// ancestor dirs — up to but NOT including the workspace root — contains a `.git`. Such projects are\n// separate repos, not part of THIS workspace's graph, so they must not get inferred targets (that is\n// what drags foreign clones into `nx affected`). Same repo-boundary signal the AI guards use.\nexport function isInsideNestedGitRepo(workspaceRoot: string, projectRoot: string): boolean {\n let dir = projectRoot;\n while (dir && dir !== '.' && dir !== '/') {\n if (existsSync(join(workspaceRoot, dir, '.git'))) return true;\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n return false;\n}\n\nfunction addPerProjectTargets(\n results: CreateNodesResultV2,\n projectFiles: readonly string[],\n opts: Required<ArchitecturePluginOptions>,\n context: CreateNodesContextV2,\n): void {\n // Track processed project roots to avoid duplicates when both files exist\n const processedRoots = new Set<string>();\n\n for (const projectFile of projectFiles) {\n const isProjectJson = projectFile.endsWith('project.json');\n const isPackageJson = projectFile.endsWith('package.json');\n\n if (!isProjectJson && !isPackageJson) continue;\n\n const projectRoot = dirname(projectFile);\n\n // Skip root (workspace manifest, not a project)\n if (projectRoot === '.') continue;\n // The scoped root policy project declares check/ci itself. It has no product source to lint,\n // compile or test, so the ordinary per-project aggregate would recreate irrelevant fan-out.\n if (projectRoot === 'rules') continue;\n\n // Skip projects inside a nested git repo (vendored clones under repositories/): they are\n // separate repos and must not be swept into this workspace's `nx affected` graph.\n if (isInsideNestedGitRepo(context.workspaceRoot, projectRoot)) continue;\n\n // Skip if we've already processed this project root\n if (processedRoots.has(projectRoot)) continue;\n\n // For package.json, skip if project.json also exists in same directory\n // (prefer project.json - it will be processed separately)\n if (isPackageJson) {\n const projectJsonPath = join(context.workspaceRoot, projectRoot, 'project.json');\n if (existsSync(projectJsonPath)) continue;\n }\n\n processedRoots.add(projectRoot);\n\n const architectureEnabled =\n opts.workspace.enabled === true &&\n existsSync(join(context.workspaceRoot, 'architecture'));\n const targets = buildPerProjectTargets(\n isProjectJson,\n projectRoot,\n opts,\n architectureEnabled,\n isProjectJson\n ? new RawProjectJsonReader().read(context.workspaceRoot, projectFile, projectRoot)\n : undefined,\n );\n\n if (Object.keys(targets).length === 0) continue;\n\n const result: CreateNodesResult = {\n projects: {\n [projectRoot]: {\n targets,\n },\n },\n };\n\n results.push([projectFile, result] as const);\n }\n}\n\n/**\n * Build the target map for one project. Most targets are project.json-only\n * (package.json-only projects may not have TypeScript source); `ci` goes on all.\n */\n// webpieces-disable no-function-outside-class -- Nx requires its inference callback and target-map assembly at module scope; this existing functional plugin is invoked by Nx, not DI.\nfunction buildPerProjectTargets(\n isProjectJson: boolean,\n projectRoot: string,\n opts: Required<ArchitecturePluginOptions>,\n architectureEnabled: boolean,\n rawProject: RawProjectJson | undefined,\n): Record<string, TargetConfiguration> {\n const targets: Record<string, TargetConfiguration> = {};\n\n // Per-project validation gates that `ci` must depend on. Collected as they are added\n // so `ci` references only gates that actually exist on THIS project (a package.json-only\n // project has none).\n const validationTargets: string[] = [];\n\n // Add circular-deps target ONLY for project.json projects\n if (isProjectJson && opts.circularDeps.enabled) {\n if (!isExcluded(projectRoot, opts.circularDeps.excludePatterns!)) {\n const targetName = opts.circularDeps.targetName!;\n targets[targetName] = createCircularDepsTarget(projectRoot, targetName);\n validationTargets.push(targetName);\n }\n }\n\n // Per-project DI design DAG: regenerate design.json/design.md/design.html on every build.\n //\n // `di-graph-generate` is itself pushed onto validationTargets so `ci` still RUNS it — it used to ride\n // in only as the `dependsOn` of the deleted `validate-di-graph-unchanged` gate. There is no staleness\n // gate here any more: \"the regenerated design files are committed\" is now one repo-wide check in\n // `wp-review-upsert-pr` (see di-graph-targets.ts for why the per-project gate could not work).\n if (isProjectJson && opts.workspace.validations!.diGraph) {\n targets['di-graph-generate'] = createDiGraphGenerateTarget();\n validationTargets.push('di-graph-generate');\n }\n\n // API documents, opted into with a TAG (generate:openapi / generate:docs-site). An untagged project\n // costs this one in-memory tag check. They ride ci like every other build step — generation is\n // ordinary BUILD work, not a side channel (#1021).\n if (rawProject !== undefined) {\n const generated = {\n ...new GenerateTargets(projectRoot, rawProject).infer(),\n ...new RuntimeWiringTargets().infer(rawProject),\n };\n for (const [name, target] of Object.entries(generated)) {\n targets[name] = target;\n if (name !== 'build') validationTargets.push(name);\n }\n }\n\n // Add ci target to ALL projects (both project.json and package.json). ci aggregates\n // lint + build + test + the validation gates that formerly rode on the compile\n // executor's targetDefaults, so a bare `build` stays a fast compile-only step.\n targets['ci'] = createCiTarget(validationTargets, architectureEnabled);\n targets['hotfix-ci'] = createHotfixCiTarget();\n\n return targets;\n}\n\n/**\n * Nx V2 Inference Plugin\n * Matches project.json and package.json files to create targets\n */\nexport const createNodesV2: CreateNodesV2<ArchitecturePluginOptions> = [\n // Pattern to match project.json and package.json files\n '**/{project,package}.json',\n\n // Inference function\n createNodesFunction,\n];\n\n/**\n * Build list of enabled validation target names for validate-complete dependency chain\n */\nfunction buildValidationTargetsList(\n validations: Required<ArchitecturePluginOptions>['workspace']['validations'],\n): string[] {\n const targets: string[] = [];\n if (validations!.noCycles) targets.push('validate-no-architecture-cycles');\n if (validations!.architectureUnchanged) targets.push('validate-architecture-unchanged');\n if (validations!.validatePackageJson) targets.push('validate-packagejson');\n // Use combined validate-code instead of 3 separate targets\n if (\n validations!.validateNewMethods ||\n validations!.validateModifiedMethods ||\n validations!.validateModifiedFiles\n ) {\n targets.push('validate-code');\n }\n if (validations!.validateVersionsLocked) targets.push('validate-versions-locked');\n if (validations!.validateTsInSrc) targets.push('validate-ts-in-src');\n if (validations!.validateNxWiring) targets.push('validate-nx-wiring');\n if (validations!.runtimeArchitecture) targets.push('validate-runtime-architecture');\n if (validations!.validateApiRelations) targets.push('validate-api-relations');\n if (validations!.validateApiLibTag) targets.push('validate-api-lib-tag');\n return targets;\n}\n\n/**\n * Create workspace-level architecture validation targets WITHOUT prefix\n * Used for virtual 'architecture' project\n */\nfunction createWorkspaceTargetsWithoutPrefix(\n opts: Required<ArchitecturePluginOptions>,\n): Record<string, TargetConfiguration> {\n const targets: Record<string, TargetConfiguration> = {};\n const graphPath = opts.workspace.graphPath!;\n const validations = opts.workspace.validations!;\n // One ValidationTargets instance, injected below to build each target config.\n const targetFactory = new ValidationTargets();\n\n // Add help target (always available)\n targets['help'] = createHelpTarget();\n\n if (opts.workspace.features!.generate) {\n targets['generate'] = createGenerateTarget(graphPath);\n }\n if (opts.workspace.features!.visualize) {\n targets['visualize'] = createVisualizeTargetWithoutPrefix(graphPath);\n }\n if (opts.workspace.features!.visualizeRuntime) {\n targets['visualize-runtime'] = createVisualizeRuntimeTarget();\n }\n if (validations.noCycles) {\n targets['validate-no-architecture-cycles'] = targetFactory.noCycles();\n }\n if (validations.architectureUnchanged) {\n targets['validate-architecture-unchanged'] = createValidateUnchangedTarget(graphPath);\n }\n if (validations.validatePackageJson) {\n targets['validate-packagejson'] = targetFactory.packageJson();\n }\n // Always available (cheap; success when a repo has no checklists). Kept out of the validate-complete /\n // ci aggregate so it does not change existing gate behavior — consumers point a required check at it.\n targets['validate-checklist-docs'] = targetFactory.checklistDocs();\n // Use combined validate-code instead of 3 separate targets\n // Options come from declared owner files' direct policy-ID maps, resolved by\n // @webpieces/rules-config from the root rulePacks declaration.\n if (\n validations.validateNewMethods ||\n validations.validateModifiedMethods ||\n validations.validateModifiedFiles\n ) {\n targets['validate-code'] = targetFactory.code();\n }\n if (validations.validateVersionsLocked) {\n targets['validate-versions-locked'] = targetFactory.versionsLocked();\n }\n if (validations.validateTsInSrc) {\n targets['validate-ts-in-src'] = targetFactory.tsInSrc();\n }\n if (validations.validateNxWiring) {\n targets['validate-nx-wiring'] = targetFactory.nxWiring();\n }\n if (validations.runtimeArchitecture) {\n targets['validate-runtime-architecture'] = createValidateRuntimeArchitectureTarget();\n }\n if (validations.validateApiRelations) {\n targets['validate-api-relations'] = targetFactory.apiRelations();\n }\n if (validations.validateApiLibTag) {\n targets['validate-api-lib-tag'] = targetFactory.apiLibTag();\n }\n\n // Add validate-complete target that runs all enabled validations\n const validationTargets = buildValidationTargetsList(validations);\n if (validationTargets.length > 0) {\n targets['validate-complete'] = createValidateCompleteTarget(validationTargets);\n }\n\n return targets;\n}\n\nfunction createGenerateTarget(graphPath: string): TargetConfiguration {\n return {\n executor: '@webpieces/nx-webpieces-rules:generate',\n cache: false,\n outputs: [\n '{workspaceRoot}/architecture/dependencies.json',\n '{workspaceRoot}/architecture/dependencies.html',\n '{workspaceRoot}/architecture/apis',\n '{workspaceRoot}/architecture/runtime-dependencies.json',\n ],\n options: { graphPath },\n metadata: {\n technologies: ['nx'],\n description:\n 'Generate the architecture dependency graph (+ clickable dependencies.html) and the runtime microservice graph',\n },\n };\n}\n\nfunction createVisualizeTargetWithoutPrefix(graphPath: string): TargetConfiguration {\n return {\n executor: '@webpieces/nx-webpieces-rules:visualize',\n cache: false,\n options: { graphPath },\n metadata: {\n technologies: ['nx'],\n description:\n 'View saved architecture without refreshing; refresh: pnpm nx run architecture:generate',\n },\n };\n}\n\nfunction createValidateUnchangedTarget(graphPath: string): TargetConfiguration {\n return {\n executor: '@webpieces/nx-webpieces-rules:validate-architecture-unchanged',\n cache: false,\n inputs: ['default', '{workspaceRoot}/architecture/dependencies.json'],\n options: { graphPath },\n metadata: {\n technologies: ['nx'],\n description: 'Validate the architecture matches the saved blessed graph',\n },\n };\n}\n\nfunction createValidateCompleteTarget(validationTargets: string[]): TargetConfiguration {\n return {\n executor: 'nx:noop',\n cache: true,\n dependsOn: validationTargets,\n metadata: {\n technologies: ['nx'],\n description:\n 'Run all architecture validations (cycles, unchanged, package.json, code rules)',\n },\n };\n}\n\n/**\n * Create per-project ci target - Gradle-style composite target\n * Composite CI target: runs lint, build, test, and every validation gate.\n *\n * Validation (architecture graph completeness, per-project file-import cycles, DI-graph\n * unchanged) lives HERE, not on the build/compile target. That keeps `nx build` a fast\n * compile-only step for local iteration while `nx ci` is the full gate the PR check runs.\n *\n * The per-project gates are passed in because they exist only on project.json projects;\n * `architecture:validate-complete` is a cross-project dep added only when the workspace\n * `architecture` project exists.\n *\n * NOTE: Type checking is done by the build target (@nx/js:tsc) during compilation.\n */\n// webpieces-disable no-function-outside-class -- Nx inference plugin: createNodes invokes these as module-scope target factories; the entire plugin is intentionally functional (matching the surrounding 18 factories), a DI class is not how the Nx plugin API is called.\nexport function createCiTarget(\n perProjectValidation: string[],\n architectureEnabled: boolean,\n): TargetConfiguration {\n const dependsOn: string[] = ['lint', 'build', 'test', ...perProjectValidation];\n if (architectureEnabled) {\n dependsOn.push('architecture:validate-complete');\n }\n return {\n executor: 'nx:noop',\n cache: true,\n // The branch is part of what `ci` asserts, because the rules it aggregates can be switched off by\n // turnOffRuleWhileOnBranch. Its own cache entry is a noop, but a `ci` hash that ignores the branch\n // is a green claim about a branch that was never checked. See branch-identity-inputs.ts.\n inputs: ['default', ...BRANCH_IDENTITY_INPUTS],\n dependsOn,\n metadata: {\n technologies: ['nx'],\n description:\n 'Run all CI checks: lint, build, test, and validation (Gradle-style composite target)',\n },\n };\n}\n\n/** Emergency profile: retain compilation/typechecking and tests, schedule no lint or policy target. */\n// webpieces-disable no-function-outside-class -- Nx inference target factory, matching createCiTarget and invoked by the module-scope plugin callback.\nexport function createHotfixCiTarget(): TargetConfiguration {\n return {\n executor: 'nx:noop',\n cache: true,\n inputs: ['default', ...BRANCH_IDENTITY_INPUTS],\n dependsOn: ['build', 'test'],\n metadata: {\n technologies: ['nx'],\n description:\n 'Hotfix CI: compilation/typechecking and tests only; lint and Webpieces validators bypassed',\n },\n };\n}\n\nfunction createHelpTarget(): TargetConfiguration {\n return {\n executor: '@webpieces/nx-webpieces-rules:help',\n cache: false, // Never cache - always show help output\n metadata: {\n technologies: ['nx'],\n description: 'Display help for @webpieces/nx-webpieces-rules commands and targets',\n },\n };\n}\n\n/**\n * Create per-project circular dependency checking target.\n *\n * Uses the `validate-no-file-import-cycles` executor (which bundles madge as a\n * dependency) rather than a runtime `npx madge` fetch. The executor reads\n * the declared Nx owner file's direct policy-ID map to turn the gate on/off (`mode`) and\n * time-boxed (`turnOffRuleUntilEpoch`) like every other webpieces rule.\n *\n * Note `projectRoot` is intentionally unused now — the executor derives the\n * project root from the Nx context — but the param is kept for call-site\n * symmetry with the rest of the per-project target factories.\n */\nfunction createCircularDepsTarget(_projectRoot: string, _targetName: string): TargetConfiguration {\n return {\n executor: '@webpieces/nx-webpieces-rules:validate-no-file-import-cycles',\n cache: true,\n // BRANCH_IDENTITY_INPUTS: this gate honors turnOffRuleWhileOnBranch, and it is CACHED, so without\n // the branch in its hash a hatched green replays onto branches the hatch never covered.\n inputs: ['default', ...BRANCH_IDENTITY_INPUTS],\n outputs: [] as string[],\n metadata: {\n technologies: ['madge'],\n description: 'Check for circular file-import dependencies using madge',\n },\n };\n}\n\n/**\n * Check if a project should be excluded based on patterns\n */\nfunction isExcluded(projectRoot: string, excludePatterns: string[]): boolean {\n if (excludePatterns.length === 0) {\n return false;\n }\n\n // Simple glob matching (could be enhanced with minimatch if needed)\n return excludePatterns.some((pattern: string) => {\n // Convert glob pattern to regex\n const regexPattern = pattern\n .replace(/\\*\\*/g, '.*') // ** matches any path\n .replace(/\\*/g, '[^/]*'); // * matches any string except /\n\n const regex = new RegExp(`^${regexPattern}$`);\n return regex.test(projectRoot);\n });\n}\n\n/**\n * Export plugin as default for Nx\n */\nexport default { createNodesV2 };\n"]}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { TargetConfiguration } from '@nx/devkit';
|
|
2
|
+
import type { RawProjectJson } from './generate-targets';
|
|
3
|
+
/** Opt-in ownership tags are the migration boundary; no broad source enforcement activates silently. */
|
|
4
|
+
export declare class RuntimeWiringTargets {
|
|
5
|
+
infer(project: RawProjectJson): Record<string, TargetConfiguration>;
|
|
6
|
+
private buildDependencies;
|
|
7
|
+
}
|