@webpieces/nx-webpieces-rules 0.4.869 → 0.4.871

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/package.json +7 -7
  2. package/src/lib/di-graph/runtime-client-bindings.d.ts +17 -3
  3. package/src/lib/di-graph/runtime-client-bindings.js +70 -26
  4. package/src/lib/di-graph/runtime-client-bindings.js.map +1 -1
  5. package/src/lib/di-graph/token-resolver.js +0 -14
  6. package/src/lib/di-graph/token-resolver.js.map +1 -1
  7. package/src/lib/runtime-wiring/assembler.js +3 -3
  8. package/src/lib/runtime-wiring/assembler.js.map +1 -1
  9. package/src/lib/runtime-wiring/canonical-clients.d.ts +2 -0
  10. package/src/lib/runtime-wiring/canonical-clients.js +12 -6
  11. package/src/lib/runtime-wiring/canonical-clients.js.map +1 -1
  12. package/src/lib/runtime-wiring/codec.d.ts +1 -0
  13. package/src/lib/runtime-wiring/codec.js +10 -3
  14. package/src/lib/runtime-wiring/codec.js.map +1 -1
  15. package/src/lib/runtime-wiring/declaration.d.ts +3 -3
  16. package/src/lib/runtime-wiring/declaration.js +5 -5
  17. package/src/lib/runtime-wiring/declaration.js.map +1 -1
  18. package/src/lib/runtime-wiring/prepared-targets.js +4 -4
  19. package/src/lib/runtime-wiring/prepared-targets.js.map +1 -1
  20. package/src/lib/runtime-wiring/source-extractor.d.ts +15 -3
  21. package/src/lib/runtime-wiring/source-extractor.js +53 -41
  22. package/src/lib/runtime-wiring/source-extractor.js.map +1 -1
  23. package/src/lib/runtime-wiring/source-types.js +1 -1
  24. package/src/lib/runtime-wiring/source-types.js.map +1 -1
  25. package/src/lib/runtime-wiring/wiring-format.d.ts +9 -7
  26. package/src/lib/runtime-wiring/wiring-format.js +52 -56
  27. package/src/lib/runtime-wiring/wiring-format.js.map +1 -1
  28. package/src/rule-help.js +2 -2
  29. 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.869",
3
+ "version": "0.4.871",
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.869",
24
- "@webpieces/core-util": "0.4.869",
25
- "@webpieces/eslint-rules": "0.4.869",
26
- "@webpieces/rules-config": "0.4.869",
23
+ "@webpieces/api-doc-model": "0.4.871",
24
+ "@webpieces/core-util": "0.4.871",
25
+ "@webpieces/eslint-rules": "0.4.871",
26
+ "@webpieces/rules-config": "0.4.871",
27
27
  "madge": "8.0.0",
28
- "@webpieces/rules-sdk": "0.4.869"
28
+ "@webpieces/rules-sdk": "0.4.871"
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.869"
44
+ "@webpieces/tooling-testkit": "0.4.871"
45
45
  },
46
46
  "types": "./src/index.d.ts",
