@webpieces/nx-webpieces-rules 0.4.869 → 0.4.870
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/package.json +7 -7
- package/src/lib/di-graph/runtime-client-bindings.d.ts +13 -3
- package/src/lib/di-graph/runtime-client-bindings.js +53 -25
- package/src/lib/di-graph/runtime-client-bindings.js.map +1 -1
- package/src/lib/di-graph/token-resolver.js +0 -14
- package/src/lib/di-graph/token-resolver.js.map +1 -1
- package/src/lib/runtime-wiring/assembler.js +3 -3
- package/src/lib/runtime-wiring/assembler.js.map +1 -1
- package/src/lib/runtime-wiring/canonical-clients.d.ts +2 -0
- package/src/lib/runtime-wiring/canonical-clients.js +12 -6
- package/src/lib/runtime-wiring/canonical-clients.js.map +1 -1
- package/src/lib/runtime-wiring/codec.d.ts +1 -0
- package/src/lib/runtime-wiring/codec.js +10 -3
- package/src/lib/runtime-wiring/codec.js.map +1 -1
- package/src/lib/runtime-wiring/declaration.d.ts +3 -3
- package/src/lib/runtime-wiring/declaration.js +5 -5
- package/src/lib/runtime-wiring/declaration.js.map +1 -1
- package/src/lib/runtime-wiring/prepared-targets.js +4 -4
- package/src/lib/runtime-wiring/prepared-targets.js.map +1 -1
- package/src/lib/runtime-wiring/source-extractor.d.ts +14 -3
- package/src/lib/runtime-wiring/source-extractor.js +52 -41
- package/src/lib/runtime-wiring/source-extractor.js.map +1 -1
- package/src/lib/runtime-wiring/source-types.js +1 -1
- package/src/lib/runtime-wiring/source-types.js.map +1 -1
- package/src/lib/runtime-wiring/wiring-format.d.ts +9 -7
- package/src/lib/runtime-wiring/wiring-format.js +52 -56
- package/src/lib/runtime-wiring/wiring-format.js.map +1 -1
- package/src/rule-help.js +2 -2
- package/src/rule-help.js.map +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webpieces/nx-webpieces-rules",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.870",
|
|
4
4
|
"description": "Nx-specific webpieces validation rules, graph tooling, executors, and inference plugin.",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"main": "./src/index.js",
|
|
@@ -20,12 +20,12 @@
|
|
|
20
20
|
"README.md"
|
|
21
21
|
],
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@webpieces/api-doc-model": "0.4.
|
|
24
|
-
"@webpieces/core-util": "0.4.
|
|
25
|
-
"@webpieces/eslint-rules": "0.4.
|
|
26
|
-
"@webpieces/rules-config": "0.4.
|
|
23
|
+
"@webpieces/api-doc-model": "0.4.870",
|
|
24
|
+
"@webpieces/core-util": "0.4.870",
|
|
25
|
+
"@webpieces/eslint-rules": "0.4.870",
|
|
26
|
+
"@webpieces/rules-config": "0.4.870",
|
|
27
27
|
"madge": "8.0.0",
|
|
28
|
-
"@webpieces/rules-sdk": "0.4.
|
|
28
|
+
"@webpieces/rules-sdk": "0.4.870"
|
|
29
29
|
},
|
|
30
30
|
"peerDependencies": {
|
|
31
31
|
"@nx/devkit": ">=18.0.0"
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"access": "public"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
|
-
"@webpieces/tooling-testkit": "0.4.
|
|
44
|
+
"@webpieces/tooling-testkit": "0.4.870"
|
|
45
45
|
},
|
|
46
46
|
"types": "./src/index.d.ts",
|
|
47
47
|
"bin": {
|
|
@@ -1,9 +1,19 @@
|
|
|
1
1
|
import * as ts from 'typescript';
|
|
2
2
|
import { Binding } from './model';
|
|
3
|
-
/**
|
|
3
|
+
/**
|
|
4
|
+
* The host binder's client registrations retain the same DI token and singleton boundary as a
|
|
5
|
+
* hand-written lazy factory: `binder.createRpcClientAndBind(Api, deployment, options?)` and
|
|
6
|
+
* `binder.createPubSubClientAndBind(...)` bind `options.token` when given, else the API class itself.
|
|
7
|
+
* `binder.bindExternal(Api, VendorImpl)` binds the vendor class to its external contract.
|
|
8
|
+
*/
|
|
4
9
|
export declare class RuntimeClientBindings {
|
|
5
10
|
collectNode(call: ts.CallExpression, checker: ts.TypeChecker, root: string): Binding | undefined;
|
|
6
11
|
collectBrowser(call: ts.CallExpression, checker: ts.TypeChecker, root: string): Binding | undefined;
|
|
7
|
-
|
|
8
|
-
private
|
|
12
|
+
/** The method name when `call` resolves to the host Binder declared in `pkg`; otherwise undefined. */
|
|
13
|
+
private binderMethod;
|
|
14
|
+
private client;
|
|
15
|
+
private external;
|
|
16
|
+
private implementation;
|
|
17
|
+
/** `new ClientBindOptions(token, ...)` names an extra token; omitted, the API class is the token. */
|
|
18
|
+
private tokenExpression;
|
|
9
19
|
}
|
|
@@ -5,44 +5,72 @@ const tslib_1 = require("tslib");
|
|
|
5
5
|
const ts = tslib_1.__importStar(require("typescript"));
|
|
6
6
|
const model_1 = require("./model");
|
|
7
7
|
const token_resolver_1 = require("./token-resolver");
|
|
8
|
-
/**
|
|
8
|
+
/**
|
|
9
|
+
* The host binder's client registrations retain the same DI token and singleton boundary as a
|
|
10
|
+
* hand-written lazy factory: `binder.createRpcClientAndBind(Api, deployment, options?)` and
|
|
11
|
+
* `binder.createPubSubClientAndBind(...)` bind `options.token` when given, else the API class itself.
|
|
12
|
+
* `binder.bindExternal(Api, VendorImpl)` binds the vendor class to its external contract.
|
|
13
|
+
*/
|
|
9
14
|
class RuntimeClientBindings {
|
|
10
15
|
collectNode(call, checker, root) {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
if (
|
|
15
|
-
return;
|
|
16
|
-
const owner = checker.getTypeAtLocation(callee.expression).getSymbol()?.getName();
|
|
17
|
-
if ((callee.name.text === 'bindRpc' && owner === 'RuntimeClients') ||
|
|
18
|
-
(callee.name.text === 'bindPubSub' && owner === 'RuntimeTaskClients')) {
|
|
19
|
-
return this.binding(call, checker, root);
|
|
20
|
-
}
|
|
16
|
+
const method = this.binderMethod(call, checker, 'http-routing');
|
|
17
|
+
if (method === 'createRpcClientAndBind' || method === 'createPubSubClientAndBind')
|
|
18
|
+
return this.client(call, checker, root);
|
|
19
|
+
if (method === 'bindExternal')
|
|
20
|
+
return this.external(call, checker, root);
|
|
21
21
|
return undefined;
|
|
22
22
|
}
|
|
23
23
|
collectBrowser(call, checker, root) {
|
|
24
|
-
if (
|
|
24
|
+
if (this.binderMethod(call, checker, 'http-client-browser') !== 'createRpcClientAndBind')
|
|
25
25
|
return;
|
|
26
|
-
|
|
27
|
-
if (symbol && (symbol.flags & ts.SymbolFlags.Alias) !== 0)
|
|
28
|
-
symbol = checker.getAliasedSymbol(symbol);
|
|
29
|
-
if (symbol?.getName() !== 'provideRpcClient' ||
|
|
30
|
-
checker.getTypeAtLocation(call).getSymbol()?.getName() !== 'RpcClientProvider')
|
|
31
|
-
return;
|
|
32
|
-
return this.binding(call, checker, root);
|
|
26
|
+
return this.client(call, checker, root);
|
|
33
27
|
}
|
|
34
|
-
|
|
28
|
+
/** The method name when `call` resolves to the host Binder declared in `pkg`; otherwise undefined. */
|
|
29
|
+
binderMethod(call, checker, pkg) {
|
|
30
|
+
if (!ts.isPropertyAccessExpression(call.expression))
|
|
31
|
+
return undefined;
|
|
35
32
|
const declaration = checker.getResolvedSignature(call)?.declaration;
|
|
36
33
|
if (declaration === undefined)
|
|
37
|
-
return
|
|
38
|
-
|
|
34
|
+
return undefined;
|
|
35
|
+
const file = declaration.getSourceFile().fileName.replace(/\\/g, '/');
|
|
36
|
+
if (!new RegExp(`(?:/packages/http/|/node_modules/@webpieces/)${pkg}/`).test(file))
|
|
37
|
+
return undefined;
|
|
38
|
+
const owner = declaration.parent;
|
|
39
|
+
const ownerName = owner !== undefined && (ts.isClassDeclaration(owner) || ts.isInterfaceDeclaration(owner))
|
|
40
|
+
? owner.name?.text
|
|
41
|
+
: undefined;
|
|
42
|
+
return ownerName === 'Binder' ? call.expression.name.text : undefined;
|
|
39
43
|
}
|
|
40
|
-
|
|
41
|
-
if (call.arguments.length <
|
|
44
|
+
client(call, checker, root) {
|
|
45
|
+
if (call.arguments.length < 2)
|
|
42
46
|
return;
|
|
43
|
-
const token = (0, token_resolver_1.resolveTokenKey)(call
|
|
47
|
+
const token = (0, token_resolver_1.resolveTokenKey)(this.tokenExpression(call), checker, root);
|
|
44
48
|
return new model_1.Binding(token.key, token.display, 'toDynamicValue', 'singleton', null, call.expression.getText(), (0, token_resolver_1.relativeFile)(root, call.getSourceFile()), [], true);
|
|
45
49
|
}
|
|
50
|
+
external(call, checker, root) {
|
|
51
|
+
const api = call.arguments[0];
|
|
52
|
+
const impl = call.arguments[1];
|
|
53
|
+
if (api === undefined || impl === undefined)
|
|
54
|
+
return;
|
|
55
|
+
const token = (0, token_resolver_1.resolveTokenKey)(api, checker, root);
|
|
56
|
+
return new model_1.Binding(token.key, token.display, 'to', 'singleton', this.implementation(impl, checker), impl.getText(), (0, token_resolver_1.relativeFile)(root, call.getSourceFile()));
|
|
57
|
+
}
|
|
58
|
+
implementation(expression, checker) {
|
|
59
|
+
let symbol = checker.getSymbolAtLocation(expression);
|
|
60
|
+
if (symbol !== undefined && (symbol.flags & ts.SymbolFlags.Alias) !== 0)
|
|
61
|
+
symbol = checker.getAliasedSymbol(symbol);
|
|
62
|
+
return symbol?.declarations?.find((declaration) => ts.isClassDeclaration(declaration)) ?? null;
|
|
63
|
+
}
|
|
64
|
+
/** `new ClientBindOptions(token, ...)` names an extra token; omitted, the API class is the token. */
|
|
65
|
+
tokenExpression(call) {
|
|
66
|
+
const options = call.arguments[2];
|
|
67
|
+
if (options !== undefined && ts.isNewExpression(options)) {
|
|
68
|
+
const token = options.arguments?.[0];
|
|
69
|
+
if (token !== undefined && token.kind !== ts.SyntaxKind.UndefinedKeyword && token.getText() !== 'undefined')
|
|
70
|
+
return token;
|
|
71
|
+
}
|
|
72
|
+
return call.arguments[0];
|
|
73
|
+
}
|
|
46
74
|
}
|
|
47
75
|
exports.RuntimeClientBindings = RuntimeClientBindings;
|
|
48
76
|
//# sourceMappingURL=runtime-client-bindings.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime-client-bindings.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/nx-webpieces-rules/src/lib/di-graph/runtime-client-bindings.ts"],"names":[],"mappings":";;;;AAAA,uDAAiC;AACjC,mCAAkC;AAClC,qDAAiE;AAEjE
|
|
1
|
+
{"version":3,"file":"runtime-client-bindings.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/nx-webpieces-rules/src/lib/di-graph/runtime-client-bindings.ts"],"names":[],"mappings":"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","sourcesContent":["import * as ts from 'typescript';\nimport { Binding } from './model';\nimport { relativeFile, resolveTokenKey } from './token-resolver';\n\n/**\n * The host binder's client registrations retain the same DI token and singleton boundary as a\n * hand-written lazy factory: `binder.createRpcClientAndBind(Api, deployment, options?)` and\n * `binder.createPubSubClientAndBind(...)` bind `options.token` when given, else the API class itself.\n * `binder.bindExternal(Api, VendorImpl)` binds the vendor class to its external contract.\n */\nexport class RuntimeClientBindings {\n collectNode(\n call: ts.CallExpression,\n checker: ts.TypeChecker,\n root: string,\n ): Binding | undefined {\n const method = this.binderMethod(call, checker, 'http-routing');\n if (method === 'createRpcClientAndBind' || method === 'createPubSubClientAndBind')\n return this.client(call, checker, root);\n if (method === 'bindExternal') return this.external(call, checker, root);\n return undefined;\n }\n\n collectBrowser(\n call: ts.CallExpression,\n checker: ts.TypeChecker,\n root: string,\n ): Binding | undefined {\n if (this.binderMethod(call, checker, 'http-client-browser') !== 'createRpcClientAndBind') return;\n return this.client(call, checker, root);\n }\n\n /** The method name when `call` resolves to the host Binder declared in `pkg`; otherwise undefined. */\n private binderMethod(call: ts.CallExpression, checker: ts.TypeChecker, pkg: string): string | undefined {\n if (!ts.isPropertyAccessExpression(call.expression)) return undefined;\n const declaration = checker.getResolvedSignature(call)?.declaration;\n if (declaration === undefined) return undefined;\n const file = declaration.getSourceFile().fileName.replace(/\\\\/g, '/');\n if (!new RegExp(`(?:/packages/http/|/node_modules/@webpieces/)${pkg}/`).test(file)) return undefined;\n const owner = declaration.parent;\n const ownerName =\n owner !== undefined && (ts.isClassDeclaration(owner) || ts.isInterfaceDeclaration(owner))\n ? owner.name?.text\n : undefined;\n return ownerName === 'Binder' ? call.expression.name.text : undefined;\n }\n\n private client(call: ts.CallExpression, checker: ts.TypeChecker, root: string): Binding | undefined {\n if (call.arguments.length < 2) return;\n const token = resolveTokenKey(this.tokenExpression(call), checker, root);\n return new Binding(\n token.key,\n token.display,\n 'toDynamicValue',\n 'singleton',\n null,\n call.expression.getText(),\n relativeFile(root, call.getSourceFile()),\n [],\n true,\n );\n }\n\n private external(call: ts.CallExpression, checker: ts.TypeChecker, root: string): Binding | undefined {\n const api = call.arguments[0];\n const impl = call.arguments[1];\n if (api === undefined || impl === undefined) return;\n const token = resolveTokenKey(api, checker, root);\n return new Binding(\n token.key,\n token.display,\n 'to',\n 'singleton',\n this.implementation(impl, checker),\n impl.getText(),\n relativeFile(root, call.getSourceFile()),\n );\n }\n\n private implementation(expression: ts.Expression, checker: ts.TypeChecker): ts.ClassDeclaration | null {\n let symbol = checker.getSymbolAtLocation(expression);\n if (symbol !== undefined && (symbol.flags & ts.SymbolFlags.Alias) !== 0) symbol = checker.getAliasedSymbol(symbol);\n return symbol?.declarations?.find((declaration: ts.Declaration) => ts.isClassDeclaration(declaration)) as ts.ClassDeclaration | undefined ?? null;\n }\n\n /** `new ClientBindOptions(token, ...)` names an extra token; omitted, the API class is the token. */\n private tokenExpression(call: ts.CallExpression): ts.Expression {\n const options = call.arguments[2];\n if (options !== undefined && ts.isNewExpression(options)) {\n const token = options.arguments?.[0];\n if (token !== undefined && token.kind !== ts.SyntaxKind.UndefinedKeyword && token.getText() !== 'undefined')\n return token;\n }\n return call.arguments[0];\n }\n}\n"]}
|
|
@@ -72,11 +72,6 @@ function declarationInitializer(decl) {
|
|
|
72
72
|
*/
|
|
73
73
|
function resolveTokenKey(expr, checker, workspaceRoot) {
|
|
74
74
|
const display = expr.getText();
|
|
75
|
-
if (ts.isPropertyAccessExpression(expr) &&
|
|
76
|
-
expr.name.text === 'identifier' &&
|
|
77
|
-
checker.getTypeAtLocation(expr.expression).getSymbol()?.getName() === 'ClientToken') {
|
|
78
|
-
return new model_1.TokenRef(resolveTokenKey(expr.expression, checker, workspaceRoot).key, display);
|
|
79
|
-
}
|
|
80
75
|
let symbol = checker.getSymbolAtLocation(expr);
|
|
81
76
|
// For `TYPES.Counter` the symbol is on the property name; for a bare identifier it
|
|
82
77
|
// may be an import alias — follow aliases to the original declaration.
|
|
@@ -97,15 +92,6 @@ function resolveTokenKey(expr, checker, workspaceRoot) {
|
|
|
97
92
|
const key = symbolCallKey(init, declFile, name);
|
|
98
93
|
if (key)
|
|
99
94
|
return new model_1.TokenRef(key, display);
|
|
100
|
-
if (ts.isNewExpression(init) &&
|
|
101
|
-
checker.getTypeAtLocation(expr).getSymbol()?.getName() === 'ClientToken') {
|
|
102
|
-
const identifier = init.arguments?.[0];
|
|
103
|
-
if (identifier !== undefined) {
|
|
104
|
-
const typedKey = symbolCallKey(identifier, declFile, name) ??
|
|
105
|
-
resolveTokenKey(identifier, checker, workspaceRoot).key;
|
|
106
|
-
return new model_1.TokenRef(typedKey, display);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
95
|
}
|
|
110
96
|
return new model_1.TokenRef(`expr:${declFile}#${name}`, display);
|
|
111
97
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"token-resolver.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/nx-webpieces-rules/src/lib/di-graph/token-resolver.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;GAaG;;AAOH,oCAEC;AAmDD,
|
|
1
|
+
{"version":3,"file":"token-resolver.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/nx-webpieces-rules/src/lib/di-graph/token-resolver.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Token Resolver\n *\n * Canonicalizes a DI token expression (the argument of @inject(...), @multiInject(...),\n * @provideSingletonDefaultForApi(...), or bind(...)) into a stable string key so that a token\n * DEFINITION (e.g. `TYPES.Counter` in one file) and its BIND SITE (e.g.\n * `bind(TYPES.Counter)` in another package) resolve to the same key.\n *\n * Key forms:\n * - Symbol.for('X') → \"symbol.for:X\" (global symbol registry — string key is identity)\n * - Symbol('X') → \"symbol:<file>#<name>\" (per-declaration identity)\n * - class-as-token → \"class:<file>#<Name>\" (e.g. @inject(HeaderMethods), bind(X).toSelf())\n * - anything else → \"expr:<file>#<text>\" (best-effort fallback)\n */\n\nimport * as ts from 'typescript';\nimport * as path from 'path';\nimport { TokenRef } from './model';\n\n/** Workspace-relative posix path for a source file. */\nexport function relativeFile(workspaceRoot: string, sourceFile: ts.SourceFile): string {\n return path.relative(workspaceRoot, sourceFile.fileName).split(path.sep).join('/');\n}\n\n/** Match a `Symbol.for('X')` or `Symbol('X')` call; returns the TokenRef key core, or null. */\nfunction symbolCallKey(init: ts.Expression, declFile: string, declName: string): string | null {\n if (!ts.isCallExpression(init)) return null;\n const callee = init.expression;\n const arg = init.arguments[0];\n const argText = arg && ts.isStringLiteralLike(arg) ? arg.text : null;\n\n // Symbol.for('X')\n if (\n ts.isPropertyAccessExpression(callee) &&\n ts.isIdentifier(callee.expression) &&\n callee.expression.text === 'Symbol' &&\n callee.name.text === 'for'\n ) {\n return argText !== null ? `symbol.for:${argText}` : `symbol.for:${declFile}#${declName}`;\n }\n\n // Symbol('X')\n if (ts.isIdentifier(callee) && callee.text === 'Symbol') {\n return `symbol:${declFile}#${argText ?? declName}`;\n }\n\n return null;\n}\n\n/** Extract the property/variable name a declaration binds. */\nfunction declaredName(decl: ts.Declaration): string {\n const named = decl as ts.NamedDeclaration;\n if (named.name && (ts.isIdentifier(named.name) || ts.isStringLiteralLike(named.name))) {\n return named.name.text;\n }\n return '<anonymous>';\n}\n\n/** Pull the initializer expression off a property-assignment or variable declaration. */\nfunction declarationInitializer(decl: ts.Declaration): ts.Expression | null {\n if (ts.isPropertyAssignment(decl)) return decl.initializer;\n if (ts.isVariableDeclaration(decl) && decl.initializer) return decl.initializer;\n if (ts.isPropertyDeclaration(decl) && decl.initializer) return decl.initializer;\n return null;\n}\n\n/**\n * Resolve a token expression to its canonical key + display text.\n *\n * Uses the type checker to follow the expression (identifier or property access,\n * possibly imported from another package) to its declaration, then inspects the\n * declaration's initializer for Symbol.for / Symbol calls.\n */\nexport function resolveTokenKey(\n expr: ts.Expression,\n checker: ts.TypeChecker,\n workspaceRoot: string,\n): TokenRef {\n const display = expr.getText();\n\n let symbol = checker.getSymbolAtLocation(expr);\n // For `TYPES.Counter` the symbol is on the property name; for a bare identifier it\n // may be an import alias — follow aliases to the original declaration.\n if (symbol && (symbol.flags & ts.SymbolFlags.Alias) !== 0) {\n symbol = checker.getAliasedSymbol(symbol);\n }\n\n const decl = symbol?.declarations?.[0];\n if (!decl) {\n return new TokenRef(`expr:<unresolved>#${display}`, display);\n }\n\n const declFile = relativeFile(workspaceRoot, decl.getSourceFile());\n const name = declaredName(decl);\n\n if (ts.isClassDeclaration(decl)) {\n return new TokenRef(`class:${declFile}#${name}`, display);\n }\n\n const init = declarationInitializer(decl);\n if (init) {\n const key = symbolCallKey(init, declFile, name);\n if (key) return new TokenRef(key, display);\n }\n\n return new TokenRef(`expr:${declFile}#${name}`, display);\n}\n\n/** Build the class-as-token key for a class declaration (bind(X).toSelf(), @provideSingleton). */\nexport function classTokenKey(\n cls: ts.ClassDeclaration,\n workspaceRoot: string,\n): TokenRef {\n const file = relativeFile(workspaceRoot, cls.getSourceFile());\n const name = cls.name ? cls.name.text : '<anonymous>';\n return new TokenRef(`class:${file}#${name}`, name);\n}\n"]}
|
|
@@ -36,15 +36,15 @@ class RuntimeWiringAssembler {
|
|
|
36
36
|
const app = this.exported(root, 'app');
|
|
37
37
|
const selections = [root, ...app.wirings.map((child) => this.forward(child, root))];
|
|
38
38
|
const result = [];
|
|
39
|
-
for (const channel of ['
|
|
39
|
+
for (const channel of ['bindModules', 'routeModules']) {
|
|
40
40
|
for (const [index, selection] of selections.entries()) {
|
|
41
41
|
const owner = this.exported(selection, index === 0 ? 'app' : 'wiring');
|
|
42
42
|
if (index > 0 && owner.wirings.length > 0)
|
|
43
43
|
this.fail(`Only AppWiring selects libraries: ${selection.project}#${selection.exportedName}.`);
|
|
44
44
|
for (const [moduleIndex, module] of owner[channel].entries()) {
|
|
45
45
|
const selected = this.forward(module, selection);
|
|
46
|
-
const leaf = this.exported(selected, channel === '
|
|
47
|
-
if (leaf.
|
|
46
|
+
const leaf = this.exported(selected, channel === 'bindModules' ? 'binding' : 'routing');
|
|
47
|
+
if (leaf.bindModules.length + leaf.routeModules.length + leaf.wirings.length > 0)
|
|
48
48
|
this.fail('Leaf modules cannot hide composition or composition cycles.');
|
|
49
49
|
const via = `${project}#${declaration.entry}/${index}:${selection.project}#${selection.exportedName}/${channel}[${moduleIndex}]:${selected.project}#${selected.exportedName}`;
|
|
50
50
|
result.push(...this.resolveRelationships(leaf, selected, via));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assembler.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/nx-webpieces-rules/src/lib/runtime-wiring/assembler.ts"],"names":[],"mappings":"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","sourcesContent":["import { Option, RuleFailError } from '@webpieces/rules-config';\nimport type { ApiTransport } from '../api-usage/api-relations';\nimport type {\n DeclaredTarget,\n RuntimeDeclaration,\n WiringExport,\n WiringRelationship,\n PolicyValue,\n} from './declaration';\nimport { WiringSelection } from './declaration';\n\nexport class ResolvedWiringRelationship {\n constructor(\n public readonly owner: string,\n public readonly api: string,\n public readonly direction: 'implements' | 'uses',\n public readonly transport: ApiTransport,\n public readonly via: string,\n public readonly target?: DeclaredTarget,\n public readonly conditional?: string,\n ) {}\n}\n\n/** Pure assembly of reviewed declarations; importing a library never activates its exports. */\nexport class RuntimeWiringAssembler {\n constructor(private readonly declarations: ReadonlyMap<string, RuntimeDeclaration>) {}\n\n assemble(project: string): ResolvedWiringRelationship[] {\n const declaration = this.getDeclaration(project);\n if (declaration.entry === undefined) this.fail(`${project} has no approved app entry.`);\n const root = newSelection(project, declaration.entry!);\n const app = this.exported(root, 'app');\n const selections = [root, ...app.wirings.map((child: WiringSelection) => this.forward(child, root))];\n const result: ResolvedWiringRelationship[] = [];\n for (const channel of ['bindingModules', 'routingModules'] as const) {\n for (const [index, selection] of selections.entries()) {\n const owner = this.exported(selection, index === 0 ? 'app' : 'wiring');\n if (index > 0 && owner.wirings.length > 0)\n this.fail(`Only AppWiring selects libraries: ${selection.project}#${selection.exportedName}.`);\n for (const [moduleIndex, module] of owner[channel].entries()) {\n const selected = this.forward(module, selection);\n const leaf = this.exported(selected, channel === 'bindingModules' ? 'binding' : 'routing');\n if (leaf.bindingModules.length + leaf.routingModules.length + leaf.wirings.length > 0)\n this.fail('Leaf modules cannot hide composition or composition cycles.');\n const via = `${project}#${declaration.entry}/${index}:${selection.project}#${selection.exportedName}/${channel}[${moduleIndex}]:${selected.project}#${selected.exportedName}`;\n result.push(...this.resolveRelationships(leaf, selected, via));\n }\n }\n }\n return result;\n }\n\n private exported(selection: WiringSelection, kind: WiringExport['kind']): WiringExport {\n const key = `${selection.project}#${selection.exportedName}`;\n const declaration = this.getDeclaration(selection.project);\n const exported = Object.hasOwn(declaration.exports, selection.exportedName)\n ? declaration.exports[selection.exportedName]\n : undefined;\n if (exported === undefined) this.fail(`Missing approved export ${key}.`);\n if (exported.kind !== kind)\n this.fail(`${key}: expected ${kind}, found ${exported.kind}. Nested app/library composition is unsupported.`);\n return exported;\n }\n\n private forward(child: WiringSelection, parent: WiringSelection): WiringSelection {\n const targets: Record<string, DeclaredTarget> = {};\n const policies: Record<string, PolicyValue> = {};\n for (const [name, target] of Object.entries(child.targets))\n targets[name] = this.resolveTarget(target, parent);\n for (const [name, value] of Object.entries(child.policies)) {\n const resolved = typeof value === 'object' ? parent.policies[value.parameter] : value;\n if (resolved === undefined || typeof resolved === 'object')\n this.fail(`Unresolved policy parameter ${name} via ${parent.project}#${parent.exportedName}.`);\n policies[name] = resolved;\n }\n return new WiringSelection(child.project, child.exportedName, targets, policies);\n }\n\n private resolveRelationships(\n exported: WiringExport,\n selection: WiringSelection,\n via: string,\n ): ResolvedWiringRelationship[] {\n const result: ResolvedWiringRelationship[] = [];\n for (const relationship of exported.relationships) {\n if (!this.isEnabled(relationship, selection)) continue;\n const target =\n relationship.target === undefined\n ? undefined\n : this.resolveTarget(relationship.target, selection);\n if (\n target?.kind === 'service' &&\n target.contract !== undefined &&\n (target.contract.project !== relationship.contract.project ||\n target.contract.exportedName !== relationship.contract.exportedName)\n )\n this.fail(\n `Target capability ${target.contract.project}#${target.contract.exportedName} disagrees with ${relationship.contract.project}#${relationship.contract.exportedName}.`,\n );\n if (relationship.direction === 'uses' && target === undefined)\n this.fail(`Missing target for ${relationship.contract.exportedName}.`);\n result.push(\n new ResolvedWiringRelationship(\n relationship.contract.project,\n relationship.contract.exportedName,\n relationship.direction,\n relationship.transport,\n via,\n target,\n relationship.policy !== undefined &&\n selection.policies[relationship.policy] === 'runtime'\n ? `${selection.project}#${selection.exportedName}:${relationship.policy}`\n : undefined,\n ),\n );\n }\n return result;\n }\n\n private isEnabled(relationship: WiringRelationship, selection: WiringSelection): boolean {\n if (relationship.policy === undefined) return true;\n const decision = selection.policies[relationship.policy];\n if (decision === undefined)\n this.fail(\n `Missing explicit policy ${relationship.policy} in ${selection.project}#${selection.exportedName}.`,\n );\n return decision === 'runtime' || decision === true;\n }\n\n private resolveTarget(target: DeclaredTarget, selection: WiringSelection): DeclaredTarget {\n if (target.kind !== 'parameter') return target;\n const argument = selection.targets[target.parameter];\n if (argument === undefined || argument.kind === 'parameter')\n this.fail(\n `Unresolved target parameter ${target.parameter} in ${selection.project}#${selection.exportedName}.`,\n );\n return argument!;\n }\n\n private getDeclaration(project: string): RuntimeDeclaration {\n const declaration = this.declarations.get(project);\n if (declaration === undefined)\n this.fail(`Missing approved runtime-deps.json for ${project}.`);\n return declaration!;\n }\n\n private fail(message: string): never {\n throw new RuleFailError('validate-runtime-architecture', message, undefined, undefined, [\n new Option(\n 'Migrate src/wiring.ts and review its runtime-deps.json before generating the graph.',\n true,\n ),\n ]);\n }\n}\n\n// webpieces-disable no-function-outside-class -- construction helper for the pure assembly entry point\nfunction newSelection(\n project: string,\n exportedName: string,\n targets: Record<string, DeclaredTarget> = {},\n policies: Record<string, PolicyValue> = {},\n): WiringSelection {\n return new WiringSelection(project, exportedName, targets, policies);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"assembler.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/nx-webpieces-rules/src/lib/runtime-wiring/assembler.ts"],"names":[],"mappings":"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","sourcesContent":["import { Option, RuleFailError } from '@webpieces/rules-config';\nimport type { ApiTransport } from '../api-usage/api-relations';\nimport type {\n DeclaredTarget,\n RuntimeDeclaration,\n WiringExport,\n WiringRelationship,\n PolicyValue,\n} from './declaration';\nimport { WiringSelection } from './declaration';\n\nexport class ResolvedWiringRelationship {\n constructor(\n public readonly owner: string,\n public readonly api: string,\n public readonly direction: 'implements' | 'uses',\n public readonly transport: ApiTransport,\n public readonly via: string,\n public readonly target?: DeclaredTarget,\n public readonly conditional?: string,\n ) {}\n}\n\n/** Pure assembly of reviewed declarations; importing a library never activates its exports. */\nexport class RuntimeWiringAssembler {\n constructor(private readonly declarations: ReadonlyMap<string, RuntimeDeclaration>) {}\n\n assemble(project: string): ResolvedWiringRelationship[] {\n const declaration = this.getDeclaration(project);\n if (declaration.entry === undefined) this.fail(`${project} has no approved app entry.`);\n const root = newSelection(project, declaration.entry!);\n const app = this.exported(root, 'app');\n const selections = [root, ...app.wirings.map((child: WiringSelection) => this.forward(child, root))];\n const result: ResolvedWiringRelationship[] = [];\n for (const channel of ['bindModules', 'routeModules'] as const) {\n for (const [index, selection] of selections.entries()) {\n const owner = this.exported(selection, index === 0 ? 'app' : 'wiring');\n if (index > 0 && owner.wirings.length > 0)\n this.fail(`Only AppWiring selects libraries: ${selection.project}#${selection.exportedName}.`);\n for (const [moduleIndex, module] of owner[channel].entries()) {\n const selected = this.forward(module, selection);\n const leaf = this.exported(selected, channel === 'bindModules' ? 'binding' : 'routing');\n if (leaf.bindModules.length + leaf.routeModules.length + leaf.wirings.length > 0)\n this.fail('Leaf modules cannot hide composition or composition cycles.');\n const via = `${project}#${declaration.entry}/${index}:${selection.project}#${selection.exportedName}/${channel}[${moduleIndex}]:${selected.project}#${selected.exportedName}`;\n result.push(...this.resolveRelationships(leaf, selected, via));\n }\n }\n }\n return result;\n }\n\n private exported(selection: WiringSelection, kind: WiringExport['kind']): WiringExport {\n const key = `${selection.project}#${selection.exportedName}`;\n const declaration = this.getDeclaration(selection.project);\n const exported = Object.hasOwn(declaration.exports, selection.exportedName)\n ? declaration.exports[selection.exportedName]\n : undefined;\n if (exported === undefined) this.fail(`Missing approved export ${key}.`);\n if (exported.kind !== kind)\n this.fail(`${key}: expected ${kind}, found ${exported.kind}. Nested app/library composition is unsupported.`);\n return exported;\n }\n\n private forward(child: WiringSelection, parent: WiringSelection): WiringSelection {\n const targets: Record<string, DeclaredTarget> = {};\n const policies: Record<string, PolicyValue> = {};\n for (const [name, target] of Object.entries(child.targets))\n targets[name] = this.resolveTarget(target, parent);\n for (const [name, value] of Object.entries(child.policies)) {\n const resolved = typeof value === 'object' ? parent.policies[value.parameter] : value;\n if (resolved === undefined || typeof resolved === 'object')\n this.fail(`Unresolved policy parameter ${name} via ${parent.project}#${parent.exportedName}.`);\n policies[name] = resolved;\n }\n return new WiringSelection(child.project, child.exportedName, targets, policies);\n }\n\n private resolveRelationships(\n exported: WiringExport,\n selection: WiringSelection,\n via: string,\n ): ResolvedWiringRelationship[] {\n const result: ResolvedWiringRelationship[] = [];\n for (const relationship of exported.relationships) {\n if (!this.isEnabled(relationship, selection)) continue;\n const target =\n relationship.target === undefined\n ? undefined\n : this.resolveTarget(relationship.target, selection);\n if (\n target?.kind === 'service' &&\n target.contract !== undefined &&\n (target.contract.project !== relationship.contract.project ||\n target.contract.exportedName !== relationship.contract.exportedName)\n )\n this.fail(\n `Target capability ${target.contract.project}#${target.contract.exportedName} disagrees with ${relationship.contract.project}#${relationship.contract.exportedName}.`,\n );\n if (relationship.direction === 'uses' && target === undefined)\n this.fail(`Missing target for ${relationship.contract.exportedName}.`);\n result.push(\n new ResolvedWiringRelationship(\n relationship.contract.project,\n relationship.contract.exportedName,\n relationship.direction,\n relationship.transport,\n via,\n target,\n relationship.policy !== undefined &&\n selection.policies[relationship.policy] === 'runtime'\n ? `${selection.project}#${selection.exportedName}:${relationship.policy}`\n : undefined,\n ),\n );\n }\n return result;\n }\n\n private isEnabled(relationship: WiringRelationship, selection: WiringSelection): boolean {\n if (relationship.policy === undefined) return true;\n const decision = selection.policies[relationship.policy];\n if (decision === undefined)\n this.fail(\n `Missing explicit policy ${relationship.policy} in ${selection.project}#${selection.exportedName}.`,\n );\n return decision === 'runtime' || decision === true;\n }\n\n private resolveTarget(target: DeclaredTarget, selection: WiringSelection): DeclaredTarget {\n if (target.kind !== 'parameter') return target;\n const argument = selection.targets[target.parameter];\n if (argument === undefined || argument.kind === 'parameter')\n this.fail(\n `Unresolved target parameter ${target.parameter} in ${selection.project}#${selection.exportedName}.`,\n );\n return argument!;\n }\n\n private getDeclaration(project: string): RuntimeDeclaration {\n const declaration = this.declarations.get(project);\n if (declaration === undefined)\n this.fail(`Missing approved runtime-deps.json for ${project}.`);\n return declaration!;\n }\n\n private fail(message: string): never {\n throw new RuleFailError('validate-runtime-architecture', message, undefined, undefined, [\n new Option(\n 'Migrate src/wiring.ts and review its runtime-deps.json before generating the graph.',\n true,\n ),\n ]);\n }\n}\n\n// webpieces-disable no-function-outside-class -- construction helper for the pure assembly entry point\nfunction newSelection(\n project: string,\n exportedName: string,\n targets: Record<string, DeclaredTarget> = {},\n policies: Record<string, PolicyValue> = {},\n): WiringSelection {\n return new WiringSelection(project, exportedName, targets, policies);\n}\n"]}
|
|
@@ -5,6 +5,8 @@ export declare class CanonicalClientBindings {
|
|
|
5
5
|
constructor(checker: ts.TypeChecker);
|
|
6
6
|
problems(file: ts.SourceFile): string[];
|
|
7
7
|
private checkFactory;
|
|
8
|
+
/** The optional trailing options argument: an extra token only when it differs from the api, plus RPC filters. */
|
|
9
|
+
private options;
|
|
8
10
|
private singleton;
|
|
9
11
|
private property;
|
|
10
12
|
private method;
|
|
@@ -75,15 +75,21 @@ class CanonicalClientBindings {
|
|
|
75
75
|
return; // Custom config options aren't supported by helpers.
|
|
76
76
|
const api = call.arguments[0].getText();
|
|
77
77
|
const target = config.arguments[0].getText();
|
|
78
|
-
const filters = call.arguments[2]
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
? `provideRpcClient(${token.getText()}, ${api}, ${target})`
|
|
83
|
-
: `new RuntimeClients(options).bindRpc(${token.getText()}, ${api}, ${target}${filters});`;
|
|
78
|
+
const filters = call.arguments[2]?.getText();
|
|
79
|
+
const helper = task ? 'createPubSubClientAndBind' : 'createRpcClientAndBind';
|
|
80
|
+
const options = this.options(token.getText() === api ? undefined : token.getText(), filters, task, provider);
|
|
81
|
+
const replacement = `binder.${helper}(${api}, ${target}${options});`;
|
|
84
82
|
const location = file.getLineAndCharacterOfPosition(factory.getStart(file));
|
|
85
83
|
problems.push(`${file.fileName}:${location.line + 1}:${location.character + 1}: canonical client registration required: ${replacement}`);
|
|
86
84
|
}
|
|
85
|
+
/** The optional trailing options argument: an extra token only when it differs from the api, plus RPC filters. */
|
|
86
|
+
options(token, filters, task, browser) {
|
|
87
|
+
if (task || browser)
|
|
88
|
+
return token === undefined ? '' : `, new ${task ? 'PubSubBindOptions' : 'ClientBindOptions'}(${token})`;
|
|
89
|
+
if (token === undefined && filters === undefined)
|
|
90
|
+
return '';
|
|
91
|
+
return `, new ClientBindOptions(${token ?? 'undefined'}${filters === undefined ? '' : `, ${filters}`})`;
|
|
92
|
+
}
|
|
87
93
|
singleton(call) {
|
|
88
94
|
let node = call;
|
|
89
95
|
while (node.parent !== undefined &&
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"canonical-clients.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/nx-webpieces-rules/src/lib/runtime-wiring/canonical-clients.ts"],"names":[],"mappings":"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","sourcesContent":["import * as ts from 'typescript';\n\n/** Replacement diagnostics used only by the canonical wiring-format analyzer. */\nexport class CanonicalClientBindings {\n constructor(private readonly checker: ts.TypeChecker) {}\n\n problems(file: ts.SourceFile): string[] {\n if (!/(?:^|\\/)wiring\\.ts$/.test(file.fileName)) return [];\n const problems: string[] = [];\n const visit = (node: ts.Node): void => {\n if (ts.isCallExpression(node) && this.method(node.expression) === 'toDynamicValue') {\n const bind = this.expand(node.expression);\n const receiver =\n ts.isPropertyAccessExpression(bind) || ts.isElementAccessExpression(bind)\n ? this.expand(bind.expression)\n : undefined;\n if (\n receiver !== undefined &&\n ts.isCallExpression(receiver) &&\n this.method(receiver.expression) === 'bind' &&\n this.singleton(node)\n ) {\n this.checkFactory(\n node.arguments[0],\n receiver.arguments[0],\n false,\n file,\n problems,\n );\n }\n }\n if (ts.isObjectLiteralExpression(node)) {\n const token = this.property(node, 'provide');\n const factory = this.property(node, 'useFactory');\n if (token !== undefined && factory !== undefined)\n this.checkFactory(factory, token, true, file, problems);\n }\n ts.forEachChild(node, visit);\n };\n visit(file);\n return problems;\n }\n\n private checkFactory(\n factory: ts.Expression | undefined,\n token: ts.Expression | undefined,\n browser: boolean,\n file: ts.SourceFile,\n problems: string[],\n ): void {\n if (factory === undefined || token === undefined) return;\n const value = this.expand(factory);\n if (!ts.isArrowFunction(value) && !ts.isFunctionExpression(value)) return;\n const result =\n ts.isBlock(value.body) &&\n value.body.statements.length === 1 &&\n ts.isReturnStatement(value.body.statements[0])\n ? value.body.statements[0].expression\n : ts.isBlock(value.body)\n ? undefined\n : value.body;\n if (result === undefined) return; // Side effects/custom adapters have no helper equivalent.\n const call = this.expand(result);\n if (!ts.isCallExpression(call)) return;\n const declaration = this.checker.getResolvedSignature(call)?.declaration;\n const owner = declaration?.parent;\n if (owner === undefined || !ts.isClassDeclaration(owner)) return;\n const name = owner.name?.text;\n const method = this.method(call.expression);\n const rpc = name === 'ClientHttpFactory' && method === 'createRpcClient' && !browser;\n const task =\n name === 'ClientCloudTasksFactory' && method === 'createPubSubClient' && !browser;\n const provider =\n name === 'ClientHttpBrowserFactory' && method === 'createRpcClient' && browser;\n if (!rpc && !task && !provider) return;\n if (call.arguments.length < 2 || call.arguments.length > (rpc ? 3 : 2)) return;\n const config = this.expand(call.arguments[1]);\n if (\n !ts.isNewExpression(config) ||\n this.method(config.expression) !== (task ? 'TaskClientConfig' : 'ClientConfig') ||\n config.arguments?.length !== 1\n )\n return; // Custom config options aren't supported by helpers.\n const api = call.arguments[0].getText();\n const target = config.arguments[0].getText();\n const filters = call.arguments[2] === undefined ? '' : `, ${call.arguments[2].getText()}`;\n const replacement = task\n ? `new RuntimeTaskClients(options).bindPubSub(${token.getText()}, ${api}, ${target});`\n : provider\n ? `provideRpcClient(${token.getText()}, ${api}, ${target})`\n : `new RuntimeClients(options).bindRpc(${token.getText()}, ${api}, ${target}${filters});`;\n const location = file.getLineAndCharacterOfPosition(factory.getStart(file));\n problems.push(\n `${file.fileName}:${location.line + 1}:${location.character + 1}: canonical client registration required: ${replacement}`,\n );\n }\n\n private singleton(call: ts.CallExpression): boolean {\n let node: ts.Node = call;\n while (\n node.parent !== undefined &&\n (ts.isPropertyAccessExpression(node.parent) ||\n ts.isElementAccessExpression(node.parent) ||\n ts.isCallExpression(node.parent))\n ) {\n node = node.parent;\n if (ts.isCallExpression(node) && this.method(node.expression) === 'inSingletonScope')\n return true;\n }\n return false;\n }\n\n private property(node: ts.ObjectLiteralExpression, name: string): ts.Expression | undefined {\n for (const property of node.properties) {\n if (\n ts.isPropertyAssignment(property) &&\n (ts.isIdentifier(property.name) || ts.isStringLiteralLike(property.name)) &&\n property.name.text === name\n )\n return property.initializer;\n if (ts.isShorthandPropertyAssignment(property) && property.name.text === name)\n return property.name;\n }\n return undefined;\n }\n\n private method(expression: ts.Expression): string {\n const value = this.expand(expression);\n if (ts.isPropertyAccessExpression(value)) return value.name.text;\n if (ts.isElementAccessExpression(value) && ts.isStringLiteralLike(value.argumentExpression))\n return value.argumentExpression.text;\n const symbol = this.checker.getSymbolAtLocation(value);\n return symbol !== undefined && (symbol.flags & ts.SymbolFlags.Alias) !== 0\n ? this.checker.getAliasedSymbol(symbol).getName()\n : (symbol?.getName() ?? value.getText());\n }\n\n private expand(expression: ts.Expression, seen: Set<ts.Node> = new Set()): ts.Expression {\n if (seen.has(expression)) return expression;\n seen.add(expression);\n if (\n ts.isParenthesizedExpression(expression) ||\n ts.isAsExpression(expression) ||\n ts.isNonNullExpression(expression) ||\n ts.isSatisfiesExpression(expression)\n )\n return this.expand(expression.expression, seen);\n const declaration = this.checker.getSymbolAtLocation(expression)?.valueDeclaration;\n if (\n declaration !== undefined &&\n ts.isVariableDeclaration(declaration) &&\n declaration.initializer !== undefined\n )\n return this.expand(declaration.initializer, seen);\n return expression;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"canonical-clients.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/nx-webpieces-rules/src/lib/runtime-wiring/canonical-clients.ts"],"names":[],"mappings":";;;;AAAA,uDAAiC;AAEjC,iFAAiF;AACjF,MAAa,uBAAuB;IACH;IAA7B,YAA6B,OAAuB;QAAvB,YAAO,GAAP,OAAO,CAAgB;IAAG,CAAC;IAExD,QAAQ,CAAC,IAAmB;QACxB,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC;YAAE,OAAO,EAAE,CAAC;QAC1D,MAAM,QAAQ,GAAa,EAAE,CAAC;QAC9B,MAAM,KAAK,GAAG,CAAC,IAAa,EAAQ,EAAE;YAClC,IAAI,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,gBAAgB,EAAE,CAAC;gBACjF,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;gBAC1C,MAAM,QAAQ,GACV,EAAE,CAAC,0BAA0B,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,yBAAyB,CAAC,IAAI,CAAC;oBACrE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC;oBAC9B,CAAC,CAAC,SAAS,CAAC;gBACpB,IACI,QAAQ,KAAK,SAAS;oBACtB,EAAE,CAAC,gBAAgB,CAAC,QAAQ,CAAC;oBAC7B,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,KAAK,MAAM;oBAC3C,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EACtB,CAAC;oBACC,IAAI,CAAC,YAAY,CACb,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EACjB,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,EACrB,KAAK,EACL,IAAI,EACJ,QAAQ,CACX,CAAC;gBACN,CAAC;YACL,CAAC;YACD,IAAI,EAAE,CAAC,yBAAyB,CAAC,IAAI,CAAC,EAAE,CAAC;gBACrC,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;gBAC7C,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;gBAClD,IAAI,KAAK,KAAK,SAAS,IAAI,OAAO,KAAK,SAAS;oBAC5C,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;YAChE,CAAC;YACD,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QACjC,CAAC,CAAC;QACF,KAAK,CAAC,IAAI,CAAC,CAAC;QACZ,OAAO,QAAQ,CAAC;IACpB,CAAC;IAEO,YAAY,CAChB,OAAkC,EAClC,KAAgC,EAChC,OAAgB,EAChB,IAAmB,EACnB,QAAkB;QAElB,IAAI,OAAO,KAAK,SAAS,IAAI,KAAK,KAAK,SAAS;YAAE,OAAO;QACzD,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACnC,IAAI,CAAC,EAAE,CAAC,eAAe,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,oBAAoB,CAAC,KAAK,CAAC;YAAE,OAAO;QAC1E,MAAM,MAAM,GACR,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC;YACtB,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,KAAK,CAAC;YAClC,EAAE,CAAC,iBAAiB,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;YAC1C,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU;YACrC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC;gBACtB,CAAC,CAAC,SAAS;gBACX,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC;QACvB,IAAI,MAAM,KAAK,SAAS;YAAE,OAAO,CAAC,0DAA0D;QAC5F,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACjC,IAAI,CAAC,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC;YAAE,OAAO;QACvC,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,oBAAoB,CAAC,IAAI,CAAC,EAAE,WAAW,CAAC;QACzE,MAAM,KAAK,GAAG,WAAW,EAAE,MAAM,CAAC;QAClC,IAAI,KAAK,KAAK,SAAS,IAAI,CAAC,EAAE,CAAC,kBAAkB,CAAC,KAAK,CAAC;YAAE,OAAO;QACjE,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC;QAC9B,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC5C,MAAM,GAAG,GAAG,IAAI,KAAK,mBAAmB,IAAI,MAAM,KAAK,iBAAiB,IAAI,CAAC,OAAO,CAAC;QACrF,MAAM,IAAI,GACN,IAAI,KAAK,yBAAyB,IAAI,MAAM,KAAK,oBAAoB,IAAI,CAAC,OAAO,CAAC;QACtF,MAAM,QAAQ,GACV,IAAI,KAAK,0BAA0B,IAAI,MAAM,KAAK,iBAAiB,IAAI,OAAO,CAAC;QACnF,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,IAAI,CAAC,QAAQ;YAAE,OAAO;QACvC,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAAE,OAAO;QAC/E,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;QAC9C,IACI,CAAC,EAAE,CAAC,eAAe,CAAC,MAAM,CAAC;YAC3B,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,cAAc,CAAC;YAC/E,MAAM,CAAC,SAAS,EAAE,MAAM,KAAK,CAAC;YAE9B,OAAO,CAAC,qDAAqD;QACjE,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;QACxC,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;QAC7C,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC;QAC7C,MAAM,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,2BAA2B,CAAC,CAAC,CAAC,wBAAwB,CAAC;QAC7E,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;QAC7G,MAAM,WAAW,GAAG,UAAU,MAAM,IAAI,GAAG,KAAK,MAAM,GAAG,OAAO,IAAI,CAAC;QACrE,MAAM,QAAQ,GAAG,IAAI,CAAC,6BAA6B,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;QAC5E,QAAQ,CAAC,IAAI,CACT,GAAG,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,IAAI,GAAG,CAAC,IAAI,QAAQ,CAAC,SAAS,GAAG,CAAC,6CAA6C,WAAW,EAAE,CAC5H,CAAC;IACN,CAAC;IAED,kHAAkH;IAC1G,OAAO,CAAC,KAAyB,EAAE,OAA2B,EAAE,IAAa,EAAE,OAAgB;QACnG,IAAI,IAAI,IAAI,OAAO;YACf,OAAO,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,mBAAmB,IAAI,KAAK,GAAG,CAAC;QAC5G,IAAI,KAAK,KAAK,SAAS,IAAI,OAAO,KAAK,SAAS;YAAE,OAAO,EAAE,CAAC;QAC5D,OAAO,2BAA2B,KAAK,IAAI,WAAW,GAAG,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,OAAO,EAAE,GAAG,CAAC;IAC5G,CAAC;IAEO,SAAS,CAAC,IAAuB;QACrC,IAAI,IAAI,GAAY,IAAI,CAAC;QACzB,OACI,IAAI,CAAC,MAAM,KAAK,SAAS;YACzB,CAAC,EAAE,CAAC,0BAA0B,CAAC,IAAI,CAAC,MAAM,CAAC;gBACvC,EAAE,CAAC,yBAAyB,CAAC,IAAI,CAAC,MAAM,CAAC;gBACzC,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,EACvC,CAAC;YACC,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC;YACnB,IAAI,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,kBAAkB;gBAChF,OAAO,IAAI,CAAC;QACpB,CAAC;QACD,OAAO,KAAK,CAAC;IACjB,CAAC;IAEO,QAAQ,CAAC,IAAgC,EAAE,IAAY;QAC3D,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACrC,IACI,EAAE,CAAC,oBAAoB,CAAC,QAAQ,CAAC;gBACjC,CAAC,EAAE,CAAC,YAAY,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,mBAAmB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;gBACzE,QAAQ,CAAC,IAAI,CAAC,IAAI,KAAK,IAAI;gBAE3B,OAAO,QAAQ,CAAC,WAAW,CAAC;YAChC,IAAI,EAAE,CAAC,6BAA6B,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,KAAK,IAAI;gBACzE,OAAO,QAAQ,CAAC,IAAI,CAAC;QAC7B,CAAC;QACD,OAAO,SAAS,CAAC;IACrB,CAAC;IAEO,MAAM,CAAC,UAAyB;QACpC,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QACtC,IAAI,EAAE,CAAC,0BAA0B,CAAC,KAAK,CAAC;YAAE,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;QACjE,IAAI,EAAE,CAAC,yBAAyB,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,mBAAmB,CAAC,KAAK,CAAC,kBAAkB,CAAC;YACvF,OAAO,KAAK,CAAC,kBAAkB,CAAC,IAAI,CAAC;QACzC,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,mBAAmB,CAAC,KAAK,CAAC,CAAC;QACvD,OAAO,MAAM,KAAK,SAAS,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC;YACtE,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE;YACjD,CAAC,CAAC,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;IACjD,CAAC;IAEO,MAAM,CAAC,UAAyB,EAAE,OAAqB,IAAI,GAAG,EAAE;QACpE,IAAI,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC;YAAE,OAAO,UAAU,CAAC;QAC5C,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QACrB,IACI,EAAE,CAAC,yBAAyB,CAAC,UAAU,CAAC;YACxC,EAAE,CAAC,cAAc,CAAC,UAAU,CAAC;YAC7B,EAAE,CAAC,mBAAmB,CAAC,UAAU,CAAC;YAClC,EAAE,CAAC,qBAAqB,CAAC,UAAU,CAAC;YAEpC,OAAO,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;QACpD,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,mBAAmB,CAAC,UAAU,CAAC,EAAE,gBAAgB,CAAC;QACnF,IACI,WAAW,KAAK,SAAS;YACzB,EAAE,CAAC,qBAAqB,CAAC,WAAW,CAAC;YACrC,WAAW,CAAC,WAAW,KAAK,SAAS;YAErC,OAAO,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;QACtD,OAAO,UAAU,CAAC;IACtB,CAAC;CACJ;AA/JD,0DA+JC","sourcesContent":["import * as ts from 'typescript';\n\n/** Replacement diagnostics used only by the canonical wiring-format analyzer. */\nexport class CanonicalClientBindings {\n constructor(private readonly checker: ts.TypeChecker) {}\n\n problems(file: ts.SourceFile): string[] {\n if (!/(?:^|\\/)wiring\\.ts$/.test(file.fileName)) return [];\n const problems: string[] = [];\n const visit = (node: ts.Node): void => {\n if (ts.isCallExpression(node) && this.method(node.expression) === 'toDynamicValue') {\n const bind = this.expand(node.expression);\n const receiver =\n ts.isPropertyAccessExpression(bind) || ts.isElementAccessExpression(bind)\n ? this.expand(bind.expression)\n : undefined;\n if (\n receiver !== undefined &&\n ts.isCallExpression(receiver) &&\n this.method(receiver.expression) === 'bind' &&\n this.singleton(node)\n ) {\n this.checkFactory(\n node.arguments[0],\n receiver.arguments[0],\n false,\n file,\n problems,\n );\n }\n }\n if (ts.isObjectLiteralExpression(node)) {\n const token = this.property(node, 'provide');\n const factory = this.property(node, 'useFactory');\n if (token !== undefined && factory !== undefined)\n this.checkFactory(factory, token, true, file, problems);\n }\n ts.forEachChild(node, visit);\n };\n visit(file);\n return problems;\n }\n\n private checkFactory(\n factory: ts.Expression | undefined,\n token: ts.Expression | undefined,\n browser: boolean,\n file: ts.SourceFile,\n problems: string[],\n ): void {\n if (factory === undefined || token === undefined) return;\n const value = this.expand(factory);\n if (!ts.isArrowFunction(value) && !ts.isFunctionExpression(value)) return;\n const result =\n ts.isBlock(value.body) &&\n value.body.statements.length === 1 &&\n ts.isReturnStatement(value.body.statements[0])\n ? value.body.statements[0].expression\n : ts.isBlock(value.body)\n ? undefined\n : value.body;\n if (result === undefined) return; // Side effects/custom adapters have no helper equivalent.\n const call = this.expand(result);\n if (!ts.isCallExpression(call)) return;\n const declaration = this.checker.getResolvedSignature(call)?.declaration;\n const owner = declaration?.parent;\n if (owner === undefined || !ts.isClassDeclaration(owner)) return;\n const name = owner.name?.text;\n const method = this.method(call.expression);\n const rpc = name === 'ClientHttpFactory' && method === 'createRpcClient' && !browser;\n const task =\n name === 'ClientCloudTasksFactory' && method === 'createPubSubClient' && !browser;\n const provider =\n name === 'ClientHttpBrowserFactory' && method === 'createRpcClient' && browser;\n if (!rpc && !task && !provider) return;\n if (call.arguments.length < 2 || call.arguments.length > (rpc ? 3 : 2)) return;\n const config = this.expand(call.arguments[1]);\n if (\n !ts.isNewExpression(config) ||\n this.method(config.expression) !== (task ? 'TaskClientConfig' : 'ClientConfig') ||\n config.arguments?.length !== 1\n )\n return; // Custom config options aren't supported by helpers.\n const api = call.arguments[0].getText();\n const target = config.arguments[0].getText();\n const filters = call.arguments[2]?.getText();\n const helper = task ? 'createPubSubClientAndBind' : 'createRpcClientAndBind';\n const options = this.options(token.getText() === api ? undefined : token.getText(), filters, task, provider);\n const replacement = `binder.${helper}(${api}, ${target}${options});`;\n const location = file.getLineAndCharacterOfPosition(factory.getStart(file));\n problems.push(\n `${file.fileName}:${location.line + 1}:${location.character + 1}: canonical client registration required: ${replacement}`,\n );\n }\n\n /** The optional trailing options argument: an extra token only when it differs from the api, plus RPC filters. */\n private options(token: string | undefined, filters: string | undefined, task: boolean, browser: boolean): string {\n if (task || browser)\n return token === undefined ? '' : `, new ${task ? 'PubSubBindOptions' : 'ClientBindOptions'}(${token})`;\n if (token === undefined && filters === undefined) return '';\n return `, new ClientBindOptions(${token ?? 'undefined'}${filters === undefined ? '' : `, ${filters}`})`;\n }\n\n private singleton(call: ts.CallExpression): boolean {\n let node: ts.Node = call;\n while (\n node.parent !== undefined &&\n (ts.isPropertyAccessExpression(node.parent) ||\n ts.isElementAccessExpression(node.parent) ||\n ts.isCallExpression(node.parent))\n ) {\n node = node.parent;\n if (ts.isCallExpression(node) && this.method(node.expression) === 'inSingletonScope')\n return true;\n }\n return false;\n }\n\n private property(node: ts.ObjectLiteralExpression, name: string): ts.Expression | undefined {\n for (const property of node.properties) {\n if (\n ts.isPropertyAssignment(property) &&\n (ts.isIdentifier(property.name) || ts.isStringLiteralLike(property.name)) &&\n property.name.text === name\n )\n return property.initializer;\n if (ts.isShorthandPropertyAssignment(property) && property.name.text === name)\n return property.name;\n }\n return undefined;\n }\n\n private method(expression: ts.Expression): string {\n const value = this.expand(expression);\n if (ts.isPropertyAccessExpression(value)) return value.name.text;\n if (ts.isElementAccessExpression(value) && ts.isStringLiteralLike(value.argumentExpression))\n return value.argumentExpression.text;\n const symbol = this.checker.getSymbolAtLocation(value);\n return symbol !== undefined && (symbol.flags & ts.SymbolFlags.Alias) !== 0\n ? this.checker.getAliasedSymbol(symbol).getName()\n : (symbol?.getName() ?? value.getText());\n }\n\n private expand(expression: ts.Expression, seen: Set<ts.Node> = new Set()): ts.Expression {\n if (seen.has(expression)) return expression;\n seen.add(expression);\n if (\n ts.isParenthesizedExpression(expression) ||\n ts.isAsExpression(expression) ||\n ts.isNonNullExpression(expression) ||\n ts.isSatisfiesExpression(expression)\n )\n return this.expand(expression.expression, seen);\n const declaration = this.checker.getSymbolAtLocation(expression)?.valueDeclaration;\n if (\n declaration !== undefined &&\n ts.isVariableDeclaration(declaration) &&\n declaration.initializer !== undefined\n )\n return this.expand(declaration.initializer, seen);\n return expression;\n }\n}\n"]}
|
|
@@ -38,7 +38,7 @@ class RuntimeDeclarationCodec {
|
|
|
38
38
|
if (exported.kind !== 'app' && exported.wirings.length > 0)
|
|
39
39
|
this.fail(`${name}: only AppWiring may select library Wirings.`);
|
|
40
40
|
if (!['app', 'wiring'].includes(exported.kind) &&
|
|
41
|
-
(exported.
|
|
41
|
+
(exported.bindModules.length > 0 || exported.routeModules.length > 0))
|
|
42
42
|
this.fail(`${name}: leaf modules cannot select module lists.`);
|
|
43
43
|
if (['app', 'wiring'].includes(exported.kind) && exported.relationships.length > 0)
|
|
44
44
|
this.fail(`${name}: declare relationships in named binding/route modules.`);
|
|
@@ -58,7 +58,9 @@ class RuntimeDeclarationCodec {
|
|
|
58
58
|
}
|
|
59
59
|
// webpieces-disable no-any-unknown -- untrusted JSON is narrowed and validated at the input boundary
|
|
60
60
|
exported(value) {
|
|
61
|
-
|
|
61
|
+
this.renamed(value, 'bindingModules', 'bindModules');
|
|
62
|
+
this.renamed(value, 'routingModules', 'routeModules');
|
|
63
|
+
const exported = this.record(value, ['kind', 'relationships', 'bindModules', 'routeModules', 'wirings']);
|
|
62
64
|
const kind = this.string(exported['kind']);
|
|
63
65
|
if (kind !== 'binding' &&
|
|
64
66
|
kind !== 'routing' &&
|
|
@@ -66,7 +68,12 @@ class RuntimeDeclarationCodec {
|
|
|
66
68
|
kind !== 'app' &&
|
|
67
69
|
kind !== 'external')
|
|
68
70
|
this.fail(`Invalid export kind ${kind}.`);
|
|
69
|
-
return new declaration_1.WiringExport(kind, this.array(exported['relationships']).map((value) => this.relationship(value)), this.array(exported['
|
|
71
|
+
return new declaration_1.WiringExport(kind, this.array(exported['relationships']).map((value) => this.relationship(value)), this.array(exported['bindModules']).map((value) => this.selection(value)), this.array(exported['routeModules']).map((value) => this.selection(value)), this.array(exported['wirings']).map((value) => this.selection(value)));
|
|
72
|
+
}
|
|
73
|
+
// webpieces-disable no-any-unknown -- untrusted JSON is narrowed before the renamed-field check
|
|
74
|
+
renamed(value, old, renamed) {
|
|
75
|
+
if (Object.hasOwn(this.record(value), old))
|
|
76
|
+
this.fail(`runtime-deps field ${old} was renamed to ${renamed}; regenerate the candidate from src/wiring.ts (getBindModules/getRouteModules) and review it.`);
|
|
70
77
|
}
|
|
71
78
|
// webpieces-disable no-any-unknown -- untrusted relationship JSON is narrowed before construction
|
|
72
79
|
relationship(value) {
|