@webpieces/nx-webpieces-rules 0.3.279 → 0.3.280

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.279",
3
+ "version": "0.3.280",
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.279",
25
- "@webpieces/code-rules": "0.3.279",
26
- "@webpieces/eslint-rules": "0.3.279",
27
- "@webpieces/pr-gate": "0.3.279",
28
- "@webpieces/rules-config": "0.3.279",
24
+ "@webpieces/ai-hook-rules": "0.3.280",
25
+ "@webpieces/code-rules": "0.3.280",
26
+ "@webpieces/eslint-rules": "0.3.280",
27
+ "@webpieces/pr-gate": "0.3.280",
28
+ "@webpieces/rules-config": "0.3.280",
29
29
  "madge": "8.0.0"
30
30
  },
31
31
  "peerDependencies": {
@@ -40,6 +40,7 @@ const MISSING_DESIGN_RULE_NAME = 'missing-design-annotation';
40
40
  const DI_MARKERS = [
41
41
  '@DocumentDesign(',
42
42
  '@provideSingleton',
43
+ '@provideFrameworkSingleton',
43
44
  '@provideTransient',
44
45
  '@injectable',
45
46
  'new ContainerModule',
@@ -1 +1 @@
1
- {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/nx-webpieces-rules/src/executors/di-graph-generate/executor.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * DI Graph Generate Executor\n *\n * Per-project: statically analyzes the project's Inversify dependency DAG\n * (constructor injection from controllers — or library top-of-DAG classes —\n * down to leaves) and writes three checked-in files at the project root:\n *\n * design.json — machine-readable graph (deterministic, sorted)\n * design.md — Mermaid diagram rendered by GitHub/IDEs in PRs\n * design.html — clickable viz.js page (linked from architecture/dependencies.html)\n *\n * Runs on every build (cache:false; the build gates on\n * validate-di-graph-unchanged which dependsOn this target). Unrecognized DI\n * patterns become \"unresolved\" nodes rather than failing the build.\n *\n * Config (webpieces.config.json, rule key `di-graph`): mode RUN_EVERY_TIME | OFF.\n *\n * Usage: nx run <project>:di-graph-generate\n */\n\nimport type { ExecutorContext } from '@nx/devkit';\nimport { loadAndValidate, ResolvedConfig } from '@webpieces/rules-config';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport {\n DiAnalyzer,\n frameworkTags,\n explicitRoleTag,\n FrameworkMarkers,\n selectAnalyzer,\n} from '../../lib/di-graph/analyzer-strategy';\nimport { createProjectProgram } from '../../lib/di-graph/program';\nimport { toDesignJson } from '../../lib/di-graph/serializer';\nimport { toDesignMarkdown } from '../../lib/di-graph/mermaid';\nimport { generateDesignHTML } from '../../lib/di-graph/design-visualizer';\nimport { DiDesign, DiGraph } from '../../lib/di-graph/model';\nimport { toError } from '../../toError';\n\nexport interface DiGraphGenerateOptions {\n // No options here — config comes from webpieces.config.json at runtime.\n}\n\nexport interface ExecutorResult {\n success: boolean;\n}\n\nconst RULE_NAME = 'di-graph';\nconst MISSING_DESIGN_RULE_NAME = 'missing-design-annotation';\n\n// Cheap substring pre-scan: a project whose source never mentions any DI marker\n// gets an empty graph without paying for a ts.Program. Angular markers\n// (@Component/bootstrapApplication) are included so an Angular app that uses no\n// Inversify decorator isn't short-circuited to empty.\nconst DI_MARKERS = [\n '@DocumentDesign(',\n '@provideSingleton',\n '@provideTransient',\n '@injectable',\n 'new ContainerModule',\n '@inject(',\n '@Component(',\n 'bootstrapApplication',\n];\n\nconst ANGULAR_MARKERS = ['@Component(', 'bootstrapApplication'];\n// A non-Angular DI-design root. When no role tag is set, its presence steers the\n// marker-fallback toward the Inversify analyzer (server/controller mode).\nconst DESIGN_ROOT_MARKER = '@DocumentDesign(';\n\n/** Recursively read every project .ts file, folding each into `visit`. */\nfunction forEachSourceFile(dir: string, visit: (content: string) => void): void {\n if (!fs.existsSync(dir)) return;\n for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {\n const full = path.join(dir, entry.name);\n if (entry.isDirectory()) {\n if (entry.name === 'node_modules' || entry.name === 'dist') continue;\n forEachSourceFile(full, visit);\n } else if (entry.name.endsWith('.ts') && !entry.name.endsWith('.d.ts')) {\n visit(fs.readFileSync(full, 'utf-8'));\n }\n }\n}\n\nfunction sourceHasDiMarkers(dir: string): boolean {\n let found = false;\n forEachSourceFile(dir, (content: string) => {\n if (!found && DI_MARKERS.some((marker: string) => content.includes(marker))) found = true;\n });\n return found;\n}\n\n/** Pre-scan a project's source for the framework markers used when no tag is set. */\nfunction detectFrameworkMarkers(dir: string): FrameworkMarkers {\n let angular = false;\n let controller = false;\n forEachSourceFile(dir, (content: string) => {\n if (!angular && ANGULAR_MARKERS.some((marker: string) => content.includes(marker))) angular = true;\n if (!controller && content.includes(DESIGN_ROOT_MARKER)) controller = true;\n });\n return new FrameworkMarkers(angular, controller);\n}\n\n/**\n * Repo-relative back link from a project's committed design.html up to\n * architecture/dependencies.html, so a reader who clicked a box in the\n * architecture graph can click back out. E.g. 'packages/http/http-api' →\n * '../../../architecture/dependencies.html'.\n */\nfunction architectureBackHref(projectRoot: string): string {\n return path.posix.relative(projectRoot.replace(/\\\\/g, '/'), 'architecture/dependencies.html');\n}\n\nfunction writeDesignFiles(projectRootAbs: string, projectRoot: string, graph: DiGraph): void {\n // toDesignJson sorts the graph in place, so design.md/design.html below all\n // see the same deterministic ordering (no git churn on re-run).\n fs.writeFileSync(path.join(projectRootAbs, 'design.json'), toDesignJson(graph));\n fs.writeFileSync(path.join(projectRootAbs, 'design.md'), toDesignMarkdown(graph));\n fs.writeFileSync(\n path.join(projectRootAbs, 'design.html'),\n generateDesignHTML(graph, architectureBackHref(projectRoot)),\n );\n}\n\n/** The analyzer chosen for a project plus the role tag that drove the choice. */\nclass AnalyzerChoice {\n constructor(\n public readonly analyzer: DiAnalyzer,\n public readonly role: string | null,\n ) {}\n}\n\n/**\n * Select the analyzer by role (server & designed-lib → @DocumentDesign,\n * client→angular design, lib→skip). The explicit `role:` nx tag is the source of\n * truth; when absent we fall back to the legacy `framework:` selection + marker\n * pre-scan so designs stay identical until a project is retagged.\n */\nfunction chooseAnalyzer(tags: string[], srcDir: string): AnalyzerChoice {\n const role = explicitRoleTag(tags);\n const frameworks = frameworkTags(tags);\n const analyzer = selectAnalyzer(role, frameworks, detectFrameworkMarkers(srcDir));\n console.log(\n ` Analyzer: ${analyzer.constructor.name} ` +\n `(role tag: ${role ?? 'none'}, framework tags: ${frameworks.length > 0 ? frameworks.join(', ') : 'none'})`,\n );\n return new AnalyzerChoice(analyzer, role);\n}\n\n/**\n * A server/designed-lib project that produced no design (zero @DocumentDesign\n * roots) fails the build with role-specific guidance. Enforced under the\n * `missing-design-annotation` rule.\n */\nfunction reportMissingDesignAnnotation(projectName: string, role: string): void {\n if (role === 'server') {\n console.error(\n `❌ ${projectName} is tagged role:server but has no @DocumentDesign class.\\n` +\n ` All controllers should be annotated with @DocumentDesign() ` +\n `(from @webpieces/http-routing) so their design.json / design.html get generated\\n` +\n ` and linked from architecture/dependencies.html.`,\n );\n return;\n }\n console.error(\n `❌ ${projectName} is tagged role:designed-lib but has no @DocumentDesign class.\\n` +\n ` One or more classes you want a design printed for need @DocumentDesign() ` +\n `(from @webpieces/http-routing) added —\\n` +\n ` or retag the project role:lib if it has no design.`,\n );\n}\n\n/**\n * A server/designed-lib project MUST expose at least one @DocumentDesign root,\n * else its design is empty and the role is meaningless. Returns true (and reports)\n * when the build should fail. The `missing-design-annotation` rule gates it:\n * absent (an older published config) → enforce; OFF → skip.\n */\nfunction failsMissingDesignAnnotation(\n shared: ResolvedConfig,\n role: string | null,\n graph: DiGraph,\n projectName: string,\n): boolean {\n const missingRule = shared.rules.get(MISSING_DESIGN_RULE_NAME);\n const enforce = !missingRule || !missingRule.isOff;\n if (enforce && graph.designs.length === 0 && (role === 'server' || role === 'designed-lib')) {\n reportMissingDesignAnnotation(projectName, role);\n return true;\n }\n return false;\n}\n\nexport default async function runExecutor(\n _options: DiGraphGenerateOptions,\n context: ExecutorContext,\n): Promise<ExecutorResult> {\n const shared = loadAndValidate(context.root).resolved;\n const rule = shared.rules.get(RULE_NAME);\n if (rule && rule.isOff) {\n console.log(`\\n⏭️ Skipping ${RULE_NAME} generation (mode: OFF)\\n`);\n return { success: true };\n }\n\n const projectName = context.projectName ?? 'project';\n const projectConfig = context.projectsConfigurations?.projects[projectName];\n const projectRoot = projectConfig?.root ?? '.';\n const projectRootAbs = path.join(context.root, projectRoot);\n const srcDir = path.join(projectRootAbs, 'src');\n\n console.log(`\\n🧬 Generating DI design graph for ${projectName}\\n`);\n\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions -- chokepoint: a generator crash must produce an actionable failure, not a stack trace mid-build\n try {\n if (!sourceHasDiMarkers(srcDir)) {\n console.log(' No DI markers found — writing empty design graph');\n writeDesignFiles(projectRootAbs, projectRoot, new DiGraph(projectName));\n return { success: true };\n }\n\n const program = createProjectProgram(projectRootAbs);\n if (!program) {\n console.log(' No usable tsconfig/source — writing empty design graph');\n writeDesignFiles(projectRootAbs, projectRoot, new DiGraph(projectName));\n return { success: true };\n }\n\n const choice = chooseAnalyzer(projectConfig?.tags ?? [], srcDir);\n const graph = choice.analyzer.analyzeProject(program, context.root, projectRoot, projectName);\n\n if (failsMissingDesignAnnotation(shared, choice.role, graph, projectName)) {\n return { success: false };\n }\n\n writeDesignFiles(projectRootAbs, projectRoot, graph);\n\n const nodeCount = graph.designs.reduce((sum: number, d: DiDesign) => sum + d.nodes.length, 0);\n const edgeCount = graph.designs.reduce((sum: number, d: DiDesign) => sum + d.edges.length, 0);\n console.log(\n `✅ Wrote ${projectRoot}/design.json + design.md + design.html ` +\n `(${graph.designs.length} design(s), ${nodeCount} node(s), ${edgeCount} edge(s))`,\n );\n const unresolved = [...new Set(graph.designs.flatMap((d: DiDesign) => d.unresolved))];\n if (unresolved.length > 0) {\n console.warn(`⚠️ ${unresolved.length} unresolved token(s)/type(s): ${unresolved.join(', ')}`);\n }\n return { success: true };\n } catch (err: unknown) {\n const error = toError(err);\n console.error(`❌ DI graph generation failed for ${projectName}: ${error.message}`);\n console.error(` To unblock builds, set rules[\"${RULE_NAME}\"].mode=\"OFF\" in webpieces.config.json.`);\n return { success: false };\n }\n}\n"]}
1
+ {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/nx-webpieces-rules/src/executors/di-graph-generate/executor.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * DI Graph Generate Executor\n *\n * Per-project: statically analyzes the project's Inversify dependency DAG\n * (constructor injection from controllers — or library top-of-DAG classes —\n * down to leaves) and writes three checked-in files at the project root:\n *\n * design.json — machine-readable graph (deterministic, sorted)\n * design.md — Mermaid diagram rendered by GitHub/IDEs in PRs\n * design.html — clickable viz.js page (linked from architecture/dependencies.html)\n *\n * Runs on every build (cache:false; the build gates on\n * validate-di-graph-unchanged which dependsOn this target). Unrecognized DI\n * patterns become \"unresolved\" nodes rather than failing the build.\n *\n * Config (webpieces.config.json, rule key `di-graph`): mode RUN_EVERY_TIME | OFF.\n *\n * Usage: nx run <project>:di-graph-generate\n */\n\nimport type { ExecutorContext } from '@nx/devkit';\nimport { loadAndValidate, ResolvedConfig } from '@webpieces/rules-config';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport {\n DiAnalyzer,\n frameworkTags,\n explicitRoleTag,\n FrameworkMarkers,\n selectAnalyzer,\n} from '../../lib/di-graph/analyzer-strategy';\nimport { createProjectProgram } from '../../lib/di-graph/program';\nimport { toDesignJson } from '../../lib/di-graph/serializer';\nimport { toDesignMarkdown } from '../../lib/di-graph/mermaid';\nimport { generateDesignHTML } from '../../lib/di-graph/design-visualizer';\nimport { DiDesign, DiGraph } from '../../lib/di-graph/model';\nimport { toError } from '../../toError';\n\nexport interface DiGraphGenerateOptions {\n // No options here — config comes from webpieces.config.json at runtime.\n}\n\nexport interface ExecutorResult {\n success: boolean;\n}\n\nconst RULE_NAME = 'di-graph';\nconst MISSING_DESIGN_RULE_NAME = 'missing-design-annotation';\n\n// Cheap substring pre-scan: a project whose source never mentions any DI marker\n// gets an empty graph without paying for a ts.Program. Angular markers\n// (@Component/bootstrapApplication) are included so an Angular app that uses no\n// Inversify decorator isn't short-circuited to empty.\nconst DI_MARKERS = [\n '@DocumentDesign(',\n '@provideSingleton',\n '@provideFrameworkSingleton',\n '@provideTransient',\n '@injectable',\n 'new ContainerModule',\n '@inject(',\n '@Component(',\n 'bootstrapApplication',\n];\n\nconst ANGULAR_MARKERS = ['@Component(', 'bootstrapApplication'];\n// A non-Angular DI-design root. When no role tag is set, its presence steers the\n// marker-fallback toward the Inversify analyzer (server/controller mode).\nconst DESIGN_ROOT_MARKER = '@DocumentDesign(';\n\n/** Recursively read every project .ts file, folding each into `visit`. */\nfunction forEachSourceFile(dir: string, visit: (content: string) => void): void {\n if (!fs.existsSync(dir)) return;\n for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {\n const full = path.join(dir, entry.name);\n if (entry.isDirectory()) {\n if (entry.name === 'node_modules' || entry.name === 'dist') continue;\n forEachSourceFile(full, visit);\n } else if (entry.name.endsWith('.ts') && !entry.name.endsWith('.d.ts')) {\n visit(fs.readFileSync(full, 'utf-8'));\n }\n }\n}\n\nfunction sourceHasDiMarkers(dir: string): boolean {\n let found = false;\n forEachSourceFile(dir, (content: string) => {\n if (!found && DI_MARKERS.some((marker: string) => content.includes(marker))) found = true;\n });\n return found;\n}\n\n/** Pre-scan a project's source for the framework markers used when no tag is set. */\nfunction detectFrameworkMarkers(dir: string): FrameworkMarkers {\n let angular = false;\n let controller = false;\n forEachSourceFile(dir, (content: string) => {\n if (!angular && ANGULAR_MARKERS.some((marker: string) => content.includes(marker))) angular = true;\n if (!controller && content.includes(DESIGN_ROOT_MARKER)) controller = true;\n });\n return new FrameworkMarkers(angular, controller);\n}\n\n/**\n * Repo-relative back link from a project's committed design.html up to\n * architecture/dependencies.html, so a reader who clicked a box in the\n * architecture graph can click back out. E.g. 'packages/http/http-api' →\n * '../../../architecture/dependencies.html'.\n */\nfunction architectureBackHref(projectRoot: string): string {\n return path.posix.relative(projectRoot.replace(/\\\\/g, '/'), 'architecture/dependencies.html');\n}\n\nfunction writeDesignFiles(projectRootAbs: string, projectRoot: string, graph: DiGraph): void {\n // toDesignJson sorts the graph in place, so design.md/design.html below all\n // see the same deterministic ordering (no git churn on re-run).\n fs.writeFileSync(path.join(projectRootAbs, 'design.json'), toDesignJson(graph));\n fs.writeFileSync(path.join(projectRootAbs, 'design.md'), toDesignMarkdown(graph));\n fs.writeFileSync(\n path.join(projectRootAbs, 'design.html'),\n generateDesignHTML(graph, architectureBackHref(projectRoot)),\n );\n}\n\n/** The analyzer chosen for a project plus the role tag that drove the choice. */\nclass AnalyzerChoice {\n constructor(\n public readonly analyzer: DiAnalyzer,\n public readonly role: string | null,\n ) {}\n}\n\n/**\n * Select the analyzer by role (server & designed-lib → @DocumentDesign,\n * client→angular design, lib→skip). The explicit `role:` nx tag is the source of\n * truth; when absent we fall back to the legacy `framework:` selection + marker\n * pre-scan so designs stay identical until a project is retagged.\n */\nfunction chooseAnalyzer(tags: string[], srcDir: string): AnalyzerChoice {\n const role = explicitRoleTag(tags);\n const frameworks = frameworkTags(tags);\n const analyzer = selectAnalyzer(role, frameworks, detectFrameworkMarkers(srcDir));\n console.log(\n ` Analyzer: ${analyzer.constructor.name} ` +\n `(role tag: ${role ?? 'none'}, framework tags: ${frameworks.length > 0 ? frameworks.join(', ') : 'none'})`,\n );\n return new AnalyzerChoice(analyzer, role);\n}\n\n/**\n * A server/designed-lib project that produced no design (zero @DocumentDesign\n * roots) fails the build with role-specific guidance. Enforced under the\n * `missing-design-annotation` rule.\n */\nfunction reportMissingDesignAnnotation(projectName: string, role: string): void {\n if (role === 'server') {\n console.error(\n `❌ ${projectName} is tagged role:server but has no @DocumentDesign class.\\n` +\n ` All controllers should be annotated with @DocumentDesign() ` +\n `(from @webpieces/http-routing) so their design.json / design.html get generated\\n` +\n ` and linked from architecture/dependencies.html.`,\n );\n return;\n }\n console.error(\n `❌ ${projectName} is tagged role:designed-lib but has no @DocumentDesign class.\\n` +\n ` One or more classes you want a design printed for need @DocumentDesign() ` +\n `(from @webpieces/http-routing) added —\\n` +\n ` or retag the project role:lib if it has no design.`,\n );\n}\n\n/**\n * A server/designed-lib project MUST expose at least one @DocumentDesign root,\n * else its design is empty and the role is meaningless. Returns true (and reports)\n * when the build should fail. The `missing-design-annotation` rule gates it:\n * absent (an older published config) → enforce; OFF → skip.\n */\nfunction failsMissingDesignAnnotation(\n shared: ResolvedConfig,\n role: string | null,\n graph: DiGraph,\n projectName: string,\n): boolean {\n const missingRule = shared.rules.get(MISSING_DESIGN_RULE_NAME);\n const enforce = !missingRule || !missingRule.isOff;\n if (enforce && graph.designs.length === 0 && (role === 'server' || role === 'designed-lib')) {\n reportMissingDesignAnnotation(projectName, role);\n return true;\n }\n return false;\n}\n\nexport default async function runExecutor(\n _options: DiGraphGenerateOptions,\n context: ExecutorContext,\n): Promise<ExecutorResult> {\n const shared = loadAndValidate(context.root).resolved;\n const rule = shared.rules.get(RULE_NAME);\n if (rule && rule.isOff) {\n console.log(`\\n⏭️ Skipping ${RULE_NAME} generation (mode: OFF)\\n`);\n return { success: true };\n }\n\n const projectName = context.projectName ?? 'project';\n const projectConfig = context.projectsConfigurations?.projects[projectName];\n const projectRoot = projectConfig?.root ?? '.';\n const projectRootAbs = path.join(context.root, projectRoot);\n const srcDir = path.join(projectRootAbs, 'src');\n\n console.log(`\\n🧬 Generating DI design graph for ${projectName}\\n`);\n\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions -- chokepoint: a generator crash must produce an actionable failure, not a stack trace mid-build\n try {\n if (!sourceHasDiMarkers(srcDir)) {\n console.log(' No DI markers found — writing empty design graph');\n writeDesignFiles(projectRootAbs, projectRoot, new DiGraph(projectName));\n return { success: true };\n }\n\n const program = createProjectProgram(projectRootAbs);\n if (!program) {\n console.log(' No usable tsconfig/source — writing empty design graph');\n writeDesignFiles(projectRootAbs, projectRoot, new DiGraph(projectName));\n return { success: true };\n }\n\n const choice = chooseAnalyzer(projectConfig?.tags ?? [], srcDir);\n const graph = choice.analyzer.analyzeProject(program, context.root, projectRoot, projectName);\n\n if (failsMissingDesignAnnotation(shared, choice.role, graph, projectName)) {\n return { success: false };\n }\n\n writeDesignFiles(projectRootAbs, projectRoot, graph);\n\n const nodeCount = graph.designs.reduce((sum: number, d: DiDesign) => sum + d.nodes.length, 0);\n const edgeCount = graph.designs.reduce((sum: number, d: DiDesign) => sum + d.edges.length, 0);\n console.log(\n `✅ Wrote ${projectRoot}/design.json + design.md + design.html ` +\n `(${graph.designs.length} design(s), ${nodeCount} node(s), ${edgeCount} edge(s))`,\n );\n const unresolved = [...new Set(graph.designs.flatMap((d: DiDesign) => d.unresolved))];\n if (unresolved.length > 0) {\n console.warn(`⚠️ ${unresolved.length} unresolved token(s)/type(s): ${unresolved.join(', ')}`);\n }\n return { success: true };\n } catch (err: unknown) {\n const error = toError(err);\n console.error(`❌ DI graph generation failed for ${projectName}: ${error.message}`);\n console.error(` To unblock builds, set rules[\"${RULE_NAME}\"].mode=\"OFF\" in webpieces.config.json.`);\n return { success: false };\n }\n}\n"]}
@@ -31,7 +31,14 @@ const path = tslib_1.__importStar(require("path"));
31
31
  const model_1 = require("./model");
32
32
  const bindings_1 = require("./bindings");
33
33
  const token_resolver_1 = require("./token-resolver");
34
- const DI_DECORATORS = new Set(['provideSingleton', 'provideTransient', 'provideSingletonAs', 'injectable']);
34
+ const DI_DECORATORS = new Set([
35
+ 'provideSingleton',
36
+ 'provideTransient',
37
+ 'provideSingletonAs',
38
+ 'provideFrameworkSingleton',
39
+ 'provideFrameworkSingletonAs',
40
+ 'injectable',
41
+ ]);
35
42
  class ParamInjection {
36
43
  expr;
37
44
  multi;
@@ -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(['provideSingleton', 'provideTransient', 'provideSingletonAs', 'injectable']);\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":";AAAA;;;;;;;;;;;;;;GAcG;;;AAuCH,kDAoBC;AAWD,sDAEC;AASD,0CAEC;AAMD,0CAMC;AAGD,wCAkBC;AA0VD,kCAKC;AA6CD,oCA4CC;AAOD,kCAYC;AAWD,oCAqCC;;AA7mBD,uDAAiC;AACjC,mDAA6B;AAC7B,mCAA0F;AAC1F,yCAQoB;AACpB,qDAAgF;AAEhF,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC;IAC1B,kBAAkB;IAClB,kBAAkB;IAClB,oBAAoB;IACpB,2BAA2B;IAC3B,6BAA6B;IAC7B,YAAY;CACf,CAAC,CAAC;AAEH,MAAa,cAAc;IACvB,IAAI,CAAuB;IAC3B,KAAK,CAAU;IACf,QAAQ,CAAU;IAClB,SAAS,CAAU;IAEnB,YAAY,IAA0B,EAAE,KAAc,EAAE,QAAiB,EAAE,SAAkB;QACzF,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;IAC/B,CAAC;CACJ;AAZD,wCAYC;AAED,SAAgB,mBAAmB,CAAC,KAA8B;IAC9D,IAAI,IAAI,GAAyB,IAAI,CAAC;IACtC,IAAI,KAAK,GAAG,KAAK,CAAC;IAClB,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,IAAI,SAAS,GAAG,KAAK,CAAC;IACtB,KAAK,MAAM,SAAS,IAAI,EAAE,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;QACpD,MAAM,IAAI,GAAG,IAAA,wBAAa,EAAC,SAAS,CAAC,CAAC;QACtC,MAAM,IAAI,GAAG,IAAA,wBAAa,EAAC,SAAS,CAAC,CAAC;QACtC,IAAI,IAAI,KAAK,QAAQ,IAAI,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;YAC1C,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;QAC7B,CAAC;aAAM,IAAI,IAAI,KAAK,aAAa,IAAI,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;YACtD,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;YACzB,KAAK,GAAG,IAAI,CAAC;QACjB,CAAC;aAAM,IAAI,IAAI,KAAK,UAAU,EAAE,CAAC;YAC7B,QAAQ,GAAG,IAAI,CAAC;QACpB,CAAC;aAAM,IAAI,IAAI,KAAK,WAAW,EAAE,CAAC;YAC9B,SAAS,GAAG,IAAI,CAAC;QACrB,CAAC;IACL,CAAC;IACD,OAAO,IAAI,cAAc,CAAC,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;AAChE,CAAC;AAED,SAAS,iBAAiB,CAAC,GAAwB,EAAE,KAAkB;IACnE,KAAK,MAAM,SAAS,IAAI,IAAA,0BAAe,EAAC,GAAG,CAAC,EAAE,CAAC;QAC3C,MAAM,IAAI,GAAG,IAAA,wBAAa,EAAC,SAAS,CAAC,CAAC;QACtC,IAAI,IAAI,IAAI,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;IAC7C,CAAC;IACD,OAAO,KAAK,CAAC;AACjB,CAAC;AAED,wGAAwG;AACxG,SAAgB,qBAAqB,CAAC,GAAwB;IAC1D,OAAO,iBAAiB,CAAC,GAAG,EAAE,IAAI,GAAG,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC;AAC/D,CAAC;AASD,SAAgB,eAAe,CAAC,IAAgB;IAC5C,OAAO,IAAI,KAAK,mBAAmB,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,YAAY,CAAC;AAC7E,CAAC;AAED,SAAS,mBAAmB,CAAC,GAAwB;IACjD,OAAO,iBAAiB,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC;AACjD,CAAC;AAED,SAAgB,eAAe,CAAC,GAAwB;IACpD,KAAK,MAAM,MAAM,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC;QAC/B,IAAI,EAAE,CAAC,wBAAwB,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,IAAI;YAAE,OAAO,MAAM,CAAC;QACtE,IAAI,EAAE,CAAC,wBAAwB,CAAC,MAAM,CAAC;YAAE,OAAO,MAAM,CAAC;IAC3D,CAAC;IACD,OAAO,IAAI,CAAC;AAChB,CAAC;AAED,8DAA8D;AAC9D,SAAgB,cAAc,CAC1B,OAAmB,EACnB,aAAqB,EACrB,WAAmB;IAEnB,MAAM,MAAM,GAAG,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,WAAW,GAAG,GAAG,CAAC;IAC3E,MAAM,OAAO,GAA0B,EAAE,CAAC;IAC1C,KAAK,MAAM,UAAU,IAAI,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC;QAChD,IAAI,UAAU,CAAC,iBAAiB;YAAE,SAAS;QAC3C,MAAM,GAAG,GAAG,IAAA,6BAAY,EAAC,aAAa,EAAE,UAAU,CAAC,CAAC;QACpD,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC;YAAE,SAAS;QACtC,MAAM,KAAK,GAAG,CAAC,IAAa,EAAQ,EAAE;YAClC,IAAI,EAAE,CAAC,kBAAkB,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI;gBAAE,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACjE,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QACjC,CAAC,CAAC;QACF,KAAK,CAAC,UAAU,CAAC,CAAC;IACtB,CAAC;IACD,OAAO,OAAO,CAAC;AACnB,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAa,SAAS;IAClB,IAAI,CAAoC;IACxC,+FAA+F;IAC/F,IAAI,CAAuC;IAC3C,KAAK,CAAU;IACf,QAAQ,CAAU;IAClB,SAAS,CAAS;IAClB,SAAS,CAAS;IAElB,YACI,IAAuC,EACvC,IAA0C,EAC1C,SAAiB,EACjB,SAAiB,EACjB,KAAK,GAAG,KAAK,EACb,QAAQ,GAAG,KAAK;QAEhB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC7B,CAAC;CACJ;AAxBD,8BAwBC;AAED;;;;;;;;;;;GAWG;AACH,MAAsB,eAAe;IACd,OAAO,CAAiB;IACxB,KAAK,CAAe;IACpB,aAAa,CAAS;IACtB,MAAM,CAAW;IACnB,QAAQ,GAAG,IAAI,GAAG,EAA+B,CAAC;IAClD,OAAO,GAAG,IAAI,GAAG,EAAmB,CAAC;IACrC,aAAa,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC1C,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAC5B,OAAO,GAAG,IAAI,GAAG,EAAuB,CAAC;IAChD,SAAS,GAA+B,IAAI,CAAC;IAEvD,YAAY,OAAuB,EAAE,KAAmB,EAAE,aAAqB,EAAE,MAAgB;QAC7F,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;QACnC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACzB,CAAC;IAKD;;;;;OAKG;IACO,UAAU,CAAC,GAAwB;QACzC,OAAO,GAAG,KAAK,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC;IACnE,CAAC;IAED,OAAO,CAAC,GAAwB;QAC5B,IAAI,CAAC,SAAS,GAAG,GAAG,CAAC;QACrB,MAAM,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QAC/B,IAAI,CAAC,MAAM,CAAC,IAAI,GAAG,EAAE,CAAC;QACtB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IACxB,CAAC;IAED;;;;;;;OAOG;IACO,SAAS,CAAC,GAAwB,EAAE,YAAqB,SAAS,EAAE,OAAO,GAAG,EAAE;QACtF,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACxC,IAAI,QAAQ;YAAE,OAAO,QAAQ,CAAC;QAE9B,MAAM,SAAS,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,aAAa,CAAC;QAC3D,MAAM,IAAI,GAAG,IAAA,6BAAY,EAAC,IAAI,CAAC,aAAa,EAAE,GAAG,CAAC,aAAa,EAAE,CAAC,CAAC;QACnE,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;QACzC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QAE3B,MAAM,aAAa,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;QAC3C,MAAM,KAAK,GAAG,aAAa,KAAK,SAAS,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC;QACtE,4EAA4E;QAC5E,6EAA6E;QAC7E,2EAA2E;QAC3E,mBAAmB;QACnB,MAAM,IAAI,GAAe,IAAA,0BAAe,EAAC,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;QAClF,MAAM,IAAI,GAAG,IAAI,cAAM,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;QAC1D,2EAA2E;QAC3E,6EAA6E;QAC7E,MAAM,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QACzC,IAAI,GAAG,KAAK,EAAE,IAAI,GAAG,KAAK,SAAS;YAAE,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;QACpD,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC7B,OAAO,EAAE,CAAC;IACd,CAAC;IAEO,OAAO,CAAC,SAAiB,EAAE,IAAY;QAC3C,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;YAC/B,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;YAC5B,OAAO,SAAS,CAAC;QACrB,CAAC;QACD,MAAM,aAAa,GAAG,GAAG,SAAS,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QACjE,IAAI,EAAE,GAAG,aAAa,CAAC;QACvB,IAAI,CAAC,GAAG,CAAC,CAAC;QACV,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;YAC1B,EAAE,GAAG,GAAG,aAAa,IAAI,CAAC,EAAE,CAAC;YAC7B,CAAC,EAAE,CAAC;QACR,CAAC;QACD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACrB,OAAO,EAAE,CAAC;IACd,CAAC;IAED,mEAAmE;IAC3D,UAAU,CAAC,GAAwB;QACvC,MAAM,KAAK,GAAG,IAAA,8BAAa,EAAC,GAAG,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;QACrD,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;YACjD,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS;gBAAE,OAAO,OAAO,CAAC,KAAK,CAAC;QAC1D,CAAC;QACD,OAAO,SAAS,CAAC;IACrB,CAAC;IAED;;;;;;OAMG;IACK,QAAQ,CAAC,OAAgB,EAAE,IAAgB,EAAE,SAAiB;QAClE,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAC3C,IAAI,QAAQ;YAAE,OAAO,QAAQ,CAAC;QAE9B,MAAM,MAAM,GAAG,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,YAAY,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC;QAC5F,MAAM,SAAS,GAAG,SAAS,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,KAAK,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC;QAC/F,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;QACjD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QAC9B,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,cAAM,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;QAChG,IAAI,IAAI,KAAK,SAAS;YAAE,IAAI,CAAC,iBAAiB,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;QAC5D,OAAO,EAAE,CAAC;IACd,CAAC;IAED,qFAAqF;IAC7E,iBAAiB,CAAC,MAAc,EAAE,OAAgB;QACtD,KAAK,MAAM,GAAG,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;YACpC,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAC5C,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACtB,KAAK,MAAM,UAAU,IAAI,QAAQ,EAAE,CAAC;oBAChC,8DAA8D;oBAC9D,MAAM,IAAI,GAAG,IAAI,CAAC,aAAa,CAAC,UAAU,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;oBACzD,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,cAAM,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;gBAC7G,CAAC;YACL,CAAC;iBAAM,CAAC;gBACJ,MAAM,IAAI,GAAG,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;gBAChE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,cAAM,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;YAC7G,CAAC;QACL,CAAC;IACL,CAAC;IAED;;;;OAIG;IACK,cAAc,CAAC,SAAiB,EAAE,IAAY,EAAE,MAAc;QAClE,MAAM,GAAG,GAAG,GAAG,SAAS,IAAI,MAAM,IAAI,IAAI,EAAE,CAAC;QAC7C,MAAM,QAAQ,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC7C,IAAI,QAAQ;YAAE,OAAO,QAAQ,CAAC;QAE9B,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;QACzC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QAChC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,cAAM,CAAC,EAAE,EAAE,SAAS,EAAE,YAAY,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACxH,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,KAAK,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QAChE,OAAO,EAAE,CAAC;IACd,CAAC;IAES,SAAS,CAAC,GAAwB;QACxC,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,OAAO;QAClC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAEtB,oEAAoE;QACpE,wEAAwE;QACxE,2EAA2E;QAC3E,IAAI,IAAA,0BAAe,EAAC,GAAG,CAAC;YAAE,OAAO;QAEjC,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QACnC,KAAK,MAAM,SAAS,IAAI,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,EAAE,CAAC;YAClD,IAAI,CAAC,gBAAgB,CAAC,MAAM,EAAE,GAAG,EAAE,SAAS,CAAC,CAAC;QAClD,CAAC;IACL,CAAC;IAED,4EAA4E;IACpE,gBAAgB,CAAC,MAAc,EAAE,GAAwB,EAAE,SAAoB;QACnF,IAAI,SAAS,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YAC5B,IAAI,CAAC,oBAAoB,CAAC,MAAM,EAAE,GAAG,EAAE,SAAS,CAAC,CAAC;QACtD,CAAC;aAAM,CAAC;YACJ,IAAI,CAAC,qBAAqB,CAAC,MAAM,EAAE,GAAG,EAAE,SAAS,CAAC,CAAC;QACvD,CAAC;IACL,CAAC;IAED,sFAAsF;IAC9E,qBAAqB,CAAC,MAAc,EAAE,GAAwB,EAAE,SAAoB;QACxF,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC;QAC5B,IAAI,CAAC,IAAI;YAAE,OAAO;QAClB,MAAM,KAAK,GAAG,IAAA,gCAAe,EAAC,IAAI,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;QACtE,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,OAAO,CAAC;QACvD,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAE9C,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACtB,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;gBAC7B,MAAM,IAAI,GAAG,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;gBAC9D,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAClB,IAAI,cAAM,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,GAAG,EAAE,SAAS,CAAC,SAAS,EAAE,SAAS,CAAC,SAAS,CAAC,CACrG,CAAC;YACN,CAAC;YACD,OAAO;QACX,CAAC;QAED,0EAA0E;QAC1E,IAAI,SAAS,CAAC,KAAK,IAAI,SAAS,CAAC,QAAQ;YAAE,OAAO;QAElD,6EAA6E;QAC7E,yEAAyE;QACzE,IAAI,SAAS,CAAC,IAAI,KAAK,cAAc,EAAE,CAAC;YACpC,MAAM,MAAM,GAAG,IAAA,kCAAuB,EAAC,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;YAC3D,IAAI,MAAM,EAAE,CAAC;gBACT,MAAM,UAAU,GAAG,IAAA,8BAAa,EAAC,MAAM,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;gBAC7D,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,SAAS,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;gBACpE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;gBACvB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAClB,IAAI,cAAM,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,EAAE,SAAS,CAAC,SAAS,EAAE,SAAS,CAAC,SAAS,CAAC,CACjH,CAAC;gBACF,OAAO;YACX,CAAC;QACL,CAAC;QAED,MAAM,IAAI,GAAG,IAAA,6BAAY,EAAC,IAAI,CAAC,aAAa,EAAE,GAAG,CAAC,aAAa,EAAE,CAAC,CAAC;QACnE,MAAM,KAAK,GAAG,SAAS,CAAC,SAAS,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC;QAC/E,MAAM,IAAI,GAAG,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;QAC7D,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAClB,IAAI,cAAM,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,GAAG,EAAE,SAAS,CAAC,SAAS,EAAE,SAAS,CAAC,SAAS,CAAC,CACrG,CAAC;IACN,CAAC;IAEO,aAAa,CAAC,OAAgB,EAAE,SAAiB;QACrD,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;YACpB,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;YACzE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;YAClC,OAAO,IAAI,CAAC;QAChB,CAAC;QACD,IAAI,OAAO,CAAC,IAAI,KAAK,iBAAiB;YAAE,OAAO,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC;QAC7F,IAAI,OAAO,CAAC,IAAI,KAAK,gBAAgB;YAAE,OAAO,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;QAC3F,yDAAyD;QACzD,MAAM,MAAM,GAAG,OAAO,CAAC,SAAS,KAAK,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC;QACnF,MAAM,KAAK,GAAG,SAAS,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC;QACpD,OAAO,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC5D,CAAC;IAED,kFAAkF;IAC1E,oBAAoB,CAAC,MAAc,EAAE,GAAwB,EAAE,SAAoB;QACvF,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,IAAI,EAAE,CAAC,YAAY,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;QAC1F,MAAM,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,IAAA,kCAAuB,EAAC,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAE/E,IAAI,MAAM,EAAE,CAAC;YACT,MAAM,KAAK,GAAG,IAAA,8BAAa,EAAC,MAAM,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;YACxD,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;YACpC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;YACvB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAClB,IAAI,cAAM,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,GAAG,EAAE,SAAS,CAAC,SAAS,EAAE,SAAS,CAAC,SAAS,CAAC,CACvG,CAAC;YACF,OAAO;QACX,CAAC;QAED,gFAAgF;QAChF,MAAM,IAAI,GAAG,IAAA,6BAAY,EAAC,IAAI,CAAC,aAAa,EAAE,GAAG,CAAC,aAAa,EAAE,CAAC,CAAC;QACnE,MAAM,KAAK,GAAG,SAAS,CAAC,SAAS,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC;QACrF,MAAM,IAAI,GAAG,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;QAClD,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAClB,IAAI,cAAM,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,SAAS,EAAE,QAAQ,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,CAAC,SAAS,EAAE,SAAS,CAAC,SAAS,CAAC,CACjI,CAAC;IACN,CAAC;CACJ;AAhQD,0CAgQC;AAED;;;GAGG;AACH,MAAa,sBAAuB,SAAQ,eAAe;IAC7C,iBAAiB,CAAC,GAAwB;QAChD,MAAM,IAAI,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;QAClC,IAAI,CAAC,IAAI;YAAE,OAAO,EAAE,CAAC;QAErB,MAAM,UAAU,GAAgB,EAAE,CAAC;QACnC,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YAClC,MAAM,SAAS,GAAG,mBAAmB,CAAC,KAAK,CAAC,CAAC;YAC7C,IAAI,SAAS,CAAC,SAAS;gBAAE,SAAS;YAElC,MAAM,SAAS,GAAG,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YACvF,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAEzD,IAAI,SAAS,CAAC,IAAI,EAAE,CAAC;gBACjB,UAAU,CAAC,IAAI,CACX,IAAI,SAAS,CAAC,OAAO,EAAE,SAAS,CAAC,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,CAAC,KAAK,EAAE,SAAS,CAAC,QAAQ,CAAC,CACpG,CAAC;YACN,CAAC;iBAAM,CAAC;gBACJ,MAAM,OAAO,GACT,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC,mBAAmB,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC;oBACpF,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ;oBACrB,CAAC,CAAC,IAAI,CAAC;gBACf,UAAU,CAAC,IAAI,CAAC,IAAI,SAAS,CAAC,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC;YAC1E,CAAC;QACL,CAAC;QACD,OAAO,UAAU,CAAC;IACtB,CAAC;CACJ;AA3BD,wDA2BC;AAED,SAAgB,WAAW,CAAC,CAAsB,EAAE,CAAsB;IACtE,MAAM,KAAK,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IACxC,MAAM,KAAK,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IACxC,IAAI,KAAK,KAAK,KAAK;QAAE,OAAO,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACnD,OAAO,CAAC,CAAC,aAAa,EAAE,CAAC,QAAQ,GAAG,CAAC,CAAC,aAAa,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5E,CAAC;AAED;;;GAGG;AACH,SAAS,gBAAgB,CACrB,OAA8B,EAC9B,OAAuB,EACvB,KAAmB,EACnB,aAAqB;IAErB,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,GAAwB,EAAE,EAAE,CAAC,mBAAmB,CAAC,GAAG,CAAC,CAAC,CAAC;IACzF,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAuB,CAAC;IAEhD,KAAK,MAAM,GAAG,IAAI,SAAS,EAAE,CAAC;QAC1B,MAAM,IAAI,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;QAClC,KAAK,MAAM,KAAK,IAAI,IAAI,EAAE,UAAU,IAAI,EAAE,EAAE,CAAC;YACzC,MAAM,SAAS,GAAG,mBAAmB,CAAC,KAAK,CAAC,CAAC;YAC7C,IAAI,SAAS,CAAC,SAAS;gBAAE,SAAS;YAClC,IAAI,SAAS,CAAC,IAAI,EAAE,CAAC;gBACjB,MAAM,KAAK,GAAG,IAAA,gCAAe,EAAC,SAAS,CAAC,IAAI,EAAE,OAAO,EAAE,aAAa,CAAC,CAAC;gBACtE,KAAK,MAAM,OAAO,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;oBAC5C,IAAI,OAAO,CAAC,SAAS;wBAAE,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;gBAC3D,CAAC;YACL,CAAC;iBAAM,IAAI,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC,mBAAmB,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAClG,MAAM,MAAM,GAAG,IAAA,kCAAuB,EAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;gBACrE,IAAI,MAAM;oBAAE,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YACrC,CAAC;QACL,CAAC;IACL,CAAC;IAED,OAAO,SAAS,CAAC,MAAM,CAAC,CAAC,GAAwB,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;AAC9E,CAAC;AAED;;;;;;;;;GASG;AACH,SAAgB,YAAY,CAAC,MAAgB;IACzC,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAoB,CAAC;IAC7C,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QAC3B,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QACxC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAChB,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC/B,CAAC;IAED,6EAA6E;IAC7E,sEAAsE;IACtE,MAAM,SAAS,GAAG,IAAI,GAAG,EAAU,CAAC;IACpC,MAAM,KAAK,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC5B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACpC,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACpB,IAAI,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC;YAAE,SAAS;QAChC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAClB,KAAK,MAAM,EAAE,IAAI,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC;YACtC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC;gBAAE,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC3C,CAAC;IACL,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC5C,KAAK,MAAM,EAAE,IAAI,SAAS;QAAE,SAAS,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;IACjD,6EAA6E;IAC7E,wEAAwE;IACxE,KAAK,IAAI,IAAI,GAAG,CAAC,EAAE,IAAI,GAAG,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC;QAC/C,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;YAC3B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,KAAK,MAAM,CAAC,IAAI;gBAAE,SAAS;YAC7D,MAAM,SAAS,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;YACnD,IAAI,SAAS,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;gBACzC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC;gBAC/B,OAAO,GAAG,IAAI,CAAC;YACnB,CAAC;QACL,CAAC;QACD,IAAI,CAAC,OAAO;YAAE,MAAM;IACxB,CAAC;IAED,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QAC9B,IAAI,CAAC,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;QACzC,IAAI,IAAI,CAAC,KAAK,GAAG,QAAQ;YAAE,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC;IACrD,CAAC;IACD,MAAM,CAAC,QAAQ,GAAG,QAAQ,CAAC;AAC/B,CAAC;AAED;;;;GAIG;AACH,SAAgB,WAAW,CACvB,IAAyB,EACzB,QAAoB,EACpB,aAAqB,EACrB,WAAkD;IAElD,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,aAAa,CAAC;IAC7D,MAAM,IAAI,GAAG,IAAA,6BAAY,EAAC,aAAa,EAAE,IAAI,CAAC,aAAa,EAAE,CAAC,CAAC;IAC/D,MAAM,MAAM,GAAG,IAAI,gBAAQ,CAAC,SAAS,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;IACvD,WAAW,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAClC,YAAY,CAAC,MAAM,CAAC,CAAC;IACrB,OAAO,MAAM,CAAC;AAClB,CAAC;AAED;;;;;;;;GAQG;AACH,SAAgB,YAAY,CACxB,OAAmB,EACnB,aAAqB,EACrB,WAAmB,EACnB,WAAmB,EACnB,mBAAmB,GAAG,KAAK,EAC3B,WAAuB,YAAY;IAEnC,MAAM,OAAO,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IACzC,MAAM,KAAK,GAAG,IAAA,0BAAe,EAAC,OAAO,EAAE,OAAO,EAAE,aAAa,CAAC,CAAC;IAC/D,MAAM,KAAK,GAAG,IAAI,eAAO,CAAC,WAAW,CAAC,CAAC;IAEvC,MAAM,OAAO,GAAG,cAAc,CAAC,OAAO,EAAE,aAAa,EAAE,WAAW,CAAC,CAAC;IACpE,MAAM,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,GAAwB,EAAE,EAAE,CAAC,qBAAqB,CAAC,GAAG,CAAC,CAAC,CAAC;IAC7F,gFAAgF;IAChF,+EAA+E;IAC/E,uDAAuD;IACvD,MAAM,KAAK,GACP,WAAW,CAAC,MAAM,GAAG,CAAC;QAClB,CAAC,CAAC,WAAW;QACb,CAAC,CAAC,QAAQ,KAAK,YAAY,IAAI,mBAAmB;YAChD,CAAC,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,aAAa,CAAC;YAC1D,CAAC,CAAC,EAAE,CAAC;IAEf,KAAK,MAAM,IAAI,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;QAC9C,MAAM,QAAQ,GAAe,qBAAqB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;QAC/F,KAAK,CAAC,OAAO,CAAC,IAAI,CACd,WAAW,CACP,IAAI,EACJ,QAAQ,EACR,aAAa,EACb,CAAC,MAAgB,EAAE,EAAE,CAAC,IAAI,sBAAsB,CAAC,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,MAAM,CAAC,CAC1F,CACJ,CAAC;IACN,CAAC;IAED,OAAO,KAAK,CAAC;AACjB,CAAC","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"]}
@@ -169,12 +169,14 @@ function collectDecoratorBindings(cls, checker, workspaceRoot, table) {
169
169
  const file = (0, token_resolver_1.relativeFile)(workspaceRoot, cls.getSourceFile());
170
170
  for (const decorator of classDecorators(cls)) {
171
171
  const name = decoratorName(decorator);
172
- if (name === 'provideSingleton' || name === 'provideTransient') {
172
+ // provideFrameworkSingleton(As) are the framework-registry twins of provideSingleton(As)
173
+ // (see @webpieces/core-context frameworkProvide.ts) — same self/token binding, singleton scope.
174
+ if (name === 'provideSingleton' || name === 'provideTransient' || name === 'provideFrameworkSingleton') {
173
175
  const token = (0, token_resolver_1.classTokenKey)(cls, workspaceRoot);
174
- const scope = name === 'provideSingleton' ? 'singleton' : 'transient';
176
+ const scope = name === 'provideTransient' ? 'transient' : 'singleton';
175
177
  table.add(new model_1.Binding(token.key, token.display, 'decorator', scope, cls, '', file));
176
178
  }
177
- else if (name === 'provideSingletonAs') {
179
+ else if (name === 'provideSingletonAs' || name === 'provideFrameworkSingletonAs') {
178
180
  const call = decoratorCall(decorator);
179
181
  const tokenExpr = call?.arguments[0];
180
182
  if (!tokenExpr)
@@ -1 +1 @@
1
- {"version":3,"file":"bindings.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/nx-webpieces-rules/src/lib/di-graph/bindings.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Binding Table (pass 1 of the DI graph analyzer)\n *\n * Scans every source file in the project's TypeScript program (skipping .d.ts and\n * node_modules) and collects all Inversify bindings into a Map<tokenKey, Binding[]>:\n *\n * - ContainerModule bodies: bind(TOKEN).to(Impl) / .toSelf() / .toConstantValue(x)\n * / .toDynamicValue(fn), with .inSingletonScope() etc.\n * - Decorators: @provideSingleton() / @provideTransient() (self-binding)\n * and @provideSingletonAs(TOKEN)\n *\n * Arrays because multiInject tokens (e.g. HEADER_TYPES.PlatformHeadersExtension) are\n * bound once per ContainerModule across several packages.\n */\n\nimport * as ts from 'typescript';\nimport { Binding, BindingKind, DiScope } from './model';\nimport { classTokenKey, relativeFile, resolveTokenKey } from './token-resolver';\n\nconst BIND_METHOD_NAMES = new Set(['to', 'toSelf', 'toConstantValue', 'toDynamicValue']);\n\nexport class BindingTable {\n private readonly byToken = new Map<string, Binding[]>();\n\n add(binding: Binding): void {\n const list = this.byToken.get(binding.tokenKey);\n if (list) {\n list.push(binding);\n } else {\n this.byToken.set(binding.tokenKey, [binding]);\n }\n }\n\n lookup(tokenKey: string): Binding[] {\n return this.byToken.get(tokenKey) ?? [];\n }\n}\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/**\n * A class the walker treats as an EXTERNAL boundary: its declaration lives in a\n * `.d.ts` file or under `node_modules` — i.e. a published package outside this\n * nx workspace. The exact inverse of {@link isAnalyzableFile}'s file test. In an\n * nx monorepo internal libs resolve through tsconfig path mappings to real `.ts`\n * source, so they are NOT external and keep expanding; only third-party packages\n * (resolved to `.d.ts` in `node_modules`) trip this. Pass-2 renders such a class\n * as a leaf `external` node and stops — it does not descend into its ctor deps.\n */\nexport function isExternalClass(cls: ts.ClassDeclaration): boolean {\n const sourceFile = cls.getSourceFile();\n return sourceFile.isDeclarationFile || sourceFile.fileName.includes('/node_modules/');\n}\n\n/** Walk `.inSingletonScope()` / `.inTransientScope()` suffixes above a binding call. */\nfunction scopeFromChain(bindingCall: ts.CallExpression): DiScope {\n let node: ts.Node = bindingCall;\n while (\n node.parent &&\n ts.isPropertyAccessExpression(node.parent) &&\n node.parent.parent &&\n ts.isCallExpression(node.parent.parent)\n ) {\n const methodName = node.parent.name.text;\n if (methodName === 'inSingletonScope') return 'singleton';\n if (methodName === 'inTransientScope') return 'transient';\n node = node.parent.parent;\n }\n return 'unknown';\n}\n\n/**\n * If `expr` is (or resolves through the checker to) a class declaration, return it.\n */\nexport function resolveClassDeclaration(\n expr: ts.Expression,\n checker: ts.TypeChecker,\n): ts.ClassDeclaration | null {\n let symbol = checker.getSymbolAtLocation(expr);\n if (symbol && (symbol.flags & ts.SymbolFlags.Alias) !== 0) {\n symbol = checker.getAliasedSymbol(symbol);\n }\n for (const decl of symbol?.declarations ?? []) {\n if (ts.isClassDeclaration(decl)) return decl;\n }\n return null;\n}\n\n/**\n * Recognize `bind(TOKEN)` at the bottom of a fluent chain. Accepts a bare `bind(...)`\n * identifier call or `options.bind(...)` property call.\n */\nfunction asBindCall(expr: ts.Expression): ts.CallExpression | null {\n if (!ts.isCallExpression(expr)) return null;\n const callee = expr.expression;\n if (ts.isIdentifier(callee) && callee.text === 'bind') return expr;\n if (ts.isPropertyAccessExpression(callee) && callee.name.text === 'bind') return expr;\n return null;\n}\n\n/**\n * Handle one `<receiver>.to*(...)` call: if the receiver bottoms out at bind(TOKEN),\n * record the binding.\n */\nfunction collectBindCall(\n call: ts.CallExpression,\n checker: ts.TypeChecker,\n workspaceRoot: string,\n table: BindingTable,\n): void {\n if (!ts.isPropertyAccessExpression(call.expression)) return;\n const methodName = call.expression.name.text;\n if (!BIND_METHOD_NAMES.has(methodName)) return;\n\n const bindCall = asBindCall(call.expression.expression);\n if (!bindCall || bindCall.arguments.length === 0) return;\n\n const tokenExpr = bindCall.arguments[0];\n const file = relativeFile(workspaceRoot, call.getSourceFile());\n const scope = scopeFromChain(call);\n\n if (methodName === 'toSelf') {\n const cls = resolveClassDeclaration(tokenExpr, checker);\n const token = cls\n ? classTokenKey(cls, workspaceRoot)\n : resolveTokenKey(tokenExpr, checker, workspaceRoot);\n table.add(new Binding(token.key, tokenExpr.getText(), 'toSelf', scope, cls, '', file));\n return;\n }\n\n const token = resolveTokenKey(tokenExpr, checker, workspaceRoot);\n\n if (methodName === 'to') {\n const implExpr = call.arguments[0];\n const cls = implExpr ? resolveClassDeclaration(implExpr, checker) : null;\n const valueText = implExpr ? implExpr.getText() : '';\n table.add(new Binding(token.key, token.display, 'to', scope, cls, valueText, file));\n return;\n }\n\n const kind: BindingKind = methodName === 'toConstantValue' ? 'toConstantValue' : 'toDynamicValue';\n const valueExpr = call.arguments[0];\n const valueText = valueExpr ? firstLine(valueExpr.getText()) : '';\n table.add(new Binding(token.key, token.display, kind, scope, null, valueText, file));\n}\n\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/** Return the decorator call expression when `decorator` is `@name(...)`, else null. */\nexport function decoratorCall(decorator: ts.Decorator): ts.CallExpression | null {\n return ts.isCallExpression(decorator.expression) ? decorator.expression : null;\n}\n\n/** The identifier name of a decorator like `@provideSingleton()` or `@inject(X)`. */\nexport function decoratorName(decorator: ts.Decorator): string | null {\n const call = decoratorCall(decorator);\n const callee = call ? call.expression : decorator.expression;\n if (ts.isIdentifier(callee)) return callee.text;\n if (ts.isPropertyAccessExpression(callee)) return callee.name.text;\n return null;\n}\n\nexport function classDecorators(cls: ts.ClassDeclaration): ts.Decorator[] {\n const decorators = ts.getDecorators(cls);\n return decorators ? [...decorators] : [];\n}\n\nfunction collectDecoratorBindings(\n cls: ts.ClassDeclaration,\n checker: ts.TypeChecker,\n workspaceRoot: string,\n table: BindingTable,\n): void {\n const file = relativeFile(workspaceRoot, cls.getSourceFile());\n for (const decorator of classDecorators(cls)) {\n const name = decoratorName(decorator);\n if (name === 'provideSingleton' || name === 'provideTransient') {\n const token = classTokenKey(cls, workspaceRoot);\n const scope: DiScope = name === 'provideSingleton' ? 'singleton' : 'transient';\n table.add(new Binding(token.key, token.display, 'decorator', scope, cls, '', file));\n } else if (name === 'provideSingletonAs') {\n const call = decoratorCall(decorator);\n const tokenExpr = call?.arguments[0];\n if (!tokenExpr) continue;\n const token = resolveTokenKey(tokenExpr, checker, workspaceRoot);\n table.add(new Binding(token.key, token.display, 'decorator', 'singleton', cls, '', file));\n }\n }\n}\n\n/**\n * Pass 1: collect every binding in the program into a token-keyed table.\n */\nexport function collectBindings(\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\n const visit = (node: ts.Node): void => {\n if (ts.isCallExpression(node)) {\n collectBindCall(node, checker, workspaceRoot, table);\n } else if (ts.isClassDeclaration(node)) {\n collectDecoratorBindings(node, checker, workspaceRoot, table);\n }\n ts.forEachChild(node, visit);\n };\n visit(sourceFile);\n }\n\n return table;\n}\n"]}
1
+ {"version":3,"file":"bindings.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/nx-webpieces-rules/src/lib/di-graph/bindings.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Binding Table (pass 1 of the DI graph analyzer)\n *\n * Scans every source file in the project's TypeScript program (skipping .d.ts and\n * node_modules) and collects all Inversify bindings into a Map<tokenKey, Binding[]>:\n *\n * - ContainerModule bodies: bind(TOKEN).to(Impl) / .toSelf() / .toConstantValue(x)\n * / .toDynamicValue(fn), with .inSingletonScope() etc.\n * - Decorators: @provideSingleton() / @provideTransient() (self-binding)\n * and @provideSingletonAs(TOKEN)\n *\n * Arrays because multiInject tokens (e.g. HEADER_TYPES.PlatformHeadersExtension) are\n * bound once per ContainerModule across several packages.\n */\n\nimport * as ts from 'typescript';\nimport { Binding, BindingKind, DiScope } from './model';\nimport { classTokenKey, relativeFile, resolveTokenKey } from './token-resolver';\n\nconst BIND_METHOD_NAMES = new Set(['to', 'toSelf', 'toConstantValue', 'toDynamicValue']);\n\nexport class BindingTable {\n private readonly byToken = new Map<string, Binding[]>();\n\n add(binding: Binding): void {\n const list = this.byToken.get(binding.tokenKey);\n if (list) {\n list.push(binding);\n } else {\n this.byToken.set(binding.tokenKey, [binding]);\n }\n }\n\n lookup(tokenKey: string): Binding[] {\n return this.byToken.get(tokenKey) ?? [];\n }\n}\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/**\n * A class the walker treats as an EXTERNAL boundary: its declaration lives in a\n * `.d.ts` file or under `node_modules` — i.e. a published package outside this\n * nx workspace. The exact inverse of {@link isAnalyzableFile}'s file test. In an\n * nx monorepo internal libs resolve through tsconfig path mappings to real `.ts`\n * source, so they are NOT external and keep expanding; only third-party packages\n * (resolved to `.d.ts` in `node_modules`) trip this. Pass-2 renders such a class\n * as a leaf `external` node and stops — it does not descend into its ctor deps.\n */\nexport function isExternalClass(cls: ts.ClassDeclaration): boolean {\n const sourceFile = cls.getSourceFile();\n return sourceFile.isDeclarationFile || sourceFile.fileName.includes('/node_modules/');\n}\n\n/** Walk `.inSingletonScope()` / `.inTransientScope()` suffixes above a binding call. */\nfunction scopeFromChain(bindingCall: ts.CallExpression): DiScope {\n let node: ts.Node = bindingCall;\n while (\n node.parent &&\n ts.isPropertyAccessExpression(node.parent) &&\n node.parent.parent &&\n ts.isCallExpression(node.parent.parent)\n ) {\n const methodName = node.parent.name.text;\n if (methodName === 'inSingletonScope') return 'singleton';\n if (methodName === 'inTransientScope') return 'transient';\n node = node.parent.parent;\n }\n return 'unknown';\n}\n\n/**\n * If `expr` is (or resolves through the checker to) a class declaration, return it.\n */\nexport function resolveClassDeclaration(\n expr: ts.Expression,\n checker: ts.TypeChecker,\n): ts.ClassDeclaration | null {\n let symbol = checker.getSymbolAtLocation(expr);\n if (symbol && (symbol.flags & ts.SymbolFlags.Alias) !== 0) {\n symbol = checker.getAliasedSymbol(symbol);\n }\n for (const decl of symbol?.declarations ?? []) {\n if (ts.isClassDeclaration(decl)) return decl;\n }\n return null;\n}\n\n/**\n * Recognize `bind(TOKEN)` at the bottom of a fluent chain. Accepts a bare `bind(...)`\n * identifier call or `options.bind(...)` property call.\n */\nfunction asBindCall(expr: ts.Expression): ts.CallExpression | null {\n if (!ts.isCallExpression(expr)) return null;\n const callee = expr.expression;\n if (ts.isIdentifier(callee) && callee.text === 'bind') return expr;\n if (ts.isPropertyAccessExpression(callee) && callee.name.text === 'bind') return expr;\n return null;\n}\n\n/**\n * Handle one `<receiver>.to*(...)` call: if the receiver bottoms out at bind(TOKEN),\n * record the binding.\n */\nfunction collectBindCall(\n call: ts.CallExpression,\n checker: ts.TypeChecker,\n workspaceRoot: string,\n table: BindingTable,\n): void {\n if (!ts.isPropertyAccessExpression(call.expression)) return;\n const methodName = call.expression.name.text;\n if (!BIND_METHOD_NAMES.has(methodName)) return;\n\n const bindCall = asBindCall(call.expression.expression);\n if (!bindCall || bindCall.arguments.length === 0) return;\n\n const tokenExpr = bindCall.arguments[0];\n const file = relativeFile(workspaceRoot, call.getSourceFile());\n const scope = scopeFromChain(call);\n\n if (methodName === 'toSelf') {\n const cls = resolveClassDeclaration(tokenExpr, checker);\n const token = cls\n ? classTokenKey(cls, workspaceRoot)\n : resolveTokenKey(tokenExpr, checker, workspaceRoot);\n table.add(new Binding(token.key, tokenExpr.getText(), 'toSelf', scope, cls, '', file));\n return;\n }\n\n const token = resolveTokenKey(tokenExpr, checker, workspaceRoot);\n\n if (methodName === 'to') {\n const implExpr = call.arguments[0];\n const cls = implExpr ? resolveClassDeclaration(implExpr, checker) : null;\n const valueText = implExpr ? implExpr.getText() : '';\n table.add(new Binding(token.key, token.display, 'to', scope, cls, valueText, file));\n return;\n }\n\n const kind: BindingKind = methodName === 'toConstantValue' ? 'toConstantValue' : 'toDynamicValue';\n const valueExpr = call.arguments[0];\n const valueText = valueExpr ? firstLine(valueExpr.getText()) : '';\n table.add(new Binding(token.key, token.display, kind, scope, null, valueText, file));\n}\n\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/** Return the decorator call expression when `decorator` is `@name(...)`, else null. */\nexport function decoratorCall(decorator: ts.Decorator): ts.CallExpression | null {\n return ts.isCallExpression(decorator.expression) ? decorator.expression : null;\n}\n\n/** The identifier name of a decorator like `@provideSingleton()` or `@inject(X)`. */\nexport function decoratorName(decorator: ts.Decorator): string | null {\n const call = decoratorCall(decorator);\n const callee = call ? call.expression : decorator.expression;\n if (ts.isIdentifier(callee)) return callee.text;\n if (ts.isPropertyAccessExpression(callee)) return callee.name.text;\n return null;\n}\n\nexport function classDecorators(cls: ts.ClassDeclaration): ts.Decorator[] {\n const decorators = ts.getDecorators(cls);\n return decorators ? [...decorators] : [];\n}\n\nfunction collectDecoratorBindings(\n cls: ts.ClassDeclaration,\n checker: ts.TypeChecker,\n workspaceRoot: string,\n table: BindingTable,\n): void {\n const file = relativeFile(workspaceRoot, cls.getSourceFile());\n for (const decorator of classDecorators(cls)) {\n const name = decoratorName(decorator);\n // provideFrameworkSingleton(As) are the framework-registry twins of provideSingleton(As)\n // (see @webpieces/core-context frameworkProvide.ts) — same self/token binding, singleton scope.\n if (name === 'provideSingleton' || name === 'provideTransient' || name === 'provideFrameworkSingleton') {\n const token = classTokenKey(cls, workspaceRoot);\n const scope: DiScope = name === 'provideTransient' ? 'transient' : 'singleton';\n table.add(new Binding(token.key, token.display, 'decorator', scope, cls, '', file));\n } else if (name === 'provideSingletonAs' || name === 'provideFrameworkSingletonAs') {\n const call = decoratorCall(decorator);\n const tokenExpr = call?.arguments[0];\n if (!tokenExpr) continue;\n const token = resolveTokenKey(tokenExpr, checker, workspaceRoot);\n table.add(new Binding(token.key, token.display, 'decorator', 'singleton', cls, '', file));\n }\n }\n}\n\n/**\n * Pass 1: collect every binding in the program into a token-keyed table.\n */\nexport function collectBindings(\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\n const visit = (node: ts.Node): void => {\n if (ts.isCallExpression(node)) {\n collectBindCall(node, checker, workspaceRoot, table);\n } else if (ts.isClassDeclaration(node)) {\n collectDecoratorBindings(node, checker, workspaceRoot, table);\n }\n ts.forEachChild(node, visit);\n };\n visit(sourceFile);\n }\n\n return table;\n}\n"]}