47
47
  "bin": {
@@ -1,9 +1,23 @@
1
1
  import * as ts from 'typescript';
2
2
  import { Binding } from './model';
3
- /** Canonical lazy client helpers retain the same DI token and singleton boundary. */
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; the browser
8
+ * spelling `binder.bindExternal(Api, new UseClass(Vendor) | new UseExisting(Token))`
9
+ * resolves through to the same implementation class (an alias walks into its target).
10
+ */
4
11
  export declare class RuntimeClientBindings {
5
12
  collectNode(call: ts.CallExpression, checker: ts.TypeChecker, root: string): Binding | undefined;
6
13
  collectBrowser(call: ts.CallExpression, checker: ts.TypeChecker, root: string): Binding | undefined;
7
- private frameworkCall;
8
- private binding;
14
+ /** The method name when `call` resolves to the host Binder declared in `pkg`; otherwise undefined. */
15
+ private binderMethod;
16
+ private client;
17
+ private external;
18
+ /** The browser `new UseClass(X)` / `new UseExisting(X)` names X; the Node form is X itself. */
19
+ private externalImpl;
20
+ private implementation;
21
+ /** `new ClientBindOptions(token, ...)` names an extra token; omitted, the API class is the token. */
22
+ private tokenExpression;
9
23
  }
@@ -5,44 +5,88 @@ 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
- /** Canonical lazy client helpers retain the same DI token and singleton boundary. */
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; the browser
13
+ * spelling `binder.bindExternal(Api, new UseClass(Vendor) | new UseExisting(Token))`
14
+ * resolves through to the same implementation class (an alias walks into its target).
15
+ */
9
16
  class RuntimeClientBindings {
10
17
  collectNode(call, checker, root) {
11
- if (!this.frameworkCall(call, checker))
12
- return;
13
- const callee = call.expression;
14
- if (!ts.isPropertyAccessExpression(callee))
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
- }
18
+ const method = this.binderMethod(call, checker, 'http-routing');
19
+ if (method === 'createRpcClientAndBind' || method === 'createPubSubClientAndBind')
20
+ return this.client(call, checker, root);
21
+ if (method === 'bindExternal')
22
+ return this.external(call, checker, root);
21
23
  return undefined;
22
24
  }
23
25
  collectBrowser(call, checker, root) {
24
- if (!this.frameworkCall(call, checker))
25
- return;
26
- let symbol = checker.getSymbolAtLocation(call.expression);
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
+ const method = this.binderMethod(call, checker, 'http-client-browser');
27
+ if (method === 'createRpcClientAndBind')
28
+ return this.client(call, checker, root);
29
+ if (method === 'bindExternal')
30
+ return this.external(call, checker, root);
31
+ return undefined;
33
32
  }
34
- frameworkCall(call, checker) {
33
+ /** The method name when `call` resolves to the host Binder declared in `pkg`; otherwise undefined. */
34
+ binderMethod(call, checker, pkg) {
35
+ if (!ts.isPropertyAccessExpression(call.expression))
36
+ return undefined;
35
37
  const declaration = checker.getResolvedSignature(call)?.declaration;
36
38
  if (declaration === undefined)
37
- return false;
38
- return /(?:\/packages\/(?:http|cloud)\/|\/node_modules\/@webpieces\/)(?:http-client-node|http-client-browser|cloudtasks-client)\//.test(declaration.getSourceFile().fileName.replace(/\\/g, '/'));
39
+ return undefined;
40
+ const file = declaration.getSourceFile().fileName.replace(/\\/g, '/');
41
+ if (!new RegExp(`(?:/packages/http/|/node_modules/@webpieces/)${pkg}/`).test(file))
42
+ return undefined;
43
+ const owner = declaration.parent;
44
+ const ownerName = owner !== undefined && (ts.isClassDeclaration(owner) || ts.isInterfaceDeclaration(owner))
45
+ ? owner.name?.text
46
+ : undefined;
47
+ return ownerName === 'Binder' ? call.expression.name.text : undefined;
39
48
  }
40
- binding(call, checker, root) {
41
- if (call.arguments.length < 3)
49
+ client(call, checker, root) {
50
+ if (call.arguments.length < 2)
42
51
  return;
43
- const token = (0, token_resolver_1.resolveTokenKey)(call.arguments[0], checker, root);
52
+ const token = (0, token_resolver_1.resolveTokenKey)(this.tokenExpression(call), checker, root);
44
53
  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
54
  }
55
+ external(call, checker, root) {
56
+ const api = call.arguments[0];
57
+ const impl = call.arguments[1] === undefined ? undefined : this.externalImpl(call.arguments[1], checker);
58
+ if (api === undefined || impl === undefined)
59
+ return;
60
+ const token = (0, token_resolver_1.resolveTokenKey)(api, checker, root);
61
+ 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()));
62
+ }
63
+ /** The browser `new UseClass(X)` / `new UseExisting(X)` names X; the Node form is X itself. */
64
+ externalImpl(expression, checker) {
65
+ if (!ts.isNewExpression(expression))
66
+ return expression;
67
+ let recipe = checker.getSymbolAtLocation(expression.expression);
68
+ if (recipe !== undefined && (recipe.flags & ts.SymbolFlags.Alias) !== 0)
69
+ recipe = checker.getAliasedSymbol(recipe);
70
+ if (recipe === undefined || !['UseClass', 'UseExisting'].includes(recipe.getName()))
71
+ return undefined;
72
+ return expression.arguments?.[0];
73
+ }
74
+ implementation(expression, checker) {
75
+ let symbol = checker.getSymbolAtLocation(expression);
76
+ if (symbol !== undefined && (symbol.flags & ts.SymbolFlags.Alias) !== 0)
77
+ symbol = checker.getAliasedSymbol(symbol);
78
+ return symbol?.declarations?.find((declaration) => ts.isClassDeclaration(declaration)) ?? null;
79
+ }
80
+ /** `new ClientBindOptions(token, ...)` names an extra token; omitted, the API class is the token. */
81
+ tokenExpression(call) {
82
+ const options = call.arguments[2];
83
+ if (options !== undefined && ts.isNewExpression(options)) {
84
+ const token = options.arguments?.[0];
85
+ if (token !== undefined && token.kind !== ts.SyntaxKind.UndefinedKeyword && token.getText() !== 'undefined')
86
+ return token;
87
+ }
88
+ return call.arguments[0];
89
+ }
46
90
  }
47
91
  exports.RuntimeClientBindings = RuntimeClientBindings;
48
92
  //# 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,qFAAqF;AACrF,MAAa,qBAAqB;IAC9B,WAAW,CACP,IAAuB,EACvB,OAAuB,EACvB,IAAY;QAEZ,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC;YAAE,OAAO;QAC/C,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC;QAC/B,IAAI,CAAC,EAAE,CAAC,0BAA0B,CAAC,MAAM,CAAC;YAAE,OAAO;QACnD,MAAM,KAAK,GAAG,OAAO,CAAC,iBAAiB,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,SAAS,EAAE,EAAE,OAAO,EAAE,CAAC;QAClF,IACI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,KAAK,SAAS,IAAI,KAAK,KAAK,gBAAgB,CAAC;YAC9D,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,KAAK,YAAY,IAAI,KAAK,KAAK,oBAAoB,CAAC,EACvE,CAAC;YACC,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;QAC7C,CAAC;QACD,OAAO,SAAS,CAAC;IACrB,CAAC;IAED,cAAc,CACV,IAAuB,EACvB,OAAuB,EACvB,IAAY;QAEZ,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC;YAAE,OAAO;QAC/C,IAAI,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC1D,IAAI,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC;YACrD,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC;QAC9C,IACI,MAAM,EAAE,OAAO,EAAE,KAAK,kBAAkB;YACxC,OAAO,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,OAAO,EAAE,KAAK,mBAAmB;YAE9E,OAAO;QACX,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;IAC7C,CAAC;IAEO,aAAa,CAAC,IAAuB,EAAE,OAAuB;QAClE,MAAM,WAAW,GAAG,OAAO,CAAC,oBAAoB,CAAC,IAAI,CAAC,EAAE,WAAW,CAAC;QACpE,IAAI,WAAW,KAAK,SAAS;YAAE,OAAO,KAAK,CAAC;QAC5C,OAAO,2HAA2H,CAAC,IAAI,CAAC,WAAW,CAAC,aAAa,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC;IACtM,CAAC;IAEO,OAAO,CACX,IAAuB,EACvB,OAAuB,EACvB,IAAY;QAEZ,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO;QACtC,MAAM,KAAK,GAAG,IAAA,gCAAe,EAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;QAChE,OAAO,IAAI,eAAO,CACd,KAAK,CAAC,GAAG,EACT,KAAK,CAAC,OAAO,EACb,gBAAgB,EAChB,WAAW,EACX,IAAI,EACJ,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,EACzB,IAAA,6BAAY,EAAC,IAAI,EAAE,IAAI,CAAC,aAAa,EAAE,CAAC,EACxC,EAAE,EACF,IAAI,CACP,CAAC;IACN,CAAC;CACJ;AA7DD,sDA6DC","sourcesContent":["import * as ts from 'typescript';\nimport { Binding } from './model';\nimport { relativeFile, resolveTokenKey } from './token-resolver';\n\n/** Canonical lazy client helpers retain the same DI token and singleton boundary. */\nexport class RuntimeClientBindings {\n collectNode(\n call: ts.CallExpression,\n checker: ts.TypeChecker,\n root: string,\n ): Binding | undefined {\n if (!this.frameworkCall(call, checker)) return;\n const callee = call.expression;\n if (!ts.isPropertyAccessExpression(callee)) return;\n const owner = checker.getTypeAtLocation(callee.expression).getSymbol()?.getName();\n if (\n (callee.name.text === 'bindRpc' && owner === 'RuntimeClients') ||\n (callee.name.text === 'bindPubSub' && owner === 'RuntimeTaskClients')\n ) {\n return this.binding(call, checker, root);\n }\n return undefined;\n }\n\n collectBrowser(\n call: ts.CallExpression,\n checker: ts.TypeChecker,\n root: string,\n ): Binding | undefined {\n if (!this.frameworkCall(call, checker)) return;\n let symbol = checker.getSymbolAtLocation(call.expression);\n if (symbol && (symbol.flags & ts.SymbolFlags.Alias) !== 0)\n symbol = checker.getAliasedSymbol(symbol);\n if (\n symbol?.getName() !== 'provideRpcClient' ||\n checker.getTypeAtLocation(call).getSymbol()?.getName() !== 'RpcClientProvider'\n )\n return;\n return this.binding(call, checker, root);\n }\n\n private frameworkCall(call: ts.CallExpression, checker: ts.TypeChecker): boolean {\n const declaration = checker.getResolvedSignature(call)?.declaration;\n if (declaration === undefined) return false;\n return /(?:\\/packages\\/(?:http|cloud)\\/|\\/node_modules\\/@webpieces\\/)(?:http-client-node|http-client-browser|cloudtasks-client)\\//.test(declaration.getSourceFile().fileName.replace(/\\\\/g, '/'));\n }\n\n private binding(\n call: ts.CallExpression,\n checker: ts.TypeChecker,\n root: string,\n ): Binding | undefined {\n if (call.arguments.length < 3) return;\n const token = resolveTokenKey(call.arguments[0], 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"]}
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; the browser\n * spelling `binder.bindExternal(Api, new UseClass(Vendor) | new UseExisting(Token))`\n * resolves through to the same implementation class (an alias walks into its target).\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 const method = this.binderMethod(call, checker, 'http-client-browser');\n if (method === 'createRpcClientAndBind') return this.client(call, checker, root);\n if (method === 'bindExternal') return this.external(call, checker, root);\n return undefined;\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] === undefined ? undefined : this.externalImpl(call.arguments[1], checker);\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 /** The browser `new UseClass(X)` / `new UseExisting(X)` names X; the Node form is X itself. */\n private externalImpl(expression: ts.Expression, checker: ts.TypeChecker): ts.Expression | undefined {\n if (!ts.isNewExpression(expression)) return expression;\n let recipe = checker.getSymbolAtLocation(expression.expression);\n if (recipe !== undefined && (recipe.flags & ts.SymbolFlags.Alias) !== 0) recipe = checker.getAliasedSymbol(recipe);\n if (recipe === undefined || !['UseClass', 'UseExisting'].includes(recipe.getName())) return undefined;\n return expression.arguments?.[0];\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":"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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 if (\n ts.isPropertyAccessExpression(expr) &&\n expr.name.text === 'identifier' &&\n checker.getTypeAtLocation(expr.expression).getSymbol()?.getName() === 'ClientToken'\n ) {\n return new TokenRef(resolveTokenKey(expr.expression, checker, workspaceRoot).key, display);\n }\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 if (\n ts.isNewExpression(init) &&\n checker.getTypeAtLocation(expr).getSymbol()?.getName() === 'ClientToken'\n ) {\n const identifier = init.arguments?.[0];\n if (identifier !== undefined) {\n const typedKey =\n symbolCallKey(identifier, declFile, name) ??\n resolveTokenKey(identifier, checker, workspaceRoot).key;\n return new TokenRef(typedKey, display);\n }\n }\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"]}
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 ['bindingModules', 'routingModules']) {
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 === 'bindingModules' ? 'binding' : 'routing');
47
- if (leaf.bindingModules.length + leaf.routingModules.length + leaf.wirings.length > 0)
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":";;;AAAA,0DAAgE;AAShE,+CAAgD;AAEhD,MAAa,0BAA0B;IAEf;IACA;IACA;IACA;IACA;IACA;IACA;IAPpB,YACoB,KAAa,EACb,GAAW,EACX,SAAgC,EAChC,SAAuB,EACvB,GAAW,EACX,MAAuB,EACvB,WAAoB;QANpB,UAAK,GAAL,KAAK,CAAQ;QACb,QAAG,GAAH,GAAG,CAAQ;QACX,cAAS,GAAT,SAAS,CAAuB;QAChC,cAAS,GAAT,SAAS,CAAc;QACvB,QAAG,GAAH,GAAG,CAAQ;QACX,WAAM,GAAN,MAAM,CAAiB;QACvB,gBAAW,GAAX,WAAW,CAAS;IACrC,CAAC;CACP;AAVD,gEAUC;AAED,+FAA+F;AAC/F,MAAa,sBAAsB;IACF;IAA7B,YAA6B,YAAqD;QAArD,iBAAY,GAAZ,YAAY,CAAyC;IAAG,CAAC;IAEtF,QAAQ,CAAC,OAAe;QACpB,MAAM,WAAW,GAAG,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;QACjD,IAAI,WAAW,CAAC,KAAK,KAAK,SAAS;YAAE,IAAI,CAAC,IAAI,CAAC,GAAG,OAAO,6BAA6B,CAAC,CAAC;QACxF,MAAM,IAAI,GAAG,YAAY,CAAC,OAAO,EAAE,WAAW,CAAC,KAAM,CAAC,CAAC;QACvD,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QACvC,MAAM,UAAU,GAAG,CAAC,IAAI,EAAE,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,KAAsB,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;QACrG,MAAM,MAAM,GAAiC,EAAE,CAAC;QAChD,KAAK,MAAM,OAAO,IAAI,CAAC,gBAAgB,EAAE,gBAAgB,CAAU,EAAE,CAAC;YAClE,KAAK,MAAM,CAAC,KAAK,EAAE,SAAS,CAAC,IAAI,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC;gBACpD,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;gBACvE,IAAI,KAAK,GAAG,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC;oBACrC,IAAI,CAAC,IAAI,CAAC,qCAAqC,SAAS,CAAC,OAAO,IAAI,SAAS,CAAC,YAAY,GAAG,CAAC,CAAC;gBACnG,KAAK,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC;oBAC3D,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;oBACjD,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,KAAK,gBAAgB,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;oBAC3F,IAAI,IAAI,CAAC,cAAc,CAAC,MAAM,GAAG,IAAI,CAAC,cAAc,CAAC,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC;wBACjF,IAAI,CAAC,IAAI,CAAC,6DAA6D,CAAC,CAAC;oBAC7E,MAAM,GAAG,GAAG,GAAG,OAAO,IAAI,WAAW,CAAC,KAAK,IAAI,KAAK,IAAI,SAAS,CAAC,OAAO,IAAI,SAAS,CAAC,YAAY,IAAI,OAAO,IAAI,WAAW,KAAK,QAAQ,CAAC,OAAO,IAAI,QAAQ,CAAC,YAAY,EAAE,CAAC;oBAC9K,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,oBAAoB,CAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC;gBACnE,CAAC;YACL,CAAC;QACL,CAAC;QACD,OAAO,MAAM,CAAC;IAClB,CAAC;IAEO,QAAQ,CAAC,SAA0B,EAAE,IAA0B;QACnE,MAAM,GAAG,GAAG,GAAG,SAAS,CAAC,OAAO,IAAI,SAAS,CAAC,YAAY,EAAE,CAAC;QAC7D,MAAM,WAAW,GAAG,IAAI,CAAC,cAAc,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QAC3D,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,OAAO,EAAE,SAAS,CAAC,YAAY,CAAC;YACvE,CAAC,CAAC,WAAW,CAAC,OAAO,CAAC,SAAS,CAAC,YAAY,CAAC;YAC7C,CAAC,CAAC,SAAS,CAAC;QAChB,IAAI,QAAQ,KAAK,SAAS;YAAE,IAAI,CAAC,IAAI,CAAC,2BAA2B,GAAG,GAAG,CAAC,CAAC;QACzE,IAAI,QAAQ,CAAC,IAAI,KAAK,IAAI;YACtB,IAAI,CAAC,IAAI,CAAC,GAAG,GAAG,cAAc,IAAI,WAAW,QAAQ,CAAC,IAAI,kDAAkD,CAAC,CAAC;QAClH,OAAO,QAAQ,CAAC;IACpB,CAAC;IAEO,OAAO,CAAC,KAAsB,EAAE,MAAuB;QAC3D,MAAM,OAAO,GAAmC,EAAE,CAAC;QACnD,MAAM,QAAQ,GAAgC,EAAE,CAAC;QACjD,KAAK,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC;YACtD,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACvD,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;YACzD,MAAM,QAAQ,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;YACtF,IAAI,QAAQ,KAAK,SAAS,IAAI,OAAO,QAAQ,KAAK,QAAQ;gBACtD,IAAI,CAAC,IAAI,CAAC,+BAA+B,IAAI,QAAQ,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,YAAY,GAAG,CAAC,CAAC;YACnG,QAAQ,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC;QAC9B,CAAC;QACD,OAAO,IAAI,6BAAe,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,YAAY,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;IACrF,CAAC;IAEO,oBAAoB,CACxB,QAAsB,EACtB,SAA0B,EAC1B,GAAW;QAEX,MAAM,MAAM,GAAiC,EAAE,CAAC;QAChD,KAAK,MAAM,YAAY,IAAI,QAAQ,CAAC,aAAa,EAAE,CAAC;YAChD,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,YAAY,EAAE,SAAS,CAAC;gBAAE,SAAS;YACvD,MAAM,MAAM,GACR,YAAY,CAAC,MAAM,KAAK,SAAS;gBAC7B,CAAC,CAAC,SAAS;gBACX,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,YAAY,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;YAC7D,IACI,MAAM,EAAE,IAAI,KAAK,SAAS;gBAC1B,MAAM,CAAC,QAAQ,KAAK,SAAS;gBAC7B,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,KAAK,YAAY,CAAC,QAAQ,CAAC,OAAO;oBACtD,MAAM,CAAC,QAAQ,CAAC,YAAY,KAAK,YAAY,CAAC,QAAQ,CAAC,YAAY,CAAC;gBAExE,IAAI,CAAC,IAAI,CACL,qBAAqB,MAAM,CAAC,QAAQ,CAAC,OAAO,IAAI,MAAM,CAAC,QAAQ,CAAC,YAAY,mBAAmB,YAAY,CAAC,QAAQ,CAAC,OAAO,IAAI,YAAY,CAAC,QAAQ,CAAC,YAAY,GAAG,CACxK,CAAC;YACN,IAAI,YAAY,CAAC,SAAS,KAAK,MAAM,IAAI,MAAM,KAAK,SAAS;gBACzD,IAAI,CAAC,IAAI,CAAC,sBAAsB,YAAY,CAAC,QAAQ,CAAC,YAAY,GAAG,CAAC,CAAC;YAC3E,MAAM,CAAC,IAAI,CACP,IAAI,0BAA0B,CAC1B,YAAY,CAAC,QAAQ,CAAC,OAAO,EAC7B,YAAY,CAAC,QAAQ,CAAC,YAAY,EAClC,YAAY,CAAC,SAAS,EACtB,YAAY,CAAC,SAAS,EACtB,GAAG,EACH,MAAM,EACN,YAAY,CAAC,MAAM,KAAK,SAAS;gBACjC,SAAS,CAAC,QAAQ,CAAC,YAAY,CAAC,MAAM,CAAC,KAAK,SAAS;gBACjD,CAAC,CAAC,GAAG,SAAS,CAAC,OAAO,IAAI,SAAS,CAAC,YAAY,IAAI,YAAY,CAAC,MAAM,EAAE;gBACzE,CAAC,CAAC,SAAS,CAClB,CACJ,CAAC;QACN,CAAC;QACD,OAAO,MAAM,CAAC;IAClB,CAAC;IAEO,SAAS,CAAC,YAAgC,EAAE,SAA0B;QAC1E,IAAI,YAAY,CAAC,MAAM,KAAK,SAAS;YAAE,OAAO,IAAI,CAAC;QACnD,MAAM,QAAQ,GAAG,SAAS,CAAC,QAAQ,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;QACzD,IAAI,QAAQ,KAAK,SAAS;YACtB,IAAI,CAAC,IAAI,CACL,2BAA2B,YAAY,CAAC,MAAM,OAAO,SAAS,CAAC,OAAO,IAAI,SAAS,CAAC,YAAY,GAAG,CACtG,CAAC;QACN,OAAO,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,IAAI,CAAC;IACvD,CAAC;IAEO,aAAa,CAAC,MAAsB,EAAE,SAA0B;QACpE,IAAI,MAAM,CAAC,IAAI,KAAK,WAAW;YAAE,OAAO,MAAM,CAAC;QAC/C,MAAM,QAAQ,GAAG,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QACrD,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,CAAC,IAAI,KAAK,WAAW;YACvD,IAAI,CAAC,IAAI,CACL,+BAA+B,MAAM,CAAC,SAAS,OAAO,SAAS,CAAC,OAAO,IAAI,SAAS,CAAC,YAAY,GAAG,CACvG,CAAC;QACN,OAAO,QAAS,CAAC;IACrB,CAAC;IAEO,cAAc,CAAC,OAAe;QAClC,MAAM,WAAW,GAAG,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACnD,IAAI,WAAW,KAAK,SAAS;YACzB,IAAI,CAAC,IAAI,CAAC,0CAA0C,OAAO,GAAG,CAAC,CAAC;QACpE,OAAO,WAAY,CAAC;IACxB,CAAC;IAEO,IAAI,CAAC,OAAe;QACxB,MAAM,IAAI,4BAAa,CAAC,+BAA+B,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE;YACpF,IAAI,qBAAM,CACN,qFAAqF,EACrF,IAAI,CACP;SACJ,CAAC,CAAC;IACP,CAAC;CACJ;AAlID,wDAkIC;AAED,uGAAuG;AACvG,SAAS,YAAY,CACjB,OAAe,EACf,YAAoB,EACpB,UAA0C,EAAE,EAC5C,WAAwC,EAAE;IAE1C,OAAO,IAAI,6BAAe,CAAC,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;AACzE,CAAC","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] === undefined ? '' : `, ${call.arguments[2].getText()}`;
79
- const replacement = task
80
- ? `new RuntimeTaskClients(options).bindPubSub(${token.getText()}, ${api}, ${target});`
81
- : provider
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":"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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]?.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"]}
@@ -4,6 +4,7 @@ export declare class RuntimeDeclarationCodec {
4
4
  decode(text: string, expectedProject: string): RuntimeDeclaration;
5
5
  private parse;
6
6
  private exported;
7
+ private renamed;
7
8
  private relationship;
8
9
  private selection;
9
10
  private target;
@@ -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.bindingModules.length > 0 || exported.routingModules.length > 0))
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
- const exported = this.record(value, ['kind', 'relationships', 'bindingModules', 'routingModules', 'wirings']);
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['bindingModules']).map((value) => this.selection(value)), this.array(exported['routingModules']).map((value) => this.selection(value)), this.array(exported['wirings']).map((value) => this.selection(value)));
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) {