@webpieces/nx-webpieces-rules 0.3.314 → 0.3.320

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webpieces/nx-webpieces-rules",
3
- "version": "0.3.314",
3
+ "version": "0.3.320",
4
4
  "description": "Nx-specific webpieces validation rules and graph tooling. Bundles all @webpieces rule packages with Nx graph validators and an inference plugin.",
5
5
  "type": "commonjs",
6
6
  "main": "./src/index.js",
@@ -21,11 +21,11 @@
21
21
  "README.md"
22
22
  ],
23
23
  "dependencies": {
24
- "@webpieces/ai-hook-rules": "0.3.314",
25
- "@webpieces/code-rules": "0.3.314",
26
- "@webpieces/eslint-rules": "0.3.314",
27
- "@webpieces/pr-gate": "0.3.314",
28
- "@webpieces/rules-config": "0.3.314",
24
+ "@webpieces/ai-hook-rules": "0.3.320",
25
+ "@webpieces/code-rules": "0.3.320",
26
+ "@webpieces/eslint-rules": "0.3.320",
27
+ "@webpieces/pr-gate": "0.3.320",
28
+ "@webpieces/rules-config": "0.3.320",
29
29
  "madge": "8.0.0"
30
30
  },
31
31
  "peerDependencies": {
@@ -105,7 +105,7 @@ export declare abstract class DiDesignBuilder {
105
105
  */
106
106
  protected classNode(cls: ts.ClassDeclaration, scopeHint?: DiScope, apiType?: string): string;
107
107
  private claimId;
108
- /** Scope from the class's own decorator/module binding, if any. */
108
+ /** Scope from the class's own decorator/module binding, or undefined if it has none. */
109
109
  private classScope;
110
110
  /**
111
111
  * Leaf box for a constant/dynamic binding. B0: the box is labeled by the
@@ -128,6 +128,17 @@ export declare abstract class DiDesignBuilder {
128
128
  private processInjection;
129
129
  /** Inversify `@inject`/`@multiInject` and Angular `inject()`/`@Inject`/bare token. */
130
130
  private processTokenInjection;
131
+ /**
132
+ * `@inject(TOKEN) p: Provider<X>` draws `Consumer -> X`, NOT `Consumer -> Provider -> X`.
133
+ *
134
+ * A Provider is DI plumbing: it exists because `Provider<T>` is erased at runtime and needs a
135
+ * token. Nobody reading the design wants a box for it. What they want to see is that the
136
+ * consumer gets Xs — and because X's own binding supplies the scope, a transient X renders as
137
+ * the stacked "one instance per get()" box.
138
+ *
139
+ * Returns true when the token was a registered provider and the edge has been drawn.
140
+ */
141
+ private processProviderInjection;
131
142
  private bindingTarget;
132
143
  /** Inversify bare typed param — resolve the declared type directly to a class. */
133
144
  private processTypeInjection;
@@ -37,6 +37,7 @@ const DI_DECORATORS = new Set([
37
37
  'provideSingletonAs',
38
38
  'provideFrameworkSingleton',
39
39
  'provideFrameworkSingletonAs',
40
+ 'provideFrameworkTransient',
40
41
  'injectable',
41
42
  ]);
42
43
  class ParamInjection {
@@ -207,7 +208,7 @@ class DiDesignBuilder {
207
208
  * differs from the impl class name it becomes the node's `api` (rendered as the
208
209
  * primary box label, with the impl class in parens). Set on first reach.
209
210
  */
210
- classNode(cls, scopeHint = 'unknown', apiType = '') {
211
+ classNode(cls, scopeHint = 'transient', apiType = '') {
211
212
  const existing = this.classIds.get(cls);
212
213
  if (existing)
213
214
  return existing;
@@ -215,8 +216,9 @@ class DiDesignBuilder {
215
216
  const file = (0, token_resolver_1.relativeFile)(this.workspaceRoot, cls.getSourceFile());
216
217
  const id = this.claimId(className, file);
217
218
  this.classIds.set(cls, id);
218
- const declaredScope = this.classScope(cls);
219
- const scope = declaredScope !== 'unknown' ? declaredScope : scopeHint;
219
+ // The class's OWN binding wins; otherwise the scope of the module binding it was reached
220
+ // through; otherwise transient (inversify's default scope).
221
+ const scope = this.classScope(cls) ?? scopeHint;
220
222
  // A class from a published package (resolved to a .d.ts under node_modules)
221
223
  // is a boundary leaf: shown so the dependency is visible, but never expanded
222
224
  // (walkClass stops there). Roots are always project classes, so this never
@@ -246,14 +248,13 @@ class DiDesignBuilder {
246
248
  this.usedIds.add(id);
247
249
  return id;
248
250
  }
249
- /** Scope from the class's own decorator/module binding, if any. */
251
+ /** Scope from the class's own decorator/module binding, or undefined if it has none. */
250
252
  classScope(cls) {
251
253
  const token = (0, token_resolver_1.classTokenKey)(cls, this.workspaceRoot);
252
254
  for (const binding of this.table.lookup(token.key)) {
253
- if (binding.scope !== 'unknown')
254
- return binding.scope;
255
+ return binding.scope;
255
256
  }
256
- return 'unknown';
257
+ return undefined;
257
258
  }
258
259
  /**
259
260
  * Leaf box for a constant/dynamic binding. B0: the box is labeled by the
@@ -266,11 +267,17 @@ class DiDesignBuilder {
266
267
  const existing = this.leafIds.get(binding);
267
268
  if (existing)
268
269
  return existing;
269
- const detail = kind === 'dynamic' ? `${binding.tokenDisplay} (dynamic)` : binding.valueText;
270
+ const detail = kind === 'api'
271
+ ? `${binding.tokenDisplay} (api client)`
272
+ : kind === 'dynamic'
273
+ ? `${binding.tokenDisplay} (dynamic)`
274
+ : binding.valueText;
270
275
  const className = paramType !== '' ? paramType : detail !== '' ? detail : binding.tokenDisplay;
271
276
  const id = this.claimId(className, binding.file);
272
277
  this.leafIds.set(binding, id);
273
278
  this.design.nodes.push(new model_1.DiNode(id, className, kind, binding.scope, binding.file, 0, detail));
279
+ // An `api` boundary is a service/network edge — stop here, exactly like an
280
+ // external class. Only a plain dynamic leaf fans out to its factory deps.
274
281
  if (kind === 'dynamic')
275
282
  this.expandFactoryDeps(id, binding);
276
283
  return id;
@@ -304,7 +311,7 @@ class DiDesignBuilder {
304
311
  return existing;
305
312
  const id = this.claimId(className, file);
306
313
  this.unresolvedIds.set(key, id);
307
- this.design.nodes.push(new model_1.DiNode(id, className, 'unresolved', 'unknown', file, 0, detail !== className ? detail : ''));
314
+ this.design.nodes.push(new model_1.DiNode(id, className, 'unresolved', 'transient', file, 0, detail !== className ? detail : ''));
308
315
  this.design.unresolved.push(detail !== '' ? detail : className);
309
316
  return id;
310
317
  }
@@ -338,6 +345,9 @@ class DiDesignBuilder {
338
345
  return;
339
346
  const token = (0, token_resolver_1.resolveTokenKey)(expr, this.checker, this.workspaceRoot);
340
347
  const kind = injection.multi ? 'multiInject' : 'token';
348
+ if (this.processProviderInjection(fromId, token, injection)) {
349
+ return;
350
+ }
341
351
  const bindings = this.table.lookup(token.key);
342
352
  if (bindings.length > 0) {
343
353
  for (const binding of bindings) {
@@ -355,7 +365,7 @@ class DiDesignBuilder {
355
365
  const target = (0, bindings_1.resolveClassDeclaration)(expr, this.checker);
356
366
  if (target) {
357
367
  const classToken = (0, token_resolver_1.classTokenKey)(target, this.workspaceRoot);
358
- const toId = this.classNode(target, 'unknown', injection.paramType);
368
+ const toId = this.classNode(target, 'transient', injection.paramType);
359
369
  this.walkClass(target);
360
370
  this.design.edges.push(new model_1.DiEdge(fromId, toId, 'type', classToken.display, classToken.key, injection.paramName, injection.paramType));
361
371
  return;
@@ -366,6 +376,28 @@ class DiDesignBuilder {
366
376
  const toId = this.unresolvedNode(label, file, token.display);
367
377
  this.design.edges.push(new model_1.DiEdge(fromId, toId, kind, token.display, token.key, injection.paramName, injection.paramType));
368
378
  }
379
+ /**
380
+ * `@inject(TOKEN) p: Provider<X>` draws `Consumer -> X`, NOT `Consumer -> Provider -> X`.
381
+ *
382
+ * A Provider is DI plumbing: it exists because `Provider<T>` is erased at runtime and needs a
383
+ * token. Nobody reading the design wants a box for it. What they want to see is that the
384
+ * consumer gets Xs — and because X's own binding supplies the scope, a transient X renders as
385
+ * the stacked "one instance per get()" box.
386
+ *
387
+ * Returns true when the token was a registered provider and the edge has been drawn.
388
+ */
389
+ processProviderInjection(fromId, token, injection) {
390
+ const target = this.table.providerTarget(token.key);
391
+ if (!target) {
392
+ return false;
393
+ }
394
+ // apiType '' so the box reads `X`, not the declared `Provider<X>`.
395
+ const toId = this.classNode(target);
396
+ this.walkClass(target);
397
+ const targetToken = (0, token_resolver_1.classTokenKey)(target, this.workspaceRoot);
398
+ this.design.edges.push(new model_1.DiEdge(fromId, toId, 'type', targetToken.display, targetToken.key, injection.paramName, injection.paramType));
399
+ return true;
400
+ }
369
401
  bindingTarget(binding, paramType) {
370
402
  if (binding.implClass) {
371
403
  const toId = this.classNode(binding.implClass, binding.scope, paramType);
@@ -375,7 +407,7 @@ class DiDesignBuilder {
375
407
  if (binding.kind === 'toConstantValue')
376
408
  return this.leafNode(binding, 'constant', paramType);
377
409
  if (binding.kind === 'toDynamicValue')
378
- return this.leafNode(binding, 'dynamic', paramType);
410
+ return this.leafNode(binding, binding.isApiBoundary ? 'api' : 'dynamic', paramType);
379
411
  // .to(X) where X did not resolve to a class declaration.
380
412
  const detail = binding.valueText !== '' ? binding.valueText : binding.tokenDisplay;
381
413
  const label = paramType !== '' ? paramType : detail;
@@ -1 +1 @@
1
- {"version":3,"file":"analyzer.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/nx-webpieces-rules/src/lib/di-graph/analyzer.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * DI Graph Analyzer (pass 2)\n *\n * Walks constructor injection from a project's root classes down to leaves:\n *\n * - @inject(TOKEN) params → token lookup in the binding table → bound impl\n * - @multiInject(TOKEN) → fan-out edge to EVERY binding of that token\n * - bare typed params → checker resolves the type to a class (inject-by-type)\n * - toConstantValue/toDynamicValue bindings → leaf nodes, no recursion\n * - unresolvable tokens/types → kind \"unresolved\" nodes (generation never fails)\n *\n * Roots: @DocumentDesign() classes when the project has any; otherwise every\n * DI-registered class in the project that no other project class injects\n * (the tops of the local DAG).\n */\n\nimport * as ts from 'typescript';\nimport * as path from 'path';\nimport { Binding, DiDesign, DiEdge, DiGraph, DiNode, DiNodeKind, DiScope } from './model';\nimport {\n BindingTable,\n classDecorators,\n collectBindings,\n decoratorCall,\n decoratorName,\n isExternalClass,\n resolveClassDeclaration,\n} from './bindings';\nimport { classTokenKey, relativeFile, resolveTokenKey } from './token-resolver';\n\nconst DI_DECORATORS = new Set([\n 'provideSingleton',\n 'provideTransient',\n 'provideSingletonAs',\n 'provideFrameworkSingleton',\n 'provideFrameworkSingletonAs',\n 'injectable',\n]);\n\nexport class ParamInjection {\n expr: ts.Expression | null;\n multi: boolean;\n optional: boolean;\n unmanaged: boolean;\n\n constructor(expr: ts.Expression | null, multi: boolean, optional: boolean, unmanaged: boolean) {\n this.expr = expr;\n this.multi = multi;\n this.optional = optional;\n this.unmanaged = unmanaged;\n }\n}\n\nexport function readParamDecorators(param: ts.ParameterDeclaration): ParamInjection {\n let expr: ts.Expression | null = null;\n let multi = false;\n let optional = false;\n let unmanaged = false;\n for (const decorator of ts.getDecorators(param) ?? []) {\n const name = decoratorName(decorator);\n const call = decoratorCall(decorator);\n if (name === 'inject' && call?.arguments[0]) {\n expr = call.arguments[0];\n } else if (name === 'multiInject' && call?.arguments[0]) {\n expr = call.arguments[0];\n multi = true;\n } else if (name === 'optional') {\n optional = true;\n } else if (name === 'unmanaged') {\n unmanaged = true;\n }\n }\n return new ParamInjection(expr, multi, optional, unmanaged);\n}\n\nfunction hasDecoratorNamed(cls: ts.ClassDeclaration, names: Set<string>): boolean {\n for (const decorator of classDecorators(cls)) {\n const name = decoratorName(decorator);\n if (name && names.has(name)) return true;\n }\n return false;\n}\n\n/** A `@DocumentDesign` class — the explicit DI-design root (server controller or designed-lib impl). */\nexport function isDocumentDesignClass(cls: ts.ClassDeclaration): boolean {\n return hasDecoratorNamed(cls, new Set(['DocumentDesign']));\n}\n\n/**\n * The node kind for a `@DocumentDesign` root, chosen by the analyzer's root mode\n * rather than the decorator (a single `@DocumentDesign` marks both). `server` →\n * `controller`, `designed-lib` → `apiImplementation`.\n */\nexport type DiRootMode = 'controller' | 'apiImplementation';\n\nexport function rootKindForMode(mode: DiRootMode): DiNodeKind {\n return mode === 'apiImplementation' ? 'apiImplementation' : 'controller';\n}\n\nfunction isDiRegisteredClass(cls: ts.ClassDeclaration): boolean {\n return hasDecoratorNamed(cls, DI_DECORATORS);\n}\n\nexport function findConstructor(cls: ts.ClassDeclaration): ts.ConstructorDeclaration | null {\n for (const member of cls.members) {\n if (ts.isConstructorDeclaration(member) && member.body) return member;\n if (ts.isConstructorDeclaration(member)) return member;\n }\n return null;\n}\n\n/** All class declarations in files under the project root. */\nexport function projectClasses(\n program: ts.Program,\n workspaceRoot: string,\n projectRoot: string,\n): ts.ClassDeclaration[] {\n const prefix = projectRoot.endsWith('/') ? projectRoot : projectRoot + '/';\n const classes: ts.ClassDeclaration[] = [];\n for (const sourceFile of program.getSourceFiles()) {\n if (sourceFile.isDeclarationFile) continue;\n const rel = relativeFile(workspaceRoot, sourceFile);\n if (!rel.startsWith(prefix)) continue;\n const visit = (node: ts.Node): void => {\n if (ts.isClassDeclaration(node) && node.name) classes.push(node);\n ts.forEachChild(node, visit);\n };\n visit(sourceFile);\n }\n return classes;\n}\n\n/**\n * One normalized injection site, framework-agnostic — produced by a builder's\n * `collectInjections(cls)` hook and processed by the shared base. Inversify\n * emits `token`/`type` from constructor params; Angular emits `angularToken`\n * from constructor params AND `inject()` field initializers.\n *\n * Modes:\n * - `token` Inversify `@inject`/`@multiInject`: table lookup; an unbound\n * token becomes an `unresolved` node (no class fallback).\n * - `type` Inversify bare typed param: resolve the declared TYPE to a\n * class (inject-by-type); no table lookup.\n * - `angularToken` Angular `inject(T)` / `@Inject(T)` / bare typed ctor param:\n * table lookup FIRST (provider table), then fall back to\n * resolving the token expression as a class, else unresolved.\n */\nexport class Injection {\n mode: 'token' | 'type' | 'angularToken';\n /** Token/type expression (modes `token`/`angularToken`, or the type identifier for `type`). */\n expr: ts.Expression | ts.Identifier | null;\n multi: boolean;\n optional: boolean;\n paramName: string;\n paramType: string;\n\n constructor(\n mode: 'token' | 'type' | 'angularToken',\n expr: ts.Expression | ts.Identifier | null,\n paramName: string,\n paramType: string,\n multi = false,\n optional = false,\n ) {\n this.mode = mode;\n this.expr = expr;\n this.paramName = paramName;\n this.paramType = paramType;\n this.multi = multi;\n this.optional = optional;\n }\n}\n\n/**\n * Builds ONE self-contained `DiDesign` for a single root. A fresh instance is\n * created per root so its maps (visited/classIds/usedIds/...) are scoped to\n * that root's tree — a dependency shared by two roots is therefore walked\n * (and duplicated) into each root's design, not hidden under whichever root\n * reached it first.\n *\n * Framework-agnostic base: subclasses implement {@link collectInjections} (and\n * override {@link rootKindOf} for Angular components); everything else — node\n * ids, leaf/unresolved labeling, token→binding resolution, factory-dep edges,\n * level assignment — is shared so Inversify and Angular render identically.\n */\nexport abstract class DiDesignBuilder {\n protected readonly checker: ts.TypeChecker;\n protected readonly table: BindingTable;\n protected readonly workspaceRoot: string;\n protected readonly design: DiDesign;\n private readonly classIds = new Map<ts.ClassDeclaration, string>();\n private readonly leafIds = new Map<Binding, string>();\n private readonly unresolvedIds = new Map<string, string>();\n private readonly usedIds = new Set<string>();\n private readonly visited = new Set<ts.ClassDeclaration>();\n protected rootClass: ts.ClassDeclaration | null = null;\n\n constructor(checker: ts.TypeChecker, table: BindingTable, workspaceRoot: string, design: DiDesign) {\n this.checker = checker;\n this.table = table;\n this.workspaceRoot = workspaceRoot;\n this.design = design;\n }\n\n /** Collect the injection sites for one class (constructor params, field inject(), ...). */\n protected abstract collectInjections(cls: ts.ClassDeclaration): Injection[];\n\n /**\n * Node kind for a root/reached class. Default: the ROOT box takes the design's\n * `rootKind` (`controller`/`apiImplementation`, chosen by root mode); every\n * reached dependency is a plain `class`. Angular overrides this to render\n * component classes as `component`.\n */\n protected rootKindOf(cls: ts.ClassDeclaration): DiNodeKind {\n return cls === this.rootClass ? this.design.rootKind : 'class';\n }\n\n addRoot(cls: ts.ClassDeclaration): void {\n this.rootClass = cls;\n const id = this.classNode(cls);\n this.design.root = id;\n this.walkClass(cls);\n }\n\n /**\n * Register (or fetch) the node for a class, returning its stable id.\n * `scopeHint` carries the scope of the module binding the class was reached\n * through (e.g. bind(TOKEN).to(X).inSingletonScope() where X is not self-bound).\n * `apiType` is the declared param/field type the class was injected as; when it\n * differs from the impl class name it becomes the node's `api` (rendered as the\n * primary box label, with the impl class in parens). Set on first reach.\n */\n protected classNode(cls: ts.ClassDeclaration, scopeHint: DiScope = 'unknown', apiType = ''): string {\n const existing = this.classIds.get(cls);\n if (existing) return existing;\n\n const className = cls.name ? cls.name.text : '<anonymous>';\n const file = relativeFile(this.workspaceRoot, cls.getSourceFile());\n const id = this.claimId(className, file);\n this.classIds.set(cls, id);\n\n const declaredScope = this.classScope(cls);\n const scope = declaredScope !== 'unknown' ? declaredScope : scopeHint;\n // A class from a published package (resolved to a .d.ts under node_modules)\n // is a boundary leaf: shown so the dependency is visible, but never expanded\n // (walkClass stops there). Roots are always project classes, so this never\n // relabels a root.\n const kind: DiNodeKind = isExternalClass(cls) ? 'external' : this.rootKindOf(cls);\n const node = new DiNode(id, className, kind, scope, file);\n // Injected AS an API/interface that resolves to a differently-named impl —\n // record the contract (strip a trailing `[]` from multiInject array params).\n const api = apiType.replace(/\\[\\]$/, '');\n if (api !== '' && api !== className) node.api = api;\n this.design.nodes.push(node);\n return id;\n }\n\n private claimId(preferred: string, file: string): string {\n if (!this.usedIds.has(preferred)) {\n this.usedIds.add(preferred);\n return preferred;\n }\n const disambiguated = `${preferred}@${path.posix.dirname(file)}`;\n let id = disambiguated;\n let n = 2;\n while (this.usedIds.has(id)) {\n id = `${disambiguated}~${n}`;\n n++;\n }\n this.usedIds.add(id);\n return id;\n }\n\n /** Scope from the class's own decorator/module binding, if any. */\n private classScope(cls: ts.ClassDeclaration): DiScope {\n const token = classTokenKey(cls, this.workspaceRoot);\n for (const binding of this.table.lookup(token.key)) {\n if (binding.scope !== 'unknown') return binding.scope;\n }\n return 'unknown';\n }\n\n /**\n * Leaf box for a constant/dynamic binding. B0: the box is labeled by the\n * DECLARED param TYPE (e.g. `FirestoreConfig`, `ClientConfig`) — the DI\n * contract — while the bound expression (`buildConfigFromEnv(...)` /\n * `TOKEN (dynamic)`) is kept as `detail`. A dynamic leaf also fans out to\n * each of its `useFactory` `deps` (Angular; empty for Inversify).\n */\n private leafNode(binding: Binding, kind: DiNodeKind, paramType: string): string {\n const existing = this.leafIds.get(binding);\n if (existing) return existing;\n\n const detail = kind === 'dynamic' ? `${binding.tokenDisplay} (dynamic)` : binding.valueText;\n const className = paramType !== '' ? paramType : detail !== '' ? detail : binding.tokenDisplay;\n const id = this.claimId(className, binding.file);\n this.leafIds.set(binding, id);\n this.design.nodes.push(new DiNode(id, className, kind, binding.scope, binding.file, 0, detail));\n if (kind === 'dynamic') this.expandFactoryDeps(id, binding);\n return id;\n }\n\n /** Edges from a `useFactory` leaf to each declared `deps: [...]` token (Angular). */\n private expandFactoryDeps(leafId: string, binding: Binding): void {\n for (const dep of binding.factoryDeps) {\n const bindings = this.table.lookup(dep.key);\n if (bindings.length > 0) {\n for (const depBinding of bindings) {\n // The dep token IS the declared type — label the box with it.\n const toId = this.bindingTarget(depBinding, dep.display);\n this.design.edges.push(new DiEdge(leafId, toId, 'type', dep.display, dep.key, dep.display, dep.display));\n }\n } else {\n const toId = this.unresolvedNode(dep.display, binding.file, '');\n this.design.edges.push(new DiEdge(leafId, toId, 'type', dep.display, dep.key, dep.display, dep.display));\n }\n }\n }\n\n /**\n * `unresolved` placeholder box. B0: labeled by the declared param TYPE\n * (`className`) with the resolving token expression kept as `detail` (and\n * surfaced in `design.unresolved` for diagnostics).\n */\n private unresolvedNode(className: string, file: string, detail: string): string {\n const key = `${className}|${detail}|${file}`;\n const existing = this.unresolvedIds.get(key);\n if (existing) return existing;\n\n const id = this.claimId(className, file);\n this.unresolvedIds.set(key, id);\n this.design.nodes.push(new DiNode(id, className, 'unresolved', 'unknown', file, 0, detail !== className ? detail : ''));\n this.design.unresolved.push(detail !== '' ? detail : className);\n return id;\n }\n\n protected walkClass(cls: ts.ClassDeclaration): void {\n if (this.visited.has(cls)) return;\n this.visited.add(cls);\n\n // External boundary: the node is already registered by the caller's\n // classNode() (kind 'external'); we intentionally do NOT descend into a\n // published package's internals (e.g. an SDK Client's ClientOptions/impl).\n if (isExternalClass(cls)) return;\n\n const fromId = this.classNode(cls);\n for (const injection of this.collectInjections(cls)) {\n this.processInjection(fromId, cls, injection);\n }\n }\n\n /** Resolve one injection to a node and record the edge(s). Never throws. */\n private processInjection(fromId: string, cls: ts.ClassDeclaration, injection: Injection): void {\n if (injection.mode === 'type') {\n this.processTypeInjection(fromId, cls, injection);\n } else {\n this.processTokenInjection(fromId, cls, injection);\n }\n }\n\n /** Inversify `@inject`/`@multiInject` and Angular `inject()`/`@Inject`/bare token. */\n private processTokenInjection(fromId: string, cls: ts.ClassDeclaration, injection: Injection): void {\n const expr = injection.expr;\n if (!expr) return;\n const token = resolveTokenKey(expr, this.checker, this.workspaceRoot);\n const kind = injection.multi ? 'multiInject' : 'token';\n const bindings = this.table.lookup(token.key);\n\n if (bindings.length > 0) {\n for (const binding of bindings) {\n const toId = this.bindingTarget(binding, injection.paramType);\n this.design.edges.push(\n new DiEdge(fromId, toId, kind, token.display, token.key, injection.paramName, injection.paramType),\n );\n }\n return;\n }\n\n // @multiInject @optional with zero bindings is legal — no edge, no error.\n if (injection.multi && injection.optional) return;\n\n // Angular: a token with no explicit provider may still be a bare @Injectable\n // class — resolve the token expression as a class and inject it by type.\n if (injection.mode === 'angularToken') {\n const target = resolveClassDeclaration(expr, this.checker);\n if (target) {\n const classToken = classTokenKey(target, this.workspaceRoot);\n const toId = this.classNode(target, 'unknown', injection.paramType);\n this.walkClass(target);\n this.design.edges.push(\n new DiEdge(fromId, toId, 'type', classToken.display, classToken.key, injection.paramName, injection.paramType),\n );\n return;\n }\n }\n\n const file = relativeFile(this.workspaceRoot, cls.getSourceFile());\n const label = injection.paramType !== '' ? injection.paramType : token.display;\n const toId = this.unresolvedNode(label, file, token.display);\n this.design.edges.push(\n new DiEdge(fromId, toId, kind, token.display, token.key, injection.paramName, injection.paramType),\n );\n }\n\n private bindingTarget(binding: Binding, paramType: string): string {\n if (binding.implClass) {\n const toId = this.classNode(binding.implClass, binding.scope, paramType);\n this.walkClass(binding.implClass);\n return toId;\n }\n if (binding.kind === 'toConstantValue') return this.leafNode(binding, 'constant', paramType);\n if (binding.kind === 'toDynamicValue') return this.leafNode(binding, 'dynamic', paramType);\n // .to(X) where X did not resolve to a class declaration.\n const detail = binding.valueText !== '' ? binding.valueText : binding.tokenDisplay;\n const label = paramType !== '' ? paramType : detail;\n return this.unresolvedNode(label, binding.file, detail);\n }\n\n /** Inversify bare typed param — resolve the declared type directly to a class. */\n private processTypeInjection(fromId: string, cls: ts.ClassDeclaration, injection: Injection): void {\n const typeRef = injection.expr && ts.isIdentifier(injection.expr) ? injection.expr : null;\n const target = typeRef ? resolveClassDeclaration(typeRef, this.checker) : null;\n\n if (target) {\n const token = classTokenKey(target, this.workspaceRoot);\n const toId = this.classNode(target);\n this.walkClass(target);\n this.design.edges.push(\n new DiEdge(fromId, toId, 'type', token.display, token.key, injection.paramName, injection.paramType),\n );\n return;\n }\n\n // Bare param whose type is not a resolvable class (interface, primitive, etc.).\n const file = relativeFile(this.workspaceRoot, cls.getSourceFile());\n const label = injection.paramType !== '' ? injection.paramType : injection.paramName;\n const toId = this.unresolvedNode(label, file, '');\n this.design.edges.push(\n new DiEdge(fromId, toId, 'type', injection.paramType, `type:${injection.paramType}`, injection.paramName, injection.paramType),\n );\n }\n}\n\n/**\n * Inversify builder: injection sites are constructor params — `@inject`/\n * `@multiInject` tokens or bare typed (inject-by-type) params.\n */\nexport class InversifyDesignBuilder extends DiDesignBuilder {\n protected collectInjections(cls: ts.ClassDeclaration): Injection[] {\n const ctor = findConstructor(cls);\n if (!ctor) return [];\n\n const injections: Injection[] = [];\n for (const param of ctor.parameters) {\n const decorated = readParamDecorators(param);\n if (decorated.unmanaged) continue;\n\n const paramName = ts.isIdentifier(param.name) ? param.name.text : param.name.getText();\n const paramType = param.type ? param.type.getText() : '';\n\n if (decorated.expr) {\n injections.push(\n new Injection('token', decorated.expr, paramName, paramType, decorated.multi, decorated.optional),\n );\n } else {\n const typeRef =\n param.type && ts.isTypeReferenceNode(param.type) && ts.isIdentifier(param.type.typeName)\n ? param.type.typeName\n : null;\n injections.push(new Injection('type', typeRef, paramName, paramType));\n }\n }\n return injections;\n }\n}\n\nexport function byClassName(a: ts.ClassDeclaration, b: ts.ClassDeclaration): number {\n const nameA = a.name ? a.name.text : '';\n const nameB = b.name ? b.name.text : '';\n if (nameA !== nameB) return nameA < nameB ? -1 : 1;\n return a.getSourceFile().fileName < b.getSourceFile().fileName ? -1 : 1;\n}\n\n/**\n * Library-project roots: DI-registered classes in the project that no other\n * project class injects (tops of the local DAG).\n */\nfunction findLibraryRoots(\n classes: ts.ClassDeclaration[],\n checker: ts.TypeChecker,\n table: BindingTable,\n workspaceRoot: string,\n): ts.ClassDeclaration[] {\n const diClasses = classes.filter((cls: ts.ClassDeclaration) => isDiRegisteredClass(cls));\n const injected = new Set<ts.ClassDeclaration>();\n\n for (const cls of diClasses) {\n const ctor = findConstructor(cls);\n for (const param of ctor?.parameters ?? []) {\n const injection = readParamDecorators(param);\n if (injection.unmanaged) continue;\n if (injection.expr) {\n const token = resolveTokenKey(injection.expr, checker, workspaceRoot);\n for (const binding of table.lookup(token.key)) {\n if (binding.implClass) injected.add(binding.implClass);\n }\n } else if (param.type && ts.isTypeReferenceNode(param.type) && ts.isIdentifier(param.type.typeName)) {\n const target = resolveClassDeclaration(param.type.typeName, checker);\n if (target) injected.add(target);\n }\n }\n }\n\n return diClasses.filter((cls: ts.ClassDeclaration) => !injected.has(cls));\n}\n\n/**\n * Assign each node its LONGEST-path depth from the design's root (root = level\n * 0, its direct injections = level 1, ...) and record the deepest level. A node\n * reached from multiple parents takes its DEEPEST depth, so it always sits below\n * everything that depends on it (a dependency is never on the same or a shallower\n * level than its dependent — e.g. a config injected by both a level-2 service and\n * a level-3 client lands at level 4, one below that client). Levels are computed\n * by edge relaxation bounded by the reachable node count, which terminates even\n * if the DI graph contains a cycle; the root is pinned at 0.\n */\nexport function assignLevels(design: DiDesign): void {\n const outgoing = new Map<string, string[]>();\n for (const e of design.edges) {\n const list = outgoing.get(e.from) ?? [];\n list.push(e.to);\n outgoing.set(e.from, list);\n }\n\n // Nodes reachable from the root — only these get a level; the rest fall back\n // to 0 below, matching the previous behaviour for disconnected nodes.\n const reachable = new Set<string>();\n const queue = [design.root];\n for (let i = 0; i < queue.length; i++) {\n const id = queue[i];\n if (reachable.has(id)) continue;\n reachable.add(id);\n for (const to of outgoing.get(id) ?? []) {\n if (!reachable.has(to)) queue.push(to);\n }\n }\n\n const levelById = new Map<string, number>();\n for (const id of reachable) levelById.set(id, 0);\n // Bellman-Ford-style longest-path relaxation. |reachable| passes suffice for\n // any acyclic graph; the pass count also bounds work if a cycle exists.\n for (let pass = 0; pass < reachable.size; pass++) {\n let changed = false;\n for (const e of design.edges) {\n if (!reachable.has(e.from) || e.to === design.root) continue;\n const candidate = (levelById.get(e.from) ?? 0) + 1;\n if (candidate > (levelById.get(e.to) ?? 0)) {\n levelById.set(e.to, candidate);\n changed = true;\n }\n }\n if (!changed) break;\n }\n\n let maxLevel = 0;\n for (const node of design.nodes) {\n node.level = levelById.get(node.id) ?? 0;\n if (node.level > maxLevel) maxLevel = node.level;\n }\n design.maxLevel = maxLevel;\n}\n\n/**\n * Build one self-contained downward design tree for a single root class, using\n * the builder produced by `makeBuilder` (Inversify or Angular). `rootKind` is\n * the node kind for the root box (`controller`/`component`/`class`).\n */\nexport function buildDesign(\n root: ts.ClassDeclaration,\n rootKind: DiNodeKind,\n workspaceRoot: string,\n makeBuilder: (design: DiDesign) => DiDesignBuilder,\n): DiDesign {\n const className = root.name ? root.name.text : '<anonymous>';\n const file = relativeFile(workspaceRoot, root.getSourceFile());\n const design = new DiDesign(className, rootKind, file);\n makeBuilder(design).addRoot(root);\n assignLevels(design);\n return design;\n}\n\n/**\n * Build the full Inversify DI graph for one project: one self-contained\n * `DiDesign` per @DocumentDesign root. `projectRoot` is workspace-relative.\n *\n * Both `rootMode`s root on @DocumentDesign classes; the mode only sets the root\n * box kind (`'controller'` for server, `'apiImplementation'` for designed-lib).\n * `includeLibraryRoots` (default false) lets a project with NO @DocumentDesign\n * class fall back to top-of-DAG DI classes (rendered as plain `class` roots).\n */\nexport function buildDiGraph(\n program: ts.Program,\n workspaceRoot: string,\n projectRoot: string,\n projectName: string,\n includeLibraryRoots = false,\n rootMode: DiRootMode = 'controller',\n): DiGraph {\n const checker = program.getTypeChecker();\n const table = collectBindings(program, checker, workspaceRoot);\n const graph = new DiGraph(projectName);\n\n const classes = projectClasses(program, workspaceRoot, projectRoot);\n const designRoots = classes.filter((cls: ts.ClassDeclaration) => isDocumentDesignClass(cls));\n // Both modes root on @DocumentDesign classes. In controller mode a project with\n // no explicit design root may fall back to top-of-DAG DI classes (those render\n // as plain `class` roots, preserving prior behaviour).\n const roots =\n designRoots.length > 0\n ? designRoots\n : rootMode === 'controller' && includeLibraryRoots\n ? findLibraryRoots(classes, checker, table, workspaceRoot)\n : [];\n\n for (const root of [...roots].sort(byClassName)) {\n const rootKind: DiNodeKind = isDocumentDesignClass(root) ? rootKindForMode(rootMode) : 'class';\n graph.designs.push(\n buildDesign(\n root,\n rootKind,\n workspaceRoot,\n (design: DiDesign) => new InversifyDesignBuilder(checker, table, workspaceRoot, design),\n ),\n );\n }\n\n return graph;\n}\n"]}
1
+ {"version":3,"file":"analyzer.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/nx-webpieces-rules/src/lib/di-graph/analyzer.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * DI Graph Analyzer (pass 2)\n *\n * Walks constructor injection from a project's root classes down to leaves:\n *\n * - @inject(TOKEN) params → token lookup in the binding table → bound impl\n * - @multiInject(TOKEN) → fan-out edge to EVERY binding of that token\n * - bare typed params → checker resolves the type to a class (inject-by-type)\n * - toConstantValue/toDynamicValue bindings → leaf nodes, no recursion\n * - unresolvable tokens/types → kind \"unresolved\" nodes (generation never fails)\n *\n * Roots: @DocumentDesign() classes when the project has any; otherwise every\n * DI-registered class in the project that no other project class injects\n * (the tops of the local DAG).\n */\n\nimport * as ts from 'typescript';\nimport * as path from 'path';\nimport { Binding, DiDesign, DiEdge, DiGraph, DiNode, DiNodeKind, DiScope, TokenRef } from './model';\nimport {\n BindingTable,\n classDecorators,\n collectBindings,\n decoratorCall,\n decoratorName,\n isExternalClass,\n resolveClassDeclaration,\n} from './bindings';\nimport { classTokenKey, relativeFile, resolveTokenKey } from './token-resolver';\n\nconst DI_DECORATORS = new Set([\n 'provideSingleton',\n 'provideTransient',\n 'provideSingletonAs',\n 'provideFrameworkSingleton',\n 'provideFrameworkSingletonAs',\n 'provideFrameworkTransient',\n 'injectable',\n]);\n\nexport class ParamInjection {\n expr: ts.Expression | null;\n multi: boolean;\n optional: boolean;\n unmanaged: boolean;\n\n constructor(expr: ts.Expression | null, multi: boolean, optional: boolean, unmanaged: boolean) {\n this.expr = expr;\n this.multi = multi;\n this.optional = optional;\n this.unmanaged = unmanaged;\n }\n}\n\nexport function readParamDecorators(param: ts.ParameterDeclaration): ParamInjection {\n let expr: ts.Expression | null = null;\n let multi = false;\n let optional = false;\n let unmanaged = false;\n for (const decorator of ts.getDecorators(param) ?? []) {\n const name = decoratorName(decorator);\n const call = decoratorCall(decorator);\n if (name === 'inject' && call?.arguments[0]) {\n expr = call.arguments[0];\n } else if (name === 'multiInject' && call?.arguments[0]) {\n expr = call.arguments[0];\n multi = true;\n } else if (name === 'optional') {\n optional = true;\n } else if (name === 'unmanaged') {\n unmanaged = true;\n }\n }\n return new ParamInjection(expr, multi, optional, unmanaged);\n}\n\nfunction hasDecoratorNamed(cls: ts.ClassDeclaration, names: Set<string>): boolean {\n for (const decorator of classDecorators(cls)) {\n const name = decoratorName(decorator);\n if (name && names.has(name)) return true;\n }\n return false;\n}\n\n/** A `@DocumentDesign` class — the explicit DI-design root (server controller or designed-lib impl). */\nexport function isDocumentDesignClass(cls: ts.ClassDeclaration): boolean {\n return hasDecoratorNamed(cls, new Set(['DocumentDesign']));\n}\n\n/**\n * The node kind for a `@DocumentDesign` root, chosen by the analyzer's root mode\n * rather than the decorator (a single `@DocumentDesign` marks both). `server` →\n * `controller`, `designed-lib` → `apiImplementation`.\n */\nexport type DiRootMode = 'controller' | 'apiImplementation';\n\nexport function rootKindForMode(mode: DiRootMode): DiNodeKind {\n return mode === 'apiImplementation' ? 'apiImplementation' : 'controller';\n}\n\nfunction isDiRegisteredClass(cls: ts.ClassDeclaration): boolean {\n return hasDecoratorNamed(cls, DI_DECORATORS);\n}\n\nexport function findConstructor(cls: ts.ClassDeclaration): ts.ConstructorDeclaration | null {\n for (const member of cls.members) {\n if (ts.isConstructorDeclaration(member) && member.body) return member;\n if (ts.isConstructorDeclaration(member)) return member;\n }\n return null;\n}\n\n/** All class declarations in files under the project root. */\nexport function projectClasses(\n program: ts.Program,\n workspaceRoot: string,\n projectRoot: string,\n): ts.ClassDeclaration[] {\n const prefix = projectRoot.endsWith('/') ? projectRoot : projectRoot + '/';\n const classes: ts.ClassDeclaration[] = [];\n for (const sourceFile of program.getSourceFiles()) {\n if (sourceFile.isDeclarationFile) continue;\n const rel = relativeFile(workspaceRoot, sourceFile);\n if (!rel.startsWith(prefix)) continue;\n const visit = (node: ts.Node): void => {\n if (ts.isClassDeclaration(node) && node.name) classes.push(node);\n ts.forEachChild(node, visit);\n };\n visit(sourceFile);\n }\n return classes;\n}\n\n/**\n * One normalized injection site, framework-agnostic — produced by a builder's\n * `collectInjections(cls)` hook and processed by the shared base. Inversify\n * emits `token`/`type` from constructor params; Angular emits `angularToken`\n * from constructor params AND `inject()` field initializers.\n *\n * Modes:\n * - `token` Inversify `@inject`/`@multiInject`: table lookup; an unbound\n * token becomes an `unresolved` node (no class fallback).\n * - `type` Inversify bare typed param: resolve the declared TYPE to a\n * class (inject-by-type); no table lookup.\n * - `angularToken` Angular `inject(T)` / `@Inject(T)` / bare typed ctor param:\n * table lookup FIRST (provider table), then fall back to\n * resolving the token expression as a class, else unresolved.\n */\nexport class Injection {\n mode: 'token' | 'type' | 'angularToken';\n /** Token/type expression (modes `token`/`angularToken`, or the type identifier for `type`). */\n expr: ts.Expression | ts.Identifier | null;\n multi: boolean;\n optional: boolean;\n paramName: string;\n paramType: string;\n\n constructor(\n mode: 'token' | 'type' | 'angularToken',\n expr: ts.Expression | ts.Identifier | null,\n paramName: string,\n paramType: string,\n multi = false,\n optional = false,\n ) {\n this.mode = mode;\n this.expr = expr;\n this.paramName = paramName;\n this.paramType = paramType;\n this.multi = multi;\n this.optional = optional;\n }\n}\n\n/**\n * Builds ONE self-contained `DiDesign` for a single root. A fresh instance is\n * created per root so its maps (visited/classIds/usedIds/...) are scoped to\n * that root's tree — a dependency shared by two roots is therefore walked\n * (and duplicated) into each root's design, not hidden under whichever root\n * reached it first.\n *\n * Framework-agnostic base: subclasses implement {@link collectInjections} (and\n * override {@link rootKindOf} for Angular components); everything else — node\n * ids, leaf/unresolved labeling, token→binding resolution, factory-dep edges,\n * level assignment — is shared so Inversify and Angular render identically.\n */\nexport abstract class DiDesignBuilder {\n protected readonly checker: ts.TypeChecker;\n protected readonly table: BindingTable;\n protected readonly workspaceRoot: string;\n protected readonly design: DiDesign;\n private readonly classIds = new Map<ts.ClassDeclaration, string>();\n private readonly leafIds = new Map<Binding, string>();\n private readonly unresolvedIds = new Map<string, string>();\n private readonly usedIds = new Set<string>();\n private readonly visited = new Set<ts.ClassDeclaration>();\n protected rootClass: ts.ClassDeclaration | null = null;\n\n constructor(checker: ts.TypeChecker, table: BindingTable, workspaceRoot: string, design: DiDesign) {\n this.checker = checker;\n this.table = table;\n this.workspaceRoot = workspaceRoot;\n this.design = design;\n }\n\n /** Collect the injection sites for one class (constructor params, field inject(), ...). */\n protected abstract collectInjections(cls: ts.ClassDeclaration): Injection[];\n\n /**\n * Node kind for a root/reached class. Default: the ROOT box takes the design's\n * `rootKind` (`controller`/`apiImplementation`, chosen by root mode); every\n * reached dependency is a plain `class`. Angular overrides this to render\n * component classes as `component`.\n */\n protected rootKindOf(cls: ts.ClassDeclaration): DiNodeKind {\n return cls === this.rootClass ? this.design.rootKind : 'class';\n }\n\n addRoot(cls: ts.ClassDeclaration): void {\n this.rootClass = cls;\n const id = this.classNode(cls);\n this.design.root = id;\n this.walkClass(cls);\n }\n\n /**\n * Register (or fetch) the node for a class, returning its stable id.\n * `scopeHint` carries the scope of the module binding the class was reached\n * through (e.g. bind(TOKEN).to(X).inSingletonScope() where X is not self-bound).\n * `apiType` is the declared param/field type the class was injected as; when it\n * differs from the impl class name it becomes the node's `api` (rendered as the\n * primary box label, with the impl class in parens). Set on first reach.\n */\n protected classNode(cls: ts.ClassDeclaration, scopeHint: DiScope = 'transient', apiType = ''): string {\n const existing = this.classIds.get(cls);\n if (existing) return existing;\n\n const className = cls.name ? cls.name.text : '<anonymous>';\n const file = relativeFile(this.workspaceRoot, cls.getSourceFile());\n const id = this.claimId(className, file);\n this.classIds.set(cls, id);\n\n // The class's OWN binding wins; otherwise the scope of the module binding it was reached\n // through; otherwise transient (inversify's default scope).\n const scope = this.classScope(cls) ?? scopeHint;\n // A class from a published package (resolved to a .d.ts under node_modules)\n // is a boundary leaf: shown so the dependency is visible, but never expanded\n // (walkClass stops there). Roots are always project classes, so this never\n // relabels a root.\n const kind: DiNodeKind = isExternalClass(cls) ? 'external' : this.rootKindOf(cls);\n const node = new DiNode(id, className, kind, scope, file);\n // Injected AS an API/interface that resolves to a differently-named impl —\n // record the contract (strip a trailing `[]` from multiInject array params).\n const api = apiType.replace(/\\[\\]$/, '');\n if (api !== '' && api !== className) node.api = api;\n this.design.nodes.push(node);\n return id;\n }\n\n private claimId(preferred: string, file: string): string {\n if (!this.usedIds.has(preferred)) {\n this.usedIds.add(preferred);\n return preferred;\n }\n const disambiguated = `${preferred}@${path.posix.dirname(file)}`;\n let id = disambiguated;\n let n = 2;\n while (this.usedIds.has(id)) {\n id = `${disambiguated}~${n}`;\n n++;\n }\n this.usedIds.add(id);\n return id;\n }\n\n /** Scope from the class's own decorator/module binding, or undefined if it has none. */\n private classScope(cls: ts.ClassDeclaration): DiScope | undefined {\n const token = classTokenKey(cls, this.workspaceRoot);\n for (const binding of this.table.lookup(token.key)) {\n return binding.scope;\n }\n return undefined;\n }\n\n /**\n * Leaf box for a constant/dynamic binding. B0: the box is labeled by the\n * DECLARED param TYPE (e.g. `FirestoreConfig`, `ClientConfig`) — the DI\n * contract — while the bound expression (`buildConfigFromEnv(...)` /\n * `TOKEN (dynamic)`) is kept as `detail`. A dynamic leaf also fans out to\n * each of its `useFactory` `deps` (Angular; empty for Inversify).\n */\n private leafNode(binding: Binding, kind: DiNodeKind, paramType: string): string {\n const existing = this.leafIds.get(binding);\n if (existing) return existing;\n\n const detail =\n kind === 'api'\n ? `${binding.tokenDisplay} (api client)`\n : kind === 'dynamic'\n ? `${binding.tokenDisplay} (dynamic)`\n : binding.valueText;\n const className = paramType !== '' ? paramType : detail !== '' ? detail : binding.tokenDisplay;\n const id = this.claimId(className, binding.file);\n this.leafIds.set(binding, id);\n this.design.nodes.push(new DiNode(id, className, kind, binding.scope, binding.file, 0, detail));\n // An `api` boundary is a service/network edge — stop here, exactly like an\n // external class. Only a plain dynamic leaf fans out to its factory deps.\n if (kind === 'dynamic') this.expandFactoryDeps(id, binding);\n return id;\n }\n\n /** Edges from a `useFactory` leaf to each declared `deps: [...]` token (Angular). */\n private expandFactoryDeps(leafId: string, binding: Binding): void {\n for (const dep of binding.factoryDeps) {\n const bindings = this.table.lookup(dep.key);\n if (bindings.length > 0) {\n for (const depBinding of bindings) {\n // The dep token IS the declared type — label the box with it.\n const toId = this.bindingTarget(depBinding, dep.display);\n this.design.edges.push(new DiEdge(leafId, toId, 'type', dep.display, dep.key, dep.display, dep.display));\n }\n } else {\n const toId = this.unresolvedNode(dep.display, binding.file, '');\n this.design.edges.push(new DiEdge(leafId, toId, 'type', dep.display, dep.key, dep.display, dep.display));\n }\n }\n }\n\n /**\n * `unresolved` placeholder box. B0: labeled by the declared param TYPE\n * (`className`) with the resolving token expression kept as `detail` (and\n * surfaced in `design.unresolved` for diagnostics).\n */\n private unresolvedNode(className: string, file: string, detail: string): string {\n const key = `${className}|${detail}|${file}`;\n const existing = this.unresolvedIds.get(key);\n if (existing) return existing;\n\n const id = this.claimId(className, file);\n this.unresolvedIds.set(key, id);\n this.design.nodes.push(new DiNode(id, className, 'unresolved', 'transient', file, 0, detail !== className ? detail : ''));\n this.design.unresolved.push(detail !== '' ? detail : className);\n return id;\n }\n\n protected walkClass(cls: ts.ClassDeclaration): void {\n if (this.visited.has(cls)) return;\n this.visited.add(cls);\n\n // External boundary: the node is already registered by the caller's\n // classNode() (kind 'external'); we intentionally do NOT descend into a\n // published package's internals (e.g. an SDK Client's ClientOptions/impl).\n if (isExternalClass(cls)) return;\n\n const fromId = this.classNode(cls);\n for (const injection of this.collectInjections(cls)) {\n this.processInjection(fromId, cls, injection);\n }\n }\n\n /** Resolve one injection to a node and record the edge(s). Never throws. */\n private processInjection(fromId: string, cls: ts.ClassDeclaration, injection: Injection): void {\n if (injection.mode === 'type') {\n this.processTypeInjection(fromId, cls, injection);\n } else {\n this.processTokenInjection(fromId, cls, injection);\n }\n }\n\n /** Inversify `@inject`/`@multiInject` and Angular `inject()`/`@Inject`/bare token. */\n private processTokenInjection(fromId: string, cls: ts.ClassDeclaration, injection: Injection): void {\n const expr = injection.expr;\n if (!expr) return;\n const token = resolveTokenKey(expr, this.checker, this.workspaceRoot);\n const kind = injection.multi ? 'multiInject' : 'token';\n\n if (this.processProviderInjection(fromId, token, injection)) {\n return;\n }\n\n const bindings = this.table.lookup(token.key);\n\n if (bindings.length > 0) {\n for (const binding of bindings) {\n const toId = this.bindingTarget(binding, injection.paramType);\n this.design.edges.push(\n new DiEdge(fromId, toId, kind, token.display, token.key, injection.paramName, injection.paramType),\n );\n }\n return;\n }\n\n // @multiInject @optional with zero bindings is legal — no edge, no error.\n if (injection.multi && injection.optional) return;\n\n // Angular: a token with no explicit provider may still be a bare @Injectable\n // class — resolve the token expression as a class and inject it by type.\n if (injection.mode === 'angularToken') {\n const target = resolveClassDeclaration(expr, this.checker);\n if (target) {\n const classToken = classTokenKey(target, this.workspaceRoot);\n const toId = this.classNode(target, 'transient', injection.paramType);\n this.walkClass(target);\n this.design.edges.push(\n new DiEdge(fromId, toId, 'type', classToken.display, classToken.key, injection.paramName, injection.paramType),\n );\n return;\n }\n }\n\n const file = relativeFile(this.workspaceRoot, cls.getSourceFile());\n const label = injection.paramType !== '' ? injection.paramType : token.display;\n const toId = this.unresolvedNode(label, file, token.display);\n this.design.edges.push(\n new DiEdge(fromId, toId, kind, token.display, token.key, injection.paramName, injection.paramType),\n );\n }\n\n /**\n * `@inject(TOKEN) p: Provider<X>` draws `Consumer -> X`, NOT `Consumer -> Provider -> X`.\n *\n * A Provider is DI plumbing: it exists because `Provider<T>` is erased at runtime and needs a\n * token. Nobody reading the design wants a box for it. What they want to see is that the\n * consumer gets Xs — and because X's own binding supplies the scope, a transient X renders as\n * the stacked \"one instance per get()\" box.\n *\n * Returns true when the token was a registered provider and the edge has been drawn.\n */\n private processProviderInjection(fromId: string, token: TokenRef, injection: Injection): boolean {\n const target = this.table.providerTarget(token.key);\n if (!target) {\n return false;\n }\n\n // apiType '' so the box reads `X`, not the declared `Provider<X>`.\n const toId = this.classNode(target);\n this.walkClass(target);\n const targetToken = classTokenKey(target, this.workspaceRoot);\n this.design.edges.push(\n new DiEdge(fromId, toId, 'type', targetToken.display, targetToken.key, injection.paramName, injection.paramType),\n );\n return true;\n }\n\n private bindingTarget(binding: Binding, paramType: string): string {\n if (binding.implClass) {\n const toId = this.classNode(binding.implClass, binding.scope, paramType);\n this.walkClass(binding.implClass);\n return toId;\n }\n if (binding.kind === 'toConstantValue') return this.leafNode(binding, 'constant', paramType);\n if (binding.kind === 'toDynamicValue')\n return this.leafNode(binding, binding.isApiBoundary ? 'api' : 'dynamic', paramType);\n // .to(X) where X did not resolve to a class declaration.\n const detail = binding.valueText !== '' ? binding.valueText : binding.tokenDisplay;\n const label = paramType !== '' ? paramType : detail;\n return this.unresolvedNode(label, binding.file, detail);\n }\n\n /** Inversify bare typed param — resolve the declared type directly to a class. */\n private processTypeInjection(fromId: string, cls: ts.ClassDeclaration, injection: Injection): void {\n const typeRef = injection.expr && ts.isIdentifier(injection.expr) ? injection.expr : null;\n const target = typeRef ? resolveClassDeclaration(typeRef, this.checker) : null;\n\n if (target) {\n const token = classTokenKey(target, this.workspaceRoot);\n const toId = this.classNode(target);\n this.walkClass(target);\n this.design.edges.push(\n new DiEdge(fromId, toId, 'type', token.display, token.key, injection.paramName, injection.paramType),\n );\n return;\n }\n\n // Bare param whose type is not a resolvable class (interface, primitive, etc.).\n const file = relativeFile(this.workspaceRoot, cls.getSourceFile());\n const label = injection.paramType !== '' ? injection.paramType : injection.paramName;\n const toId = this.unresolvedNode(label, file, '');\n this.design.edges.push(\n new DiEdge(fromId, toId, 'type', injection.paramType, `type:${injection.paramType}`, injection.paramName, injection.paramType),\n );\n }\n}\n\n/**\n * Inversify builder: injection sites are constructor params — `@inject`/\n * `@multiInject` tokens or bare typed (inject-by-type) params.\n */\nexport class InversifyDesignBuilder extends DiDesignBuilder {\n protected collectInjections(cls: ts.ClassDeclaration): Injection[] {\n const ctor = findConstructor(cls);\n if (!ctor) return [];\n\n const injections: Injection[] = [];\n for (const param of ctor.parameters) {\n const decorated = readParamDecorators(param);\n if (decorated.unmanaged) continue;\n\n const paramName = ts.isIdentifier(param.name) ? param.name.text : param.name.getText();\n const paramType = param.type ? param.type.getText() : '';\n\n if (decorated.expr) {\n injections.push(\n new Injection('token', decorated.expr, paramName, paramType, decorated.multi, decorated.optional),\n );\n } else {\n const typeRef =\n param.type && ts.isTypeReferenceNode(param.type) && ts.isIdentifier(param.type.typeName)\n ? param.type.typeName\n : null;\n injections.push(new Injection('type', typeRef, paramName, paramType));\n }\n }\n return injections;\n }\n}\n\nexport function byClassName(a: ts.ClassDeclaration, b: ts.ClassDeclaration): number {\n const nameA = a.name ? a.name.text : '';\n const nameB = b.name ? b.name.text : '';\n if (nameA !== nameB) return nameA < nameB ? -1 : 1;\n return a.getSourceFile().fileName < b.getSourceFile().fileName ? -1 : 1;\n}\n\n/**\n * Library-project roots: DI-registered classes in the project that no other\n * project class injects (tops of the local DAG).\n */\nfunction findLibraryRoots(\n classes: ts.ClassDeclaration[],\n checker: ts.TypeChecker,\n table: BindingTable,\n workspaceRoot: string,\n): ts.ClassDeclaration[] {\n const diClasses = classes.filter((cls: ts.ClassDeclaration) => isDiRegisteredClass(cls));\n const injected = new Set<ts.ClassDeclaration>();\n\n for (const cls of diClasses) {\n const ctor = findConstructor(cls);\n for (const param of ctor?.parameters ?? []) {\n const injection = readParamDecorators(param);\n if (injection.unmanaged) continue;\n if (injection.expr) {\n const token = resolveTokenKey(injection.expr, checker, workspaceRoot);\n for (const binding of table.lookup(token.key)) {\n if (binding.implClass) injected.add(binding.implClass);\n }\n } else if (param.type && ts.isTypeReferenceNode(param.type) && ts.isIdentifier(param.type.typeName)) {\n const target = resolveClassDeclaration(param.type.typeName, checker);\n if (target) injected.add(target);\n }\n }\n }\n\n return diClasses.filter((cls: ts.ClassDeclaration) => !injected.has(cls));\n}\n\n/**\n * Assign each node its LONGEST-path depth from the design's root (root = level\n * 0, its direct injections = level 1, ...) and record the deepest level. A node\n * reached from multiple parents takes its DEEPEST depth, so it always sits below\n * everything that depends on it (a dependency is never on the same or a shallower\n * level than its dependent — e.g. a config injected by both a level-2 service and\n * a level-3 client lands at level 4, one below that client). Levels are computed\n * by edge relaxation bounded by the reachable node count, which terminates even\n * if the DI graph contains a cycle; the root is pinned at 0.\n */\nexport function assignLevels(design: DiDesign): void {\n const outgoing = new Map<string, string[]>();\n for (const e of design.edges) {\n const list = outgoing.get(e.from) ?? [];\n list.push(e.to);\n outgoing.set(e.from, list);\n }\n\n // Nodes reachable from the root — only these get a level; the rest fall back\n // to 0 below, matching the previous behaviour for disconnected nodes.\n const reachable = new Set<string>();\n const queue = [design.root];\n for (let i = 0; i < queue.length; i++) {\n const id = queue[i];\n if (reachable.has(id)) continue;\n reachable.add(id);\n for (const to of outgoing.get(id) ?? []) {\n if (!reachable.has(to)) queue.push(to);\n }\n }\n\n const levelById = new Map<string, number>();\n for (const id of reachable) levelById.set(id, 0);\n // Bellman-Ford-style longest-path relaxation. |reachable| passes suffice for\n // any acyclic graph; the pass count also bounds work if a cycle exists.\n for (let pass = 0; pass < reachable.size; pass++) {\n let changed = false;\n for (const e of design.edges) {\n if (!reachable.has(e.from) || e.to === design.root) continue;\n const candidate = (levelById.get(e.from) ?? 0) + 1;\n if (candidate > (levelById.get(e.to) ?? 0)) {\n levelById.set(e.to, candidate);\n changed = true;\n }\n }\n if (!changed) break;\n }\n\n let maxLevel = 0;\n for (const node of design.nodes) {\n node.level = levelById.get(node.id) ?? 0;\n if (node.level > maxLevel) maxLevel = node.level;\n }\n design.maxLevel = maxLevel;\n}\n\n/**\n * Build one self-contained downward design tree for a single root class, using\n * the builder produced by `makeBuilder` (Inversify or Angular). `rootKind` is\n * the node kind for the root box (`controller`/`component`/`class`).\n */\nexport function buildDesign(\n root: ts.ClassDeclaration,\n rootKind: DiNodeKind,\n workspaceRoot: string,\n makeBuilder: (design: DiDesign) => DiDesignBuilder,\n): DiDesign {\n const className = root.name ? root.name.text : '<anonymous>';\n const file = relativeFile(workspaceRoot, root.getSourceFile());\n const design = new DiDesign(className, rootKind, file);\n makeBuilder(design).addRoot(root);\n assignLevels(design);\n return design;\n}\n\n/**\n * Build the full Inversify DI graph for one project: one self-contained\n * `DiDesign` per @DocumentDesign root. `projectRoot` is workspace-relative.\n *\n * Both `rootMode`s root on @DocumentDesign classes; the mode only sets the root\n * box kind (`'controller'` for server, `'apiImplementation'` for designed-lib).\n * `includeLibraryRoots` (default false) lets a project with NO @DocumentDesign\n * class fall back to top-of-DAG DI classes (rendered as plain `class` roots).\n */\nexport function buildDiGraph(\n program: ts.Program,\n workspaceRoot: string,\n projectRoot: string,\n projectName: string,\n includeLibraryRoots = false,\n rootMode: DiRootMode = 'controller',\n): DiGraph {\n const checker = program.getTypeChecker();\n const table = collectBindings(program, checker, workspaceRoot);\n const graph = new DiGraph(projectName);\n\n const classes = projectClasses(program, workspaceRoot, projectRoot);\n const designRoots = classes.filter((cls: ts.ClassDeclaration) => isDocumentDesignClass(cls));\n // Both modes root on @DocumentDesign classes. In controller mode a project with\n // no explicit design root may fall back to top-of-DAG DI classes (those render\n // as plain `class` roots, preserving prior behaviour).\n const roots =\n designRoots.length > 0\n ? designRoots\n : rootMode === 'controller' && includeLibraryRoots\n ? findLibraryRoots(classes, checker, table, workspaceRoot)\n : [];\n\n for (const root of [...roots].sort(byClassName)) {\n const rootKind: DiNodeKind = isDocumentDesignClass(root) ? rootKindForMode(rootMode) : 'class';\n graph.designs.push(\n buildDesign(\n root,\n rootKind,\n workspaceRoot,\n (design: DiDesign) => new InversifyDesignBuilder(checker, table, workspaceRoot, design),\n ),\n );\n }\n\n return graph;\n}\n"]}
@@ -97,7 +97,8 @@ function collectProviderObject(obj, checker, workspaceRoot, file, table) {
97
97
  }
98
98
  if (useFactory) {
99
99
  const deps = collectDeps(props.get('deps'), checker, workspaceRoot);
100
- table.add(new model_1.Binding(token.key, token.display, 'toDynamicValue', ANGULAR_SCOPE, null, firstLine(useFactory.getText()), file, deps));
100
+ const isApiBoundary = (0, bindings_1.isApiClientBoundary)(useFactory, checker);
101
+ table.add(new model_1.Binding(token.key, token.display, 'toDynamicValue', ANGULAR_SCOPE, null, firstLine(useFactory.getText()), file, deps, isApiBoundary));
101
102
  return;
102
103
  }
103
104
  if (useValue) {
@@ -1 +1 @@
1
- {"version":3,"file":"angular-providers.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/nx-webpieces-rules/src/lib/di-graph/angular-providers.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Angular Provider Table (pass 1, Angular flavor)\n *\n * The Angular analog of `bindings.ts` (Inversify): scans the program and maps\n * Angular's provider forms onto the SAME token-keyed {@link BindingTable} the\n * shared walker consumes, so `angular-analyzer.ts` reuses every downstream\n * mechanism (leaf labeling, factory-dep edges, unresolved handling).\n *\n * Provider sources (v1 flat global table — component-scoped shadowing is an\n * accepted approximation):\n * - Any `providers: [...]` array (ApplicationConfig, `@Component`, `@Directive`)\n * - `@Injectable({ providedIn: 'root' | 'platform' | 'any' })` self-registration\n *\n * Provider forms per array element:\n * - bare class `Foo` → to/self binding (implClass=Foo)\n * - `{ provide, useClass }` → to binding (implClass)\n * - `{ provide, useValue }` → toConstantValue leaf\n * - `{ provide, useFactory, deps: [A, B] }` → toDynamicValue leaf + factoryDeps\n * - `{ provide, useExisting }` → alias → target impl class\n * - `multi: true` → multiple bindings per token (fan-out)\n *\n * Framework-internal `provideXxx()` calls (`provideRouter`,\n * `provideZoneChangeDetection`, ...) have no DI leaves and are skipped.\n */\n\nimport * as ts from 'typescript';\nimport { Binding, DiScope, TokenRef } from './model';\nimport { BindingTable, classDecorators, decoratorCall, decoratorName, resolveClassDeclaration } from './bindings';\nimport { classTokenKey, relativeFile, resolveTokenKey } from './token-resolver';\n\n// Angular injector-scoped providers are effectively singletons at their scope.\nconst ANGULAR_SCOPE: DiScope = 'singleton';\n\nfunction isAnalyzableFile(sourceFile: ts.SourceFile): boolean {\n if (sourceFile.isDeclarationFile) return false;\n if (sourceFile.fileName.includes('/node_modules/')) return false;\n return true;\n}\n\n/** First line of an expression's source text, truncated for leaf labels. */\nfunction firstLine(text: string): string {\n const line = text.split('\\n')[0].trim();\n return line.length > 60 ? line.slice(0, 57) + '...' : line;\n}\n\n/** Pull `{ name: value }` properties out of an object literal into a map. */\nfunction objectProps(obj: ts.ObjectLiteralExpression): Map<string, ts.Expression> {\n const props = new Map<string, ts.Expression>();\n for (const prop of obj.properties) {\n if (ts.isPropertyAssignment(prop) && (ts.isIdentifier(prop.name) || ts.isStringLiteralLike(prop.name))) {\n props.set(prop.name.text, prop.initializer);\n }\n }\n return props;\n}\n\n/** Resolve each `deps: [A, B]` element to a token reference for factory-dep edges. */\nfunction collectDeps(depsExpr: ts.Expression | undefined, checker: ts.TypeChecker, workspaceRoot: string): TokenRef[] {\n if (!depsExpr || !ts.isArrayLiteralExpression(depsExpr)) return [];\n const deps: TokenRef[] = [];\n for (const element of depsExpr.elements) {\n // Simple token form (`EnvironmentConfig`); the decorated array form\n // (`[new Optional(), Token]`) is out of scope for v1.\n if (ts.isIdentifier(element) || ts.isPropertyAccessExpression(element)) {\n const cls = resolveClassDeclaration(element, checker);\n deps.push(cls ? classTokenKey(cls, workspaceRoot) : resolveTokenKey(element, checker, workspaceRoot));\n }\n }\n return deps;\n}\n\n/** Record one provider-object literal (`{ provide, useX }`) as a binding. */\nfunction collectProviderObject(\n obj: ts.ObjectLiteralExpression,\n checker: ts.TypeChecker,\n workspaceRoot: string,\n file: string,\n table: BindingTable,\n): void {\n const props = objectProps(obj);\n const provideExpr = props.get('provide');\n if (!provideExpr) return;\n\n const provideClass = resolveClassDeclaration(provideExpr, checker);\n const token = provideClass\n ? classTokenKey(provideClass, workspaceRoot)\n : resolveTokenKey(provideExpr, checker, workspaceRoot);\n\n const useClass = props.get('useClass');\n const useValue = props.get('useValue');\n const useFactory = props.get('useFactory');\n const useExisting = props.get('useExisting');\n\n if (useClass) {\n const impl = resolveClassDeclaration(useClass, checker);\n table.add(new Binding(token.key, token.display, 'to', ANGULAR_SCOPE, impl, useClass.getText(), file));\n return;\n }\n if (useExisting) {\n // Alias: T resolves to whatever `useExisting` points at — resolve through\n // to the target impl class so the walk continues into its dependencies.\n const impl = resolveClassDeclaration(useExisting, checker);\n table.add(new Binding(token.key, token.display, 'to', ANGULAR_SCOPE, impl, useExisting.getText(), file));\n return;\n }\n if (useFactory) {\n const deps = collectDeps(props.get('deps'), checker, workspaceRoot);\n table.add(\n new Binding(token.key, token.display, 'toDynamicValue', ANGULAR_SCOPE, null, firstLine(useFactory.getText()), file, deps),\n );\n return;\n }\n if (useValue) {\n table.add(\n new Binding(token.key, token.display, 'toConstantValue', ANGULAR_SCOPE, null, firstLine(useValue.getText()), file),\n );\n return;\n }\n // `{ provide: T }` with no recipe — treat the token itself as the impl class.\n if (provideClass) {\n table.add(new Binding(token.key, token.display, 'to', ANGULAR_SCOPE, provideClass, provideExpr.getText(), file));\n }\n}\n\n/** Record one element of a `providers: [...]` array. */\nfunction collectProviderElement(\n element: ts.Expression,\n checker: ts.TypeChecker,\n workspaceRoot: string,\n file: string,\n table: BindingTable,\n): void {\n // Framework-internal `provideRouter(...)` / `provideZoneChangeDetection(...)`.\n if (ts.isCallExpression(element)) return;\n\n // Bare class provider: `providers: [MyService]` → useClass: MyService.\n if (ts.isIdentifier(element) || ts.isPropertyAccessExpression(element)) {\n const cls = resolveClassDeclaration(element, checker);\n if (cls) {\n const token = classTokenKey(cls, workspaceRoot);\n table.add(new Binding(token.key, token.display, 'to', ANGULAR_SCOPE, cls, element.getText(), file));\n }\n return;\n }\n\n if (ts.isObjectLiteralExpression(element)) {\n collectProviderObject(element, checker, workspaceRoot, file, table);\n }\n}\n\n/** `@Injectable({ providedIn: 'root' | 'platform' | 'any' })` self-registration. */\nfunction collectInjectableSelfBinding(\n cls: ts.ClassDeclaration,\n checker: ts.TypeChecker,\n workspaceRoot: string,\n table: BindingTable,\n): void {\n for (const decorator of classDecorators(cls)) {\n if (decoratorName(decorator) !== 'Injectable') continue;\n const call = decoratorCall(decorator);\n const arg = call?.arguments[0];\n if (!arg || !ts.isObjectLiteralExpression(arg)) return;\n const providedIn = objectProps(arg).get('providedIn');\n if (providedIn && ts.isStringLiteralLike(providedIn)) {\n const token = classTokenKey(cls, workspaceRoot);\n const file = relativeFile(workspaceRoot, cls.getSourceFile());\n table.add(new Binding(token.key, token.display, 'decorator', ANGULAR_SCOPE, cls, '', file));\n }\n return;\n }\n}\n\n/**\n * Collect every Angular provider in the program into a token-keyed table.\n * `checker` is required so cross-package class tokens (`SaveApi`, `ClientConfig`)\n * resolve to the same declaration the injection sites reference.\n */\nexport function collectAngularProviders(\n program: ts.Program,\n checker: ts.TypeChecker,\n workspaceRoot: string,\n): BindingTable {\n const table = new BindingTable();\n\n for (const sourceFile of program.getSourceFiles()) {\n if (!isAnalyzableFile(sourceFile)) continue;\n const file = relativeFile(workspaceRoot, sourceFile);\n\n const visit = (node: ts.Node): void => {\n if (ts.isClassDeclaration(node)) {\n collectInjectableSelfBinding(node, checker, workspaceRoot, table);\n } else if (\n ts.isPropertyAssignment(node) &&\n (ts.isIdentifier(node.name) || ts.isStringLiteralLike(node.name)) &&\n node.name.text === 'providers' &&\n ts.isArrayLiteralExpression(node.initializer)\n ) {\n for (const element of node.initializer.elements) {\n collectProviderElement(element, checker, workspaceRoot, file, table);\n }\n }\n ts.forEachChild(node, visit);\n };\n visit(sourceFile);\n }\n\n return table;\n}\n"]}
1
+ {"version":3,"file":"angular-providers.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/nx-webpieces-rules/src/lib/di-graph/angular-providers.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Angular Provider Table (pass 1, Angular flavor)\n *\n * The Angular analog of `bindings.ts` (Inversify): scans the program and maps\n * Angular's provider forms onto the SAME token-keyed {@link BindingTable} the\n * shared walker consumes, so `angular-analyzer.ts` reuses every downstream\n * mechanism (leaf labeling, factory-dep edges, unresolved handling).\n *\n * Provider sources (v1 flat global table — component-scoped shadowing is an\n * accepted approximation):\n * - Any `providers: [...]` array (ApplicationConfig, `@Component`, `@Directive`)\n * - `@Injectable({ providedIn: 'root' | 'platform' | 'any' })` self-registration\n *\n * Provider forms per array element:\n * - bare class `Foo` → to/self binding (implClass=Foo)\n * - `{ provide, useClass }` → to binding (implClass)\n * - `{ provide, useValue }` → toConstantValue leaf\n * - `{ provide, useFactory, deps: [A, B] }` → toDynamicValue leaf + factoryDeps\n * - `{ provide, useExisting }` → alias → target impl class\n * - `multi: true` → multiple bindings per token (fan-out)\n *\n * Framework-internal `provideXxx()` calls (`provideRouter`,\n * `provideZoneChangeDetection`, ...) have no DI leaves and are skipped.\n */\n\nimport * as ts from 'typescript';\nimport { Binding, DiScope, TokenRef } from './model';\nimport {\n BindingTable,\n classDecorators,\n decoratorCall,\n decoratorName,\n isApiClientBoundary,\n resolveClassDeclaration,\n} from './bindings';\nimport { classTokenKey, relativeFile, resolveTokenKey } from './token-resolver';\n\n// Angular injector-scoped providers are effectively singletons at their scope.\nconst ANGULAR_SCOPE: DiScope = 'singleton';\n\nfunction isAnalyzableFile(sourceFile: ts.SourceFile): boolean {\n if (sourceFile.isDeclarationFile) return false;\n if (sourceFile.fileName.includes('/node_modules/')) return false;\n return true;\n}\n\n/** First line of an expression's source text, truncated for leaf labels. */\nfunction firstLine(text: string): string {\n const line = text.split('\\n')[0].trim();\n return line.length > 60 ? line.slice(0, 57) + '...' : line;\n}\n\n/** Pull `{ name: value }` properties out of an object literal into a map. */\nfunction objectProps(obj: ts.ObjectLiteralExpression): Map<string, ts.Expression> {\n const props = new Map<string, ts.Expression>();\n for (const prop of obj.properties) {\n if (ts.isPropertyAssignment(prop) && (ts.isIdentifier(prop.name) || ts.isStringLiteralLike(prop.name))) {\n props.set(prop.name.text, prop.initializer);\n }\n }\n return props;\n}\n\n/** Resolve each `deps: [A, B]` element to a token reference for factory-dep edges. */\nfunction collectDeps(depsExpr: ts.Expression | undefined, checker: ts.TypeChecker, workspaceRoot: string): TokenRef[] {\n if (!depsExpr || !ts.isArrayLiteralExpression(depsExpr)) return [];\n const deps: TokenRef[] = [];\n for (const element of depsExpr.elements) {\n // Simple token form (`EnvironmentConfig`); the decorated array form\n // (`[new Optional(), Token]`) is out of scope for v1.\n if (ts.isIdentifier(element) || ts.isPropertyAccessExpression(element)) {\n const cls = resolveClassDeclaration(element, checker);\n deps.push(cls ? classTokenKey(cls, workspaceRoot) : resolveTokenKey(element, checker, workspaceRoot));\n }\n }\n return deps;\n}\n\n/** Record one provider-object literal (`{ provide, useX }`) as a binding. */\nfunction collectProviderObject(\n obj: ts.ObjectLiteralExpression,\n checker: ts.TypeChecker,\n workspaceRoot: string,\n file: string,\n table: BindingTable,\n): void {\n const props = objectProps(obj);\n const provideExpr = props.get('provide');\n if (!provideExpr) return;\n\n const provideClass = resolveClassDeclaration(provideExpr, checker);\n const token = provideClass\n ? classTokenKey(provideClass, workspaceRoot)\n : resolveTokenKey(provideExpr, checker, workspaceRoot);\n\n const useClass = props.get('useClass');\n const useValue = props.get('useValue');\n const useFactory = props.get('useFactory');\n const useExisting = props.get('useExisting');\n\n if (useClass) {\n const impl = resolveClassDeclaration(useClass, checker);\n table.add(new Binding(token.key, token.display, 'to', ANGULAR_SCOPE, impl, useClass.getText(), file));\n return;\n }\n if (useExisting) {\n // Alias: T resolves to whatever `useExisting` points at — resolve through\n // to the target impl class so the walk continues into its dependencies.\n const impl = resolveClassDeclaration(useExisting, checker);\n table.add(new Binding(token.key, token.display, 'to', ANGULAR_SCOPE, impl, useExisting.getText(), file));\n return;\n }\n if (useFactory) {\n const deps = collectDeps(props.get('deps'), checker, workspaceRoot);\n const isApiBoundary = isApiClientBoundary(useFactory, checker);\n table.add(\n new Binding(token.key, token.display, 'toDynamicValue', ANGULAR_SCOPE, null, firstLine(useFactory.getText()), file, deps, isApiBoundary),\n );\n return;\n }\n if (useValue) {\n table.add(\n new Binding(token.key, token.display, 'toConstantValue', ANGULAR_SCOPE, null, firstLine(useValue.getText()), file),\n );\n return;\n }\n // `{ provide: T }` with no recipe — treat the token itself as the impl class.\n if (provideClass) {\n table.add(new Binding(token.key, token.display, 'to', ANGULAR_SCOPE, provideClass, provideExpr.getText(), file));\n }\n}\n\n/** Record one element of a `providers: [...]` array. */\nfunction collectProviderElement(\n element: ts.Expression,\n checker: ts.TypeChecker,\n workspaceRoot: string,\n file: string,\n table: BindingTable,\n): void {\n // Framework-internal `provideRouter(...)` / `provideZoneChangeDetection(...)`.\n if (ts.isCallExpression(element)) return;\n\n // Bare class provider: `providers: [MyService]` → useClass: MyService.\n if (ts.isIdentifier(element) || ts.isPropertyAccessExpression(element)) {\n const cls = resolveClassDeclaration(element, checker);\n if (cls) {\n const token = classTokenKey(cls, workspaceRoot);\n table.add(new Binding(token.key, token.display, 'to', ANGULAR_SCOPE, cls, element.getText(), file));\n }\n return;\n }\n\n if (ts.isObjectLiteralExpression(element)) {\n collectProviderObject(element, checker, workspaceRoot, file, table);\n }\n}\n\n/** `@Injectable({ providedIn: 'root' | 'platform' | 'any' })` self-registration. */\nfunction collectInjectableSelfBinding(\n cls: ts.ClassDeclaration,\n checker: ts.TypeChecker,\n workspaceRoot: string,\n table: BindingTable,\n): void {\n for (const decorator of classDecorators(cls)) {\n if (decoratorName(decorator) !== 'Injectable') continue;\n const call = decoratorCall(decorator);\n const arg = call?.arguments[0];\n if (!arg || !ts.isObjectLiteralExpression(arg)) return;\n const providedIn = objectProps(arg).get('providedIn');\n if (providedIn && ts.isStringLiteralLike(providedIn)) {\n const token = classTokenKey(cls, workspaceRoot);\n const file = relativeFile(workspaceRoot, cls.getSourceFile());\n table.add(new Binding(token.key, token.display, 'decorator', ANGULAR_SCOPE, cls, '', file));\n }\n return;\n }\n}\n\n/**\n * Collect every Angular provider in the program into a token-keyed table.\n * `checker` is required so cross-package class tokens (`SaveApi`, `ClientConfig`)\n * resolve to the same declaration the injection sites reference.\n */\nexport function collectAngularProviders(\n program: ts.Program,\n checker: ts.TypeChecker,\n workspaceRoot: string,\n): BindingTable {\n const table = new BindingTable();\n\n for (const sourceFile of program.getSourceFiles()) {\n if (!isAnalyzableFile(sourceFile)) continue;\n const file = relativeFile(workspaceRoot, sourceFile);\n\n const visit = (node: ts.Node): void => {\n if (ts.isClassDeclaration(node)) {\n collectInjectableSelfBinding(node, checker, workspaceRoot, table);\n } else if (\n ts.isPropertyAssignment(node) &&\n (ts.isIdentifier(node.name) || ts.isStringLiteralLike(node.name)) &&\n node.name.text === 'providers' &&\n ts.isArrayLiteralExpression(node.initializer)\n ) {\n for (const element of node.initializer.elements) {\n collectProviderElement(element, checker, workspaceRoot, file, table);\n }\n }\n ts.forEachChild(node, visit);\n };\n visit(sourceFile);\n }\n\n return table;\n}\n"]}
@@ -16,8 +16,18 @@ import * as ts from 'typescript';
16
16
  import { Binding } from './model';
17
17
  export declare class BindingTable {
18
18
  private readonly byToken;
19
+ /** providerTokenKey -> the class its get() resolves. See bindFrameworkProvider. */
20
+ private readonly providerTargets;
19
21
  add(binding: Binding): void;
20
22
  lookup(tokenKey: string): Binding[];
23
+ /** Record `bindFrameworkProvider(ProviderClass, TargetClass)`. */
24
+ addProviderTarget(providerTokenKey: string, target: ts.ClassDeclaration): void;
25
+ /**
26
+ * The class a Provider hands out, if this token is a registered Provider subclass.
27
+ * The walker follows this so `Factory -> XProvider -> X` is visible in the design,
28
+ * instead of the provider dead-ending as an opaque toDynamicValue leaf.
29
+ */
30
+ providerTarget(providerTokenKey: string): ts.ClassDeclaration | undefined;
21
31
  }
22
32
  /**
23
33
  * A class the walker treats as an EXTERNAL boundary: its declaration lives in a
@@ -33,6 +43,16 @@ export declare function isExternalClass(cls: ts.ClassDeclaration): boolean;
33
43
  * If `expr` is (or resolves through the checker to) a class declaration, return it.
34
44
  */
35
45
  export declare function resolveClassDeclaration(expr: ts.Expression, checker: ts.TypeChecker): ts.ClassDeclaration | null;
46
+ /**
47
+ * True when `expr` (the argument to `.toDynamicValue(...)` / an Angular
48
+ * `useFactory`) builds an API-client proxy: it contains a `createApiClient(Api, ...)`
49
+ * call whose first argument resolves to an @ApiPath-decorated contract class.
50
+ *
51
+ * This is the DI-graph boundary marker for generated (and external) API clients:
52
+ * the walk renders such a binding as an `api` leaf and stops, rather than
53
+ * descending into the client's own transport config (ClientConfig → ...).
54
+ */
55
+ export declare function isApiClientBoundary(expr: ts.Expression, checker: ts.TypeChecker): boolean;
36
56
  /** Return the decorator call expression when `decorator` is `@name(...)`, else null. */
37
57
  export declare function decoratorCall(decorator: ts.Decorator): ts.CallExpression | null;
38
58
  /** The identifier name of a decorator like `@provideSingleton()` or `@inject(X)`. */