@documentation-robotics/cli 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (269) hide show
  1. package/README.md +36 -2
  2. package/dist/analysis/relationship-classifier.js +2 -9
  3. package/dist/analysis/relationship-classifier.js.map +2 -2
  4. package/dist/analyzers/call-graph-utils.js +2 -2
  5. package/dist/analyzers/call-graph-utils.js.map +2 -2
  6. package/dist/analyzers/cards/build.js +171 -0
  7. package/dist/analyzers/cards/build.js.map +7 -0
  8. package/dist/analyzers/cards/classify.js +42 -0
  9. package/dist/analyzers/cards/classify.js.map +7 -0
  10. package/dist/analyzers/cards/edge-index.js +44 -0
  11. package/dist/analyzers/cards/edge-index.js.map +7 -0
  12. package/dist/analyzers/cards/facts.js +46 -0
  13. package/dist/analyzers/cards/facts.js.map +7 -0
  14. package/dist/analyzers/cards/graph.js +42 -0
  15. package/dist/analyzers/cards/graph.js.map +7 -0
  16. package/dist/analyzers/cards/index.js +8 -0
  17. package/dist/analyzers/cards/index.js.map +7 -0
  18. package/dist/analyzers/cards/tier0.js +18 -0
  19. package/dist/analyzers/cards/tier0.js.map +7 -0
  20. package/dist/analyzers/cards/types.js +1 -0
  21. package/dist/analyzers/cards/types.js.map +7 -0
  22. package/dist/analyzers/cbm-analyzer.js +195 -171
  23. package/dist/analyzers/cbm-analyzer.js.map +2 -2
  24. package/dist/analyzers/cbm-responses.js +336 -0
  25. package/dist/analyzers/cbm-responses.js.map +7 -0
  26. package/dist/analyzers/edge-relationships.js +45 -0
  27. package/dist/analyzers/edge-relationships.js.map +7 -0
  28. package/dist/analyzers/mapping-loader.js +9 -0
  29. package/dist/analyzers/mapping-loader.js.map +2 -2
  30. package/dist/analyzers/tier0-rules.js +153 -0
  31. package/dist/analyzers/tier0-rules.js.map +7 -0
  32. package/dist/analyzers/types.js.map +1 -1
  33. package/dist/audit/relationships/ai/prompts.js +10 -10
  34. package/dist/audit/relationships/ai/prompts.js.map +2 -2
  35. package/dist/audit/relationships/analysis/layer-templates.js +52 -52
  36. package/dist/audit/relationships/analysis/layer-templates.js.map +1 -1
  37. package/dist/cli.js +12 -2
  38. package/dist/cli.js.map +2 -2
  39. package/dist/coding-agents/default-permissions.js +31 -1
  40. package/dist/coding-agents/default-permissions.js.map +2 -2
  41. package/dist/coding-agents/drbot-mcp.js +167 -0
  42. package/dist/coding-agents/drbot-mcp.js.map +7 -0
  43. package/dist/commands/add.js +3 -2
  44. package/dist/commands/add.js.map +2 -2
  45. package/dist/commands/analyzer.js +117 -14
  46. package/dist/commands/analyzer.js.map +2 -2
  47. package/dist/commands/changeset-verify.js +55 -0
  48. package/dist/commands/changeset-verify.js.map +7 -0
  49. package/dist/commands/changeset.js +43 -22
  50. package/dist/commands/changeset.js.map +2 -2
  51. package/dist/commands/delete.js +10 -4
  52. package/dist/commands/delete.js.map +2 -2
  53. package/dist/commands/farm.js +176 -60
  54. package/dist/commands/farm.js.map +2 -2
  55. package/dist/commands/mcp.js +19 -4
  56. package/dist/commands/mcp.js.map +2 -2
  57. package/dist/commands/relationship.js +207 -26
  58. package/dist/commands/relationship.js.map +2 -2
  59. package/dist/commands/update.js +42 -23
  60. package/dist/commands/update.js.map +2 -2
  61. package/dist/commands/upgrade.js +99 -11
  62. package/dist/commands/upgrade.js.map +3 -3
  63. package/dist/commands/version.js +1 -1
  64. package/dist/commands/visualize.js +4 -3
  65. package/dist/commands/visualize.js.map +2 -2
  66. package/dist/core/catalog-migration.js +33 -0
  67. package/dist/core/catalog-migration.js.map +7 -0
  68. package/dist/core/changeset-analysis.js +421 -0
  69. package/dist/core/changeset-analysis.js.map +7 -0
  70. package/dist/core/changeset-base-index.js +153 -0
  71. package/dist/core/changeset-base-index.js.map +7 -0
  72. package/dist/core/changeset-brief-delta.js +102 -0
  73. package/dist/core/changeset-brief-delta.js.map +7 -0
  74. package/dist/core/changeset-graph.js +281 -0
  75. package/dist/core/changeset-graph.js.map +7 -0
  76. package/dist/core/changeset-only-guard.js +32 -0
  77. package/dist/core/changeset-only-guard.js.map +7 -0
  78. package/dist/core/changeset-summary.js +68 -0
  79. package/dist/core/changeset-summary.js.map +7 -0
  80. package/dist/core/changeset-validator.js +66 -20
  81. package/dist/core/changeset-validator.js.map +2 -2
  82. package/dist/core/changeset-verify.js +518 -0
  83. package/dist/core/changeset-verify.js.map +7 -0
  84. package/dist/core/changeset.js +56 -9
  85. package/dist/core/changeset.js.map +2 -2
  86. package/dist/core/element-type-migration.js +145 -0
  87. package/dist/core/element-type-migration.js.map +7 -0
  88. package/dist/core/farm-manifest.js +12 -6
  89. package/dist/core/farm-manifest.js.map +2 -2
  90. package/dist/core/farm-sync-engine.js +1 -1
  91. package/dist/core/farm-sync-engine.js.map +2 -2
  92. package/dist/core/farm-sync-state.js +10 -2
  93. package/dist/core/farm-sync-state.js.map +2 -2
  94. package/dist/core/migration-registry.js +75 -46
  95. package/dist/core/migration-registry.js.map +2 -2
  96. package/dist/core/model-upgrade.js +102 -0
  97. package/dist/core/model-upgrade.js.map +7 -0
  98. package/dist/core/model.js +82 -30
  99. package/dist/core/model.js.map +2 -2
  100. package/dist/core/mutation-handler.js +71 -6
  101. package/dist/core/mutation-handler.js.map +2 -2
  102. package/dist/core/relationship-migration-table.js +6639 -0
  103. package/dist/core/relationship-migration-table.js.map +7 -0
  104. package/dist/core/relationship-migration.js +272 -0
  105. package/dist/core/relationship-migration.js.map +7 -0
  106. package/dist/core/relationship-prune.js +49 -0
  107. package/dist/core/relationship-prune.js.map +7 -0
  108. package/dist/core/relationship-staging.js +68 -0
  109. package/dist/core/relationship-staging.js.map +7 -0
  110. package/dist/core/relationships.js +26 -4
  111. package/dist/core/relationships.js.map +2 -2
  112. package/dist/core/report-data-model.js +7 -13
  113. package/dist/core/report-data-model.js.map +2 -2
  114. package/dist/core/staged-changeset-storage.js +64 -17
  115. package/dist/core/staged-changeset-storage.js.map +2 -2
  116. package/dist/core/staged-source-reference.js +28 -0
  117. package/dist/core/staged-source-reference.js.map +7 -0
  118. package/dist/core/staging-area.js +83 -18
  119. package/dist/core/staging-area.js.map +2 -2
  120. package/dist/core/virtual-projection.js +13 -5
  121. package/dist/core/virtual-projection.js.map +2 -2
  122. package/dist/export/archimate-exporter.js +1 -0
  123. package/dist/export/archimate-exporter.js.map +2 -2
  124. package/dist/generated/compiled-validators.js +2 -2
  125. package/dist/generated/compiled-validators.js.map +2 -2
  126. package/dist/generated/layer-registry.js +16 -16
  127. package/dist/generated/layer-registry.js.map +2 -2
  128. package/dist/generated/node-types.js +186 -168
  129. package/dist/generated/node-types.js.map +2 -2
  130. package/dist/generated/relationship-index.js +2236 -7790
  131. package/dist/generated/relationship-index.js.map +2 -2
  132. package/dist/integrations/claude_code/agents/dr-architect.md +16 -3
  133. package/dist/integrations/claude_code/agents/dr-extractor.md +1 -1
  134. package/dist/integrations/claude_code/commands/dr-analyzer.md +565 -0
  135. package/dist/integrations/claude_code/commands/dr-map.md +13 -0
  136. package/dist/integrations/claude_code/commands/dr-plan.md +40 -0
  137. package/dist/integrations/claude_code/commands/dr-relate.md +106 -96
  138. package/dist/integrations/claude_code/commands/dr-verify.md +45 -2
  139. package/dist/integrations/claude_code/docs/END_TO_END_WALKTHROUGH.md +14 -0
  140. package/dist/integrations/claude_code/docs/MCP_SERVER.md +26 -2
  141. package/dist/integrations/claude_code/docs/QUICK_START.md +37 -8
  142. package/dist/integrations/claude_code/docs/README.md +48 -1
  143. package/dist/integrations/claude_code/skills/dr_01_motivation_layer/SKILL.md +93 -72
  144. package/dist/integrations/claude_code/skills/dr_02_business_layer/SKILL.md +163 -126
  145. package/dist/integrations/claude_code/skills/dr_03_product_layer/SKILL.md +161 -126
  146. package/dist/integrations/claude_code/skills/dr_04_security_layer/SKILL.md +153 -133
  147. package/dist/integrations/claude_code/skills/dr_05_application_layer/SKILL.md +129 -100
  148. package/dist/integrations/claude_code/skills/dr_06_technology_layer/SKILL.md +111 -94
  149. package/dist/integrations/claude_code/skills/dr_07_api_layer/SKILL.md +143 -157
  150. package/dist/integrations/claude_code/skills/dr_08_data_model_layer/SKILL.md +117 -33
  151. package/dist/integrations/claude_code/skills/dr_09_dataset_layer/SKILL.md +74 -25
  152. package/dist/integrations/claude_code/skills/dr_10_ux_layer/SKILL.md +88 -12
  153. package/dist/integrations/claude_code/skills/dr_11_navigation_layer/SKILL.md +83 -24
  154. package/dist/integrations/claude_code/skills/dr_12_apm_layer/SKILL.md +57 -12
  155. package/dist/integrations/claude_code/skills/dr_13_testing_layer/SKILL.md +92 -15
  156. package/dist/integrations/claude_code/skills/dr_change_planning/SKILL.md +119 -0
  157. package/dist/integrations/claude_code/skills/dr_changeset_reviewer/SKILL.md +3 -0
  158. package/dist/integrations/claude_code/skills/dr_engineering_guide/SKILL.md +1 -1
  159. package/dist/integrations/github_copilot/agents/dr-architect.md +1 -1
  160. package/dist/integrations/github_copilot/skills/dr_01_motivation_layer/SKILL.md +182 -102
  161. package/dist/integrations/github_copilot/skills/dr_02_business_layer/SKILL.md +266 -148
  162. package/dist/integrations/github_copilot/skills/dr_03_product_layer/SKILL.md +547 -86
  163. package/dist/integrations/github_copilot/skills/dr_04_security_layer/SKILL.md +164 -169
  164. package/dist/integrations/github_copilot/skills/dr_05_application_layer/SKILL.md +420 -150
  165. package/dist/integrations/github_copilot/skills/dr_06_technology_layer/SKILL.md +331 -138
  166. package/dist/integrations/github_copilot/skills/dr_07_api_layer/SKILL.md +265 -201
  167. package/dist/integrations/github_copilot/skills/dr_08_data_model_layer/SKILL.md +181 -58
  168. package/dist/integrations/github_copilot/skills/dr_09_dataset_layer/SKILL.md +209 -57
  169. package/dist/integrations/github_copilot/skills/dr_10_ux_layer/SKILL.md +277 -112
  170. package/dist/integrations/github_copilot/skills/dr_11_navigation_layer/SKILL.md +219 -70
  171. package/dist/integrations/github_copilot/skills/dr_12_apm_layer/SKILL.md +189 -105
  172. package/dist/integrations/github_copilot/skills/dr_13_testing_layer/SKILL.md +222 -102
  173. package/dist/integrations/github_copilot/skills/dr_change_planning/SKILL.md +119 -0
  174. package/dist/integrations/github_copilot/skills/dr_changeset_reviewer/SKILL.md +3 -0
  175. package/dist/integrations/hash-utils.js.map +2 -2
  176. package/dist/mcp/api-key-manager.js +14 -1
  177. package/dist/mcp/api-key-manager.js.map +2 -2
  178. package/dist/mcp/changeset-only.js +34 -0
  179. package/dist/mcp/changeset-only.js.map +7 -0
  180. package/dist/mcp/tool-registry.js +19 -3
  181. package/dist/mcp/tool-registry.js.map +2 -2
  182. package/dist/mcp/tools/changeset-analysis-tools.js +78 -0
  183. package/dist/mcp/tools/changeset-analysis-tools.js.map +7 -0
  184. package/dist/mcp/tools/changeset-editing.js +184 -0
  185. package/dist/mcp/tools/changeset-editing.js.map +7 -0
  186. package/dist/mcp/tools/changeset-lifecycle.js +83 -0
  187. package/dist/mcp/tools/changeset-lifecycle.js.map +7 -0
  188. package/dist/mcp/tools/changeset-shared.js +31 -0
  189. package/dist/mcp/tools/changeset-shared.js.map +7 -0
  190. package/dist/mcp/tools/changeset-show.js +17 -1
  191. package/dist/mcp/tools/changeset-show.js.map +2 -2
  192. package/dist/mcp/tools/changeset-verify.js +43 -0
  193. package/dist/mcp/tools/changeset-verify.js.map +7 -0
  194. package/dist/mcp/tools/index.js +19 -1
  195. package/dist/mcp/tools/index.js.map +2 -2
  196. package/dist/mcp/tools/model-add.js +6 -5
  197. package/dist/mcp/tools/model-add.js.map +2 -2
  198. package/dist/mcp/tools/model-delete.js +2 -2
  199. package/dist/mcp/tools/model-delete.js.map +2 -2
  200. package/dist/mcp/tools/model-search.js +14 -0
  201. package/dist/mcp/tools/model-search.js.map +2 -2
  202. package/dist/mcp/tools/model-show.js +29 -2
  203. package/dist/mcp/tools/model-show.js.map +2 -2
  204. package/dist/mcp/tools/model-trace.js +93 -30
  205. package/dist/mcp/tools/model-trace.js.map +2 -2
  206. package/dist/mcp/tools/model-update.js +35 -19
  207. package/dist/mcp/tools/model-update.js.map +2 -2
  208. package/dist/mcp/tools/relationship-tools.js +98 -0
  209. package/dist/mcp/tools/relationship-tools.js.map +7 -0
  210. package/dist/mcp/tools/shared.js +25 -2
  211. package/dist/mcp/tools/shared.js.map +2 -2
  212. package/dist/mcp/tools/spec-type.js +90 -0
  213. package/dist/mcp/tools/spec-type.js.map +7 -0
  214. package/dist/schemas/bundled/analyzers/cbm.json +1186 -68
  215. package/dist/schemas/bundled/analyzers/manifest.json +2 -2
  216. package/dist/schemas/bundled/api.json +1029 -1658
  217. package/dist/schemas/bundled/apm.json +499 -734
  218. package/dist/schemas/bundled/application.json +735 -371
  219. package/dist/schemas/bundled/base.json +3 -220
  220. package/dist/schemas/bundled/business.json +452 -366
  221. package/dist/schemas/bundled/data-model.json +395 -411
  222. package/dist/schemas/bundled/data-store.json +334 -558
  223. package/dist/schemas/bundled/manifest.json +18 -18
  224. package/dist/schemas/bundled/motivation.json +349 -368
  225. package/dist/schemas/bundled/navigation.json +415 -731
  226. package/dist/schemas/bundled/product.json +325 -159
  227. package/dist/schemas/bundled/security.json +864 -1232
  228. package/dist/schemas/bundled/technology.json +574 -703
  229. package/dist/schemas/bundled/testing.json +718 -1643
  230. package/dist/schemas/bundled/ux.json +739 -1352
  231. package/dist/server/schemas.js +8 -0
  232. package/dist/server/schemas.js.map +2 -2
  233. package/dist/server/server.js +218 -34
  234. package/dist/server/server.js.map +2 -2
  235. package/dist/server-entry.js +2 -1
  236. package/dist/server-entry.js.map +2 -2
  237. package/dist/telemetry/index.js +1 -1
  238. package/dist/utils/ansi-suppressor.js +6 -8
  239. package/dist/utils/ansi-suppressor.js.map +2 -2
  240. package/dist/utils/attribute-patch.js +41 -0
  241. package/dist/utils/attribute-patch.js.map +7 -0
  242. package/dist/utils/error-hints.js +29 -0
  243. package/dist/utils/error-hints.js.map +7 -0
  244. package/dist/utils/errors.js +9 -3
  245. package/dist/utils/errors.js.map +2 -2
  246. package/dist/utils/project-paths.js +26 -1
  247. package/dist/utils/project-paths.js.map +2 -2
  248. package/dist/utils/source-reference.js +14 -12
  249. package/dist/utils/source-reference.js.map +2 -2
  250. package/dist/utils/spec-version.js +2 -2
  251. package/dist/utils/spec-version.js.map +1 -1
  252. package/dist/validators/composed-reference-validator.js +5 -27
  253. package/dist/validators/composed-reference-validator.js.map +2 -2
  254. package/dist/validators/reference-validator.js +0 -7
  255. package/dist/validators/reference-validator.js.map +2 -2
  256. package/dist/validators/relationship-schema-validator.js +3 -3
  257. package/dist/validators/relationship-schema-validator.js.map +2 -2
  258. package/dist/validators/schema-validator.js +27 -9
  259. package/dist/validators/schema-validator.js.map +2 -2
  260. package/dist/validators/types.js.map +1 -1
  261. package/dist/viewer/README.md +6 -6
  262. package/dist/viewer/assets/main-CxzcuU_o.js +84 -0
  263. package/dist/viewer/assets/main-j-7ULYpm.css +1 -0
  264. package/dist/viewer/index.html +2 -2
  265. package/dist/viewer/manifest.json +10 -10
  266. package/dist/viewer/version.json +1 -1
  267. package/package.json +2 -1
  268. package/dist/viewer/assets/main-B7AOQXXX.js +0 -81
  269. package/dist/viewer/assets/main-vdrFrG7q.css +0 -1
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/core/virtual-projection.ts"],
4
- "sourcesContent": ["/**\n * VirtualProjectionEngine - Computes merged model views by applying staged changes.\n *\n * Creates virtual (temporary) projections of the base model with staged changes applied,\n * without modifying or persisting the base model. Enables safe preview and validation\n * of changes before commit. Includes projection caching with TTL-based expiration.\n *\n * Staging changes are applied in sequence order to compute accurate merged views.\n */\n\nimport type { Model } from \"./model.js\";\nimport type { Layer } from \"./layer.js\";\nimport type { Element } from \"./element.js\";\nimport type { SourceReference, ElementMetadata } from \"../types/index.js\";\nimport type { Manifest } from \"./manifest.js\";\nimport type { Relationships } from \"./relationships.js\";\nimport { Layer as LayerClass } from \"./layer.js\";\nimport { Element as ElementClass } from \"./element.js\";\nimport type { StagedChange, Change } from \"./changeset.js\";\nimport { StagedChangesetStorage } from \"./staged-changeset-storage.js\";\n\n/**\n * Projected model with isProjection flag to prevent accidental saves.\n * This marker interface ensures that projected models are recognized as temporary\n * and cannot be persisted to disk without explicit commit of the underlying changeset.\n */\nexport interface ProjectedModel {\n manifest: Manifest;\n layers: Map<string, Layer>;\n relationships: Relationships;\n loadedLayerFilter?: string[];\n isProjection: true; // Always true; marks this as a temporary virtual projection\n}\n\n/**\n * Model diff categorizing changeset changes by type.\n * Separates staged changes into additions (new elements), modifications (updated attributes),\n * and deletions (removed elements). Used for preview and diff display operations.\n */\nexport interface ModelDiff {\n additions: Array<{\n elementId: string;\n layerName: string;\n data: Record<string, unknown>; // Complete element state (from change.after)\n }>;\n modifications: Array<{\n elementId: string;\n layerName: string;\n before: Record<string, unknown>; // Previous state (from change.before)\n after: Record<string, unknown>; // New state (from change.after)\n }>;\n deletions: Array<{\n elementId: string;\n layerName: string;\n data: Record<string, unknown>; // Element state before deletion (from change.before)\n }>;\n}\n\n/**\n * Single cached layer projection.\n * Stores the computed projected layer and timestamp for cache expiration.\n */\ninterface CacheEntry {\n layer: Layer;\n computedAt: string; // ISO timestamp for age calculation\n}\n\n/**\n * Cache hit/miss metrics for monitoring cache performance.\n * Tracks successful cache hits, misses, and invalidations per changeset.\n */\ninterface CacheMetrics {\n hits: number; // Number of successful cache hits\n misses: number; // Number of cache misses (required computation)\n invalidations: number; // Number of invalidation operations\n lastInvalidation?: string; // ISO timestamp of last invalidation\n}\n\n/**\n * Projection cache for storing computed layer projections.\n * Uses TTL-based expiration to prevent stale projections.\n * Entries are lazily removed when expired on access or during periodic cleanup.\n */\ninterface ProjectionCache {\n cache: Map<string, CacheEntry>; // Key format: `${changesetId}:${layerName}`\n metrics: Map<string, CacheMetrics>; // Cache metrics keyed by changesetId\n maxAge: number; // Cache entry TTL in milliseconds (5 minutes default)\n lastCleanup: number; // Timestamp of last cleanup to limit cleanup frequency\n}\n\n/**\n * VirtualProjectionEngine - Computes merged model views without persisting.\n * Applies staged changes to a cloned base model to compute projections.\n * Uses caching with TTL-based expiration to optimize repeated projections.\n */\nexport class VirtualProjectionEngine {\n private stagingAreaManager: StagedChangesetStorage;\n private projectionCache: ProjectionCache;\n\n /**\n * Create a new projection engine.\n *\n * @param rootPath - Root path to the model (used by StagedChangesetStorage)\n */\n constructor(rootPath: string) {\n this.stagingAreaManager = new StagedChangesetStorage(rootPath);\n this.projectionCache = {\n cache: new Map(),\n metrics: new Map(),\n maxAge: 5 * 60 * 1000, // 5-minute TTL for cached projections\n lastCleanup: Date.now(),\n };\n }\n\n /**\n * Project a single element by applying staged changes to it.\n * Merges the element's base state with staged changes to compute its projected state.\n *\n * @param baseModel - The base model to project from\n * @param changesetId - ID of the changeset containing staged changes\n * @param elementId - ID of the element to project\n * @returns Projected element with staged changes applied, or null if element is deleted\n * @throws Error if changeset not found\n *\n * @remarks\n * If multiple changes exist for the element, the last change determines final state.\n * For 'delete' operations, returns null.\n * For 'add' operations without base element, creates new element from staged data.\n * For 'update' operations, merges staged changes with base element attributes.\n */\n async projectElement(\n baseModel: Model,\n changesetId: string,\n elementId: string\n ): Promise<Element | null> {\n const changeset = await this.stagingAreaManager.load(changesetId);\n if (!changeset) {\n throw new Error(`Changeset '${changesetId}' not found`);\n }\n\n // Find all changes for this element across all layers\n const elementChanges = changeset.changes.filter(\n (c: Change) => c.elementId === elementId\n ) as StagedChange[];\n\n if (elementChanges.length === 0) {\n // No changes, return base element if it exists\n return baseModel.getElementById(elementId) || null;\n }\n\n // Get the last change to determine the element's final state\n const lastChange = elementChanges[elementChanges.length - 1];\n\n if (lastChange.type === \"delete\") {\n return null;\n }\n\n // For add or update, construct the projected element\n const baseElement = baseModel.getElementById(elementId);\n const projectedData = lastChange.after || {};\n\n if (baseElement) {\n // Create a new element with projected data merged with base\n const projectedAttributes =\n typeof projectedData.attributes === \"object\" ? projectedData.attributes : {};\n\n const mergedData = {\n id: baseElement.id,\n path: baseElement.path,\n spec_node_id: baseElement.spec_node_id,\n type: typeof projectedData.type === \"string\" ? projectedData.type : baseElement.type,\n layer_id: baseElement.layer_id,\n name: typeof projectedData.name === \"string\" ? projectedData.name : baseElement.name,\n description:\n typeof projectedData.description === \"string\"\n ? projectedData.description\n : baseElement.description,\n attributes: {\n ...baseElement.attributes,\n ...projectedAttributes,\n },\n references: Array.isArray(projectedData.references)\n ? projectedData.references\n : baseElement.references,\n relationships: Array.isArray(projectedData.relationships)\n ? projectedData.relationships\n : baseElement.relationships,\n source_reference: baseElement.source_reference,\n metadata: baseElement.metadata,\n };\n\n return new ElementClass(mergedData);\n } else if (lastChange.type === \"add\") {\n // New element being added\n return new ElementClass({\n id: (lastChange.after?.id as string) || elementId,\n path: (lastChange.after?.path as string) || elementId,\n spec_node_id: (lastChange.after?.spec_node_id as string) || \"\",\n type: (projectedData.type as string) || \"unknown\",\n layer_id: lastChange.layerName,\n name: (projectedData.name as string) || elementId,\n description: (projectedData.description as string) || \"\",\n attributes: (typeof projectedData.attributes === \"object\"\n ? projectedData.attributes\n : {}) as Record<string, unknown>,\n references: Array.isArray(projectedData.references) ? projectedData.references : [],\n relationships: Array.isArray(projectedData.relationships)\n ? projectedData.relationships\n : [],\n source_reference: projectedData.source_reference as SourceReference | undefined,\n metadata: projectedData.metadata as ElementMetadata | undefined,\n layer: lastChange.layerName,\n });\n }\n\n return null;\n }\n\n /**\n * Project a layer by applying staged changes to a clone of the base layer.\n * Checks cache first; computes and caches result if not found or expired.\n *\n * @param baseModel - The base model to project from\n * @param changesetId - ID of the changeset containing staged changes\n * @param layerName - Name of the layer to project\n * @returns Projected layer with staged changes applied\n * @throws Error if changeset or base layer not found\n *\n * @remarks\n * Computation process:\n * 1. Check projection cache (returns if found and not expired)\n * 2. Clone base layer to avoid mutations\n * 3. Load staged changes filtered to this layer\n * 4. Apply changes in sequence number order (add/update/delete)\n * 5. Cache result with timestamp for TTL tracking\n * 6. Trigger periodic cache cleanup\n */\n async projectLayer(baseModel: Model, changesetId: string, layerName: string): Promise<Layer> {\n // Check cache first\n const cacheKey = `${changesetId}:${layerName}`;\n const cached = this.projectionCache.cache.get(cacheKey);\n\n if (cached) {\n const age = Date.now() - new Date(cached.computedAt).getTime();\n if (age < this.projectionCache.maxAge) {\n // Record cache hit\n this.recordCacheHit(changesetId);\n return cached.layer;\n } else {\n // Invalidate expired entry\n this.projectionCache.cache.delete(cacheKey);\n }\n }\n\n // Record cache miss\n this.recordCacheMiss(changesetId);\n\n // Load the committed base layer \u2014 must use getBaseLayer() (not getLayer()) to avoid\n // infinite recursion: getLayer() calls projectLayer(), which would call getLayer() again.\n const baseLayer = await baseModel.getBaseLayer(layerName);\n const projectedLayer = baseLayer\n ? this.cloneLayer(baseLayer)\n : new LayerClass(layerName);\n\n // Load staged changes for this layer\n const changeset = await this.stagingAreaManager.load(changesetId);\n if (!changeset) {\n throw new Error(`Changeset '${changesetId}' not found`);\n }\n\n const layerChanges = (changeset.changes as StagedChange[])\n .filter((c: StagedChange) => c.layerName === layerName)\n .sort((a: StagedChange, b: StagedChange) => a.sequenceNumber - b.sequenceNumber);\n\n // Apply changes in sequence order\n for (const change of layerChanges) {\n switch (change.type) {\n case \"add\":\n if (change.after) {\n const newElement = new ElementClass({\n id: (change.after.id as string) || change.elementId,\n path: (change.after.path as string) || change.elementId,\n spec_node_id: (change.after.spec_node_id as string) || \"\",\n type: (change.after.type as string) || \"unknown\",\n layer_id: layerName,\n name: (change.after.name as string) || change.elementId,\n description: (change.after.description as string) || \"\",\n attributes: (typeof change.after.attributes === \"object\"\n ? change.after.attributes\n : {}) as Record<string, unknown>,\n references: Array.isArray(change.after.references) ? change.after.references : [],\n relationships: Array.isArray(change.after.relationships)\n ? change.after.relationships\n : [],\n source_reference: change.after.source_reference as SourceReference | undefined,\n metadata: change.after.metadata as ElementMetadata | undefined,\n layer: layerName,\n });\n projectedLayer.addElement(newElement);\n }\n break;\n\n case \"update\":\n if (change.after) {\n // Get the existing element to preserve all state\n const existing = projectedLayer.getElement(change.elementId);\n if (existing) {\n // Create updated element with merged attributes\n const afterAttributes =\n typeof change.after.attributes === \"object\" ? change.after.attributes : {};\n\n const mergedAttributes: Record<string, unknown> = {\n ...existing.attributes,\n ...afterAttributes,\n };\n\n const updatedElement = new ElementClass({\n id: existing.id,\n path: existing.path,\n spec_node_id: existing.spec_node_id,\n layer_id: existing.layer_id,\n type: typeof change.after.type === \"string\" ? change.after.type : existing.type,\n name: typeof change.after.name === \"string\" ? change.after.name : existing.name,\n description:\n typeof change.after.description === \"string\"\n ? change.after.description\n : existing.description,\n attributes: mergedAttributes,\n references: Array.isArray(change.after.references)\n ? change.after.references\n : existing.references,\n relationships: Array.isArray(change.after.relationships)\n ? change.after.relationships\n : existing.relationships,\n layer: layerName,\n source_reference: existing.source_reference,\n metadata: existing.metadata,\n });\n\n projectedLayer.updateElement(updatedElement);\n }\n }\n break;\n\n case \"delete\":\n const existingForDelete = projectedLayer.getElement(change.elementId);\n if (existingForDelete) {\n projectedLayer.deleteElement(existingForDelete.path || existingForDelete.id);\n }\n break;\n\n case \"relationship-add\":\n case \"relationship-delete\":\n // Relationship changes are handled at the model level (model.relationships),\n // not the layer level. Skip here; no layer mutation needed.\n break;\n }\n }\n\n // Cache the result\n const cacheEntry: CacheEntry = {\n layer: projectedLayer,\n computedAt: new Date().toISOString(),\n };\n this.projectionCache.cache.set(cacheKey, cacheEntry);\n\n // Periodic cleanup of expired entries\n this.cleanupExpiredCache();\n\n return projectedLayer;\n }\n\n /**\n * Project entire model by applying staged changes to all layers.\n * Creates a complete projected model view that includes both changed and unchanged layers.\n *\n * @param baseModel - The base model to project from\n * @param changesetId - ID of the changeset containing staged changes\n * @returns ProjectedModel with isProjection=true flag (prevents accidental saves)\n * @throws Error if changeset not found\n *\n * @remarks\n * Projection includes:\n * - All layers mentioned in changeset changes\n * - All layers from base model (to have complete model state)\n * - Base model's manifest (unchanged)\n * Returned model has isProjection=true to prevent accidental persistence.\n */\n async projectModel(baseModel: Model, changesetId: string): Promise<ProjectedModel> {\n const changeset = await this.stagingAreaManager.load(changesetId);\n if (!changeset) {\n throw new Error(`Changeset '${changesetId}' not found`);\n }\n\n const projectedLayers = new Map<string, Layer>();\n\n // Project all layers mentioned in the changeset\n const layerNames = new Set<string>();\n for (const change of changeset.changes) {\n layerNames.add(change.layerName);\n }\n\n // Also include all base layers to get complete model\n for (const baseLayerName of baseModel.getLayerNames()) {\n layerNames.add(baseLayerName);\n }\n\n // Project each layer\n for (const layerName of layerNames) {\n const projectedLayer = await this.projectLayer(baseModel, changesetId, layerName);\n projectedLayers.set(layerName, projectedLayer);\n }\n\n // Create projected model with isProjection flag\n const projectedModel: ProjectedModel = {\n manifest: baseModel.manifest,\n layers: projectedLayers,\n relationships: baseModel.relationships,\n loadedLayerFilter: baseModel.loadedLayerFilter,\n isProjection: true,\n };\n\n return projectedModel;\n }\n\n /**\n * Compute diff by categorizing changeset changes by type.\n * Extracts the staged changes and organizes them into additions, modifications, and deletions.\n *\n * @param _baseModel - The base model (unused; included for interface compatibility)\n * @param changesetId - ID of the changeset to compute diff for\n * @returns ModelDiff with changes categorized by type\n * @throws Error if changeset not found\n *\n * @remarks\n * Diff is computed directly from changeset changes; does not perform deep comparison.\n * Each change's before/after snapshots are included for detailed display.\n */\n async computeDiff(_baseModel: Model, changesetId: string): Promise<ModelDiff> {\n const changeset = await this.stagingAreaManager.load(changesetId);\n if (!changeset) {\n throw new Error(`Changeset '${changesetId}' not found`);\n }\n\n const changes = changeset.changes as StagedChange[];\n\n return {\n additions: changes\n .filter((c: StagedChange) => c.type === \"add\")\n .map((c: StagedChange) => ({\n elementId: c.elementId,\n layerName: c.layerName,\n data: c.after || {},\n })),\n\n modifications: changes\n .filter((c: StagedChange) => c.type === \"update\")\n .map((c: StagedChange) => ({\n elementId: c.elementId,\n layerName: c.layerName,\n before: c.before || {},\n after: c.after || {},\n })),\n\n deletions: changes\n .filter((c: StagedChange) => c.type === \"delete\")\n .map((c: StagedChange) => ({\n elementId: c.elementId,\n layerName: c.layerName,\n data: c.before || {},\n })),\n };\n }\n\n /**\n * Get affected layers for an element in a changeset.\n * Returns all layers that have cached projections and contain changes for the element.\n *\n * @param changesetId - ID of the changeset\n * @param elementId - ID of the element being unstaged\n * @returns Set of affected layer names\n *\n * @remarks\n * When unstaging an element, only the layers where that element was modified\n * need cache invalidation. This enables granular invalidation instead of\n * invalidating the entire changeset cache.\n */\n private async getAffectedLayers(changesetId: string, elementId: string): Promise<Set<string>> {\n const affectedLayers = new Set<string>();\n\n try {\n const changeset = await this.stagingAreaManager.load(changesetId);\n if (!changeset) {\n return affectedLayers;\n }\n\n // Find all layers that have changes for this element\n for (const change of changeset.changes) {\n if (change.elementId === elementId) {\n affectedLayers.add(change.layerName);\n }\n }\n } catch {\n // If changeset can't be loaded, return empty set (no invalidation needed)\n // This handles the case where changeset is deleted or corrupted\n }\n\n return affectedLayers;\n }\n\n /**\n * Record a cache hit for metrics tracking.\n *\n * @param changesetId - ID of the changeset\n */\n private recordCacheHit(changesetId: string): void {\n const metrics = this.projectionCache.metrics.get(changesetId) || {\n hits: 0,\n misses: 0,\n invalidations: 0,\n };\n metrics.hits++;\n this.projectionCache.metrics.set(changesetId, metrics);\n }\n\n /**\n * Record a cache miss for metrics tracking.\n *\n * @param changesetId - ID of the changeset\n */\n private recordCacheMiss(changesetId: string): void {\n const metrics = this.projectionCache.metrics.get(changesetId) || {\n hits: 0,\n misses: 0,\n invalidations: 0,\n };\n metrics.misses++;\n this.projectionCache.metrics.set(changesetId, metrics);\n }\n\n /**\n * Record a cache invalidation for metrics tracking.\n *\n * @param changesetId - ID of the changeset\n */\n private recordInvalidation(changesetId: string): void {\n const metrics = this.projectionCache.metrics.get(changesetId) || {\n hits: 0,\n misses: 0,\n invalidations: 0,\n };\n metrics.invalidations++;\n metrics.lastInvalidation = new Date().toISOString();\n this.projectionCache.metrics.set(changesetId, metrics);\n }\n\n /**\n * Get cache metrics for a changeset (for monitoring and debugging).\n *\n * @param changesetId - ID of the changeset\n * @returns Cache metrics or undefined if no metrics exist\n */\n getCacheMetrics(changesetId: string): CacheMetrics | undefined {\n return this.projectionCache.metrics.get(changesetId);\n }\n\n /**\n * Invalidate projection cache when changes are staged.\n * Removes cached projections to ensure fresh computation next time.\n *\n * @param changesetId - ID of the changeset being modified\n * @param layerName - Optional: specific layer to invalidate (all if omitted)\n *\n * @remarks\n * If layerName is provided, only that layer's projection is invalidated.\n * Otherwise, all projections for the changeset are invalidated.\n */\n invalidateOnStage(changesetId: string, layerName?: string): void {\n if (layerName) {\n // Invalidate specific layer projection\n const cacheKey = `${changesetId}:${layerName}`;\n this.projectionCache.cache.delete(cacheKey);\n this.recordInvalidation(changesetId);\n } else {\n // Invalidate all projections for this changeset\n for (const key of this.projectionCache.cache.keys()) {\n if (key.startsWith(`${changesetId}:`)) {\n this.projectionCache.cache.delete(key);\n }\n }\n this.recordInvalidation(changesetId);\n }\n }\n\n /**\n * Invalidate projection cache when changes are unstaged.\n * Uses layer-specific invalidation for the affected element's layers.\n *\n * @param changesetId - ID of the changeset being modified\n * @param elementId - Optional: ID of element being unstaged (enables granular invalidation)\n *\n * @remarks\n * If elementId is provided, only the layers containing that element are invalidated.\n * This is more efficient than invalidating the entire changeset cache when\n * unstaging elements from a multi-layer changeset.\n * If elementId is omitted, invalidates all projections for the changeset.\n */\n async invalidateOnUnstage(changesetId: string, elementId?: string): Promise<void> {\n if (elementId) {\n // Layer-specific invalidation: only invalidate affected layers\n const affectedLayers = await this.getAffectedLayers(changesetId, elementId);\n for (const layerName of affectedLayers) {\n const cacheKey = `${changesetId}:${layerName}`;\n this.projectionCache.cache.delete(cacheKey);\n }\n if (affectedLayers.size > 0) {\n this.recordInvalidation(changesetId);\n }\n } else {\n // Full invalidation: clear all projections for this changeset\n for (const key of this.projectionCache.cache.keys()) {\n if (key.startsWith(`${changesetId}:`)) {\n this.projectionCache.cache.delete(key);\n }\n }\n this.recordInvalidation(changesetId);\n }\n }\n\n /**\n * Invalidate all projections for a changeset when it's discarded.\n * Clears all cached projections for this changeset to free memory.\n *\n * @param changesetId - ID of the changeset being discarded\n */\n invalidateOnDiscard(changesetId: string): void {\n for (const key of this.projectionCache.cache.keys()) {\n if (key.startsWith(`${changesetId}:`)) {\n this.projectionCache.cache.delete(key);\n }\n }\n }\n\n /**\n * Clone a layer to create an independent copy.\n * Shallow clones all elements and metadata to avoid mutations.\n * Cloned layer is marked clean to prevent unintended saves.\n *\n * @param layer - The layer to clone\n * @returns New layer with cloned elements and metadata\n *\n * @remarks\n * Cloning strategy:\n * 1. Create new Layer with same name\n * 2. Clone each element: shallow copy attributes object and array references\n * 3. Copy layer metadata if present\n * 4. Mark cloned layer as clean to prevent automatic saves\n * This ensures changes to projection don't affect base layer.\n * Note: Shallow cloning is sufficient since attributes are read-only in projections.\n */\n private cloneLayer(layer: Layer): Layer {\n const cloned = new LayerClass(layer.name);\n\n // Clone all elements (shallow copy - read-only in projection)\n for (const element of layer.listElements()) {\n const elementClone = new ElementClass({\n id: element.id,\n path: element.path,\n spec_node_id: element.spec_node_id,\n type: element.type,\n layer_id: element.layer_id,\n name: element.name,\n description: element.description,\n attributes: { ...element.attributes },\n references: [...(element.references || [])],\n relationships: [...(element.relationships || [])],\n layer: element.layer,\n source_reference: element.source_reference,\n metadata: element.metadata,\n });\n cloned.addElement(elementClone);\n }\n\n // Preserve layer metadata if present\n if (layer.metadata) {\n cloned.metadata = { ...layer.metadata };\n }\n\n // Mark as clean to prevent projection from being saved\n cloned.markClean();\n return cloned;\n }\n\n /**\n * Clean up expired cache entries periodically (every 60 seconds).\n * Removes entries that exceed the maxAge TTL.\n * Runs at most once per minute to limit overhead.\n *\n * @remarks\n * Cleanup is triggered after each projection computation.\n * Early exit if last cleanup was less than 60 seconds ago.\n * Entries are marked for deletion based on age calculation from computedAt timestamp.\n */\n private cleanupExpiredCache(): void {\n const now = Date.now();\n\n // Limit cleanup frequency to at most every 60 seconds\n if (now - this.projectionCache.lastCleanup < 60 * 1000) {\n return;\n }\n\n // Remove entries that have exceeded their TTL\n for (const [key, entry] of this.projectionCache.cache.entries()) {\n const age = now - new Date(entry.computedAt).getTime();\n if (age >= this.projectionCache.maxAge) {\n this.projectionCache.cache.delete(key);\n }\n }\n\n this.projectionCache.lastCleanup = now;\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * VirtualProjectionEngine - Computes merged model views by applying staged changes.\n *\n * Creates virtual (temporary) projections of the base model with staged changes applied,\n * without modifying or persisting the base model. Enables safe preview and validation\n * of changes before commit. Includes projection caching with TTL-based expiration.\n *\n * Staging changes are applied in sequence order to compute accurate merged views.\n */\n\nimport type { Model } from \"./model.js\";\nimport type { Layer } from \"./layer.js\";\nimport type { Element } from \"./element.js\";\nimport type { ElementMetadata } from \"../types/index.js\";\nimport { readStagedSourceReference, stagedSourceReference } from \"./staged-source-reference.js\";\nimport type { Manifest } from \"./manifest.js\";\nimport type { Relationships } from \"./relationships.js\";\nimport { Layer as LayerClass } from \"./layer.js\";\nimport { Element as ElementClass } from \"./element.js\";\nimport type { StagedChange, Change } from \"./changeset.js\";\nimport { withSequenceNumbers } from \"./changeset.js\";\nimport { StagedChangesetStorage } from \"./staged-changeset-storage.js\";\n\n/**\n * Projected model with isProjection flag to prevent accidental saves.\n * This marker interface ensures that projected models are recognized as temporary\n * and cannot be persisted to disk without explicit commit of the underlying changeset.\n */\nexport interface ProjectedModel {\n manifest: Manifest;\n layers: Map<string, Layer>;\n relationships: Relationships;\n loadedLayerFilter?: string[];\n isProjection: true; // Always true; marks this as a temporary virtual projection\n}\n\n/**\n * Model diff categorizing changeset changes by type.\n * Separates staged changes into additions (new elements), modifications (updated attributes),\n * and deletions (removed elements). Used for preview and diff display operations.\n */\nexport interface ModelDiff {\n additions: Array<{\n elementId: string;\n layerName: string;\n data: Record<string, unknown>; // Complete element state (from change.after)\n }>;\n modifications: Array<{\n elementId: string;\n layerName: string;\n before: Record<string, unknown>; // Previous state (from change.before)\n after: Record<string, unknown>; // New state (from change.after)\n }>;\n deletions: Array<{\n elementId: string;\n layerName: string;\n data: Record<string, unknown>; // Element state before deletion (from change.before)\n }>;\n}\n\n/**\n * Single cached layer projection.\n * Stores the computed projected layer and timestamp for cache expiration.\n */\ninterface CacheEntry {\n layer: Layer;\n computedAt: string; // ISO timestamp for age calculation\n}\n\n/**\n * Cache hit/miss metrics for monitoring cache performance.\n * Tracks successful cache hits, misses, and invalidations per changeset.\n */\ninterface CacheMetrics {\n hits: number; // Number of successful cache hits\n misses: number; // Number of cache misses (required computation)\n invalidations: number; // Number of invalidation operations\n lastInvalidation?: string; // ISO timestamp of last invalidation\n}\n\n/**\n * Projection cache for storing computed layer projections.\n * Uses TTL-based expiration to prevent stale projections.\n * Entries are lazily removed when expired on access or during periodic cleanup.\n */\ninterface ProjectionCache {\n cache: Map<string, CacheEntry>; // Key format: `${changesetId}:${layerName}`\n metrics: Map<string, CacheMetrics>; // Cache metrics keyed by changesetId\n maxAge: number; // Cache entry TTL in milliseconds (5 minutes default)\n lastCleanup: number; // Timestamp of last cleanup to limit cleanup frequency\n}\n\n/**\n * VirtualProjectionEngine - Computes merged model views without persisting.\n * Applies staged changes to a cloned base model to compute projections.\n * Uses caching with TTL-based expiration to optimize repeated projections.\n */\nexport class VirtualProjectionEngine {\n private stagingAreaManager: StagedChangesetStorage;\n private projectionCache: ProjectionCache;\n\n /**\n * Create a new projection engine.\n *\n * @param rootPath - Root path to the model (used by StagedChangesetStorage)\n */\n constructor(rootPath: string) {\n this.stagingAreaManager = new StagedChangesetStorage(rootPath);\n this.projectionCache = {\n cache: new Map(),\n metrics: new Map(),\n maxAge: 5 * 60 * 1000, // 5-minute TTL for cached projections\n lastCleanup: Date.now(),\n };\n }\n\n /**\n * Project a single element by applying staged changes to it.\n * Merges the element's base state with staged changes to compute its projected state.\n *\n * @param baseModel - The base model to project from\n * @param changesetId - ID of the changeset containing staged changes\n * @param elementId - ID of the element to project\n * @returns Projected element with staged changes applied, or null if element is deleted\n * @throws Error if changeset not found\n *\n * @remarks\n * If multiple changes exist for the element, the last change determines final state.\n * For 'delete' operations, returns null.\n * For 'add' operations without base element, creates new element from staged data.\n * For 'update' operations, merges staged changes with base element attributes.\n */\n async projectElement(\n baseModel: Model,\n changesetId: string,\n elementId: string\n ): Promise<Element | null> {\n const changeset = await this.stagingAreaManager.load(changesetId);\n if (!changeset) {\n throw new Error(`Changeset '${changesetId}' not found`);\n }\n\n // Find all changes for this element across all layers\n const elementChanges = changeset.changes.filter(\n (c: Change) => c.elementId === elementId\n ) as StagedChange[];\n\n if (elementChanges.length === 0) {\n // No changes, return base element if it exists\n return baseModel.getElementById(elementId) || null;\n }\n\n // Get the last change to determine the element's final state\n const lastChange = elementChanges[elementChanges.length - 1];\n\n if (lastChange.type === \"delete\") {\n return null;\n }\n\n // For add or update, construct the projected element\n const baseElement = baseModel.getElementById(elementId);\n const projectedData = lastChange.after || {};\n\n if (baseElement) {\n // Create a new element with projected data merged with base\n const projectedAttributes =\n typeof projectedData.attributes === \"object\" ? projectedData.attributes : {};\n\n const mergedData = {\n id: baseElement.id,\n path: baseElement.path,\n spec_node_id: baseElement.spec_node_id,\n type: typeof projectedData.type === \"string\" ? projectedData.type : baseElement.type,\n layer_id: baseElement.layer_id,\n name: typeof projectedData.name === \"string\" ? projectedData.name : baseElement.name,\n description:\n typeof projectedData.description === \"string\"\n ? projectedData.description\n : baseElement.description,\n attributes: {\n ...baseElement.attributes,\n ...projectedAttributes,\n },\n references: Array.isArray(projectedData.references)\n ? projectedData.references\n : baseElement.references,\n relationships: Array.isArray(projectedData.relationships)\n ? projectedData.relationships\n : baseElement.relationships,\n source_reference: (() => {\n const staged = readStagedSourceReference(projectedData);\n return staged.present ? staged.value : baseElement.source_reference;\n })(),\n metadata: baseElement.metadata,\n };\n\n return new ElementClass(mergedData);\n } else if (lastChange.type === \"add\") {\n // New element being added\n return new ElementClass({\n id: (lastChange.after?.id as string) || elementId,\n path: (lastChange.after?.path as string) || elementId,\n spec_node_id: (lastChange.after?.spec_node_id as string) || \"\",\n type: (projectedData.type as string) || \"unknown\",\n layer_id: lastChange.layerName,\n name: (projectedData.name as string) || elementId,\n description: (projectedData.description as string) || \"\",\n attributes: (typeof projectedData.attributes === \"object\"\n ? projectedData.attributes\n : {}) as Record<string, unknown>,\n references: Array.isArray(projectedData.references) ? projectedData.references : [],\n relationships: Array.isArray(projectedData.relationships)\n ? projectedData.relationships\n : [],\n source_reference: stagedSourceReference(projectedData),\n metadata: projectedData.metadata as ElementMetadata | undefined,\n layer: lastChange.layerName,\n });\n }\n\n return null;\n }\n\n /**\n * Project a layer by applying staged changes to a clone of the base layer.\n * Checks cache first; computes and caches result if not found or expired.\n *\n * @param baseModel - The base model to project from\n * @param changesetId - ID of the changeset containing staged changes\n * @param layerName - Name of the layer to project\n * @returns Projected layer with staged changes applied\n * @throws Error if changeset or base layer not found\n *\n * @remarks\n * Computation process:\n * 1. Check projection cache (returns if found and not expired)\n * 2. Clone base layer to avoid mutations\n * 3. Load staged changes filtered to this layer\n * 4. Apply changes in sequence number order (add/update/delete)\n * 5. Cache result with timestamp for TTL tracking\n * 6. Trigger periodic cache cleanup\n */\n async projectLayer(baseModel: Model, changesetId: string, layerName: string): Promise<Layer> {\n // Check cache first\n const cacheKey = `${changesetId}:${layerName}`;\n const cached = this.projectionCache.cache.get(cacheKey);\n\n if (cached) {\n const age = Date.now() - new Date(cached.computedAt).getTime();\n if (age < this.projectionCache.maxAge) {\n // Record cache hit\n this.recordCacheHit(changesetId);\n return cached.layer;\n } else {\n // Invalidate expired entry\n this.projectionCache.cache.delete(cacheKey);\n }\n }\n\n // Record cache miss\n this.recordCacheMiss(changesetId);\n\n // Load the committed base layer \u2014 must use getBaseLayer() (not getLayer()) to avoid\n // infinite recursion: getLayer() calls projectLayer(), which would call getLayer() again.\n const baseLayer = await baseModel.getBaseLayer(layerName);\n const projectedLayer = baseLayer\n ? this.cloneLayer(baseLayer)\n : new LayerClass(layerName);\n\n // Load staged changes for this layer\n const changeset = await this.stagingAreaManager.load(changesetId);\n if (!changeset) {\n throw new Error(`Changeset '${changesetId}' not found`);\n }\n\n const layerChanges = withSequenceNumbers(changeset.changes)\n .filter((c: StagedChange) => c.layerName === layerName)\n .sort((a: StagedChange, b: StagedChange) => a.sequenceNumber - b.sequenceNumber);\n\n // Apply changes in sequence order\n for (const change of layerChanges) {\n switch (change.type) {\n case \"add\":\n if (change.after) {\n const newElement = new ElementClass({\n id: (change.after.id as string) || change.elementId,\n path: (change.after.path as string) || change.elementId,\n spec_node_id: (change.after.spec_node_id as string) || \"\",\n type: (change.after.type as string) || \"unknown\",\n layer_id: layerName,\n name: (change.after.name as string) || change.elementId,\n description: (change.after.description as string) || \"\",\n attributes: (typeof change.after.attributes === \"object\"\n ? change.after.attributes\n : {}) as Record<string, unknown>,\n references: Array.isArray(change.after.references) ? change.after.references : [],\n relationships: Array.isArray(change.after.relationships)\n ? change.after.relationships\n : [],\n source_reference: stagedSourceReference(change.after),\n metadata: change.after.metadata as ElementMetadata | undefined,\n layer: layerName,\n });\n projectedLayer.addElement(newElement);\n }\n break;\n\n case \"update\":\n if (change.after) {\n // Get the existing element to preserve all state\n const existing = projectedLayer.getElement(change.elementId);\n if (existing) {\n // Create updated element with merged attributes\n const afterAttributes =\n typeof change.after.attributes === \"object\" ? change.after.attributes : {};\n\n const mergedAttributes: Record<string, unknown> = {\n ...existing.attributes,\n ...afterAttributes,\n };\n\n const updatedElement = new ElementClass({\n id: existing.id,\n path: existing.path,\n spec_node_id: existing.spec_node_id,\n layer_id: existing.layer_id,\n type: typeof change.after.type === \"string\" ? change.after.type : existing.type,\n name: typeof change.after.name === \"string\" ? change.after.name : existing.name,\n description:\n typeof change.after.description === \"string\"\n ? change.after.description\n : existing.description,\n attributes: mergedAttributes,\n references: Array.isArray(change.after.references)\n ? change.after.references\n : existing.references,\n relationships: Array.isArray(change.after.relationships)\n ? change.after.relationships\n : existing.relationships,\n layer: layerName,\n source_reference: (() => {\n const staged = readStagedSourceReference(change.after);\n return staged.present ? staged.value : existing.source_reference;\n })(),\n metadata: existing.metadata,\n });\n\n projectedLayer.updateElement(updatedElement);\n }\n }\n break;\n\n case \"delete\":\n const existingForDelete = projectedLayer.getElement(change.elementId);\n if (existingForDelete) {\n projectedLayer.deleteElement(existingForDelete.path || existingForDelete.id);\n }\n break;\n\n case \"relationship-add\":\n case \"relationship-delete\":\n // Relationship changes are handled at the model level (model.relationships),\n // not the layer level. Skip here; no layer mutation needed.\n break;\n }\n }\n\n // Cache the result\n const cacheEntry: CacheEntry = {\n layer: projectedLayer,\n computedAt: new Date().toISOString(),\n };\n this.projectionCache.cache.set(cacheKey, cacheEntry);\n\n // Periodic cleanup of expired entries\n this.cleanupExpiredCache();\n\n return projectedLayer;\n }\n\n /**\n * Project entire model by applying staged changes to all layers.\n * Creates a complete projected model view that includes both changed and unchanged layers.\n *\n * @param baseModel - The base model to project from\n * @param changesetId - ID of the changeset containing staged changes\n * @returns ProjectedModel with isProjection=true flag (prevents accidental saves)\n * @throws Error if changeset not found\n *\n * @remarks\n * Projection includes:\n * - All layers mentioned in changeset changes\n * - All layers from base model (to have complete model state)\n * - Base model's manifest (unchanged)\n * Returned model has isProjection=true to prevent accidental persistence.\n */\n async projectModel(baseModel: Model, changesetId: string): Promise<ProjectedModel> {\n const changeset = await this.stagingAreaManager.load(changesetId);\n if (!changeset) {\n throw new Error(`Changeset '${changesetId}' not found`);\n }\n\n const projectedLayers = new Map<string, Layer>();\n\n // Project all layers mentioned in the changeset\n const layerNames = new Set<string>();\n for (const change of changeset.changes) {\n layerNames.add(change.layerName);\n }\n\n // Also include all base layers to get complete model\n for (const baseLayerName of baseModel.getLayerNames()) {\n layerNames.add(baseLayerName);\n }\n\n // Project each layer\n for (const layerName of layerNames) {\n const projectedLayer = await this.projectLayer(baseModel, changesetId, layerName);\n projectedLayers.set(layerName, projectedLayer);\n }\n\n // Create projected model with isProjection flag\n const projectedModel: ProjectedModel = {\n manifest: baseModel.manifest,\n layers: projectedLayers,\n relationships: baseModel.relationships,\n loadedLayerFilter: baseModel.loadedLayerFilter,\n isProjection: true,\n };\n\n return projectedModel;\n }\n\n /**\n * Compute diff by categorizing changeset changes by type.\n * Extracts the staged changes and organizes them into additions, modifications, and deletions.\n *\n * @param _baseModel - The base model (unused; included for interface compatibility)\n * @param changesetId - ID of the changeset to compute diff for\n * @returns ModelDiff with changes categorized by type\n * @throws Error if changeset not found\n *\n * @remarks\n * Diff is computed directly from changeset changes; does not perform deep comparison.\n * Each change's before/after snapshots are included for detailed display.\n */\n async computeDiff(_baseModel: Model, changesetId: string): Promise<ModelDiff> {\n const changeset = await this.stagingAreaManager.load(changesetId);\n if (!changeset) {\n throw new Error(`Changeset '${changesetId}' not found`);\n }\n\n const changes = changeset.changes as StagedChange[];\n\n return {\n additions: changes\n .filter((c: StagedChange) => c.type === \"add\")\n .map((c: StagedChange) => ({\n elementId: c.elementId,\n layerName: c.layerName,\n data: c.after || {},\n })),\n\n modifications: changes\n .filter((c: StagedChange) => c.type === \"update\")\n .map((c: StagedChange) => ({\n elementId: c.elementId,\n layerName: c.layerName,\n before: c.before || {},\n after: c.after || {},\n })),\n\n deletions: changes\n .filter((c: StagedChange) => c.type === \"delete\")\n .map((c: StagedChange) => ({\n elementId: c.elementId,\n layerName: c.layerName,\n data: c.before || {},\n })),\n };\n }\n\n /**\n * Get affected layers for an element in a changeset.\n * Returns all layers that have cached projections and contain changes for the element.\n *\n * @param changesetId - ID of the changeset\n * @param elementId - ID of the element being unstaged\n * @returns Set of affected layer names\n *\n * @remarks\n * When unstaging an element, only the layers where that element was modified\n * need cache invalidation. This enables granular invalidation instead of\n * invalidating the entire changeset cache.\n */\n private async getAffectedLayers(changesetId: string, elementId: string): Promise<Set<string>> {\n const affectedLayers = new Set<string>();\n\n try {\n const changeset = await this.stagingAreaManager.load(changesetId);\n if (!changeset) {\n return affectedLayers;\n }\n\n // Find all layers that have changes for this element\n for (const change of changeset.changes) {\n if (change.elementId === elementId) {\n affectedLayers.add(change.layerName);\n }\n }\n } catch {\n // If changeset can't be loaded, return empty set (no invalidation needed)\n // This handles the case where changeset is deleted or corrupted\n }\n\n return affectedLayers;\n }\n\n /**\n * Record a cache hit for metrics tracking.\n *\n * @param changesetId - ID of the changeset\n */\n private recordCacheHit(changesetId: string): void {\n const metrics = this.projectionCache.metrics.get(changesetId) || {\n hits: 0,\n misses: 0,\n invalidations: 0,\n };\n metrics.hits++;\n this.projectionCache.metrics.set(changesetId, metrics);\n }\n\n /**\n * Record a cache miss for metrics tracking.\n *\n * @param changesetId - ID of the changeset\n */\n private recordCacheMiss(changesetId: string): void {\n const metrics = this.projectionCache.metrics.get(changesetId) || {\n hits: 0,\n misses: 0,\n invalidations: 0,\n };\n metrics.misses++;\n this.projectionCache.metrics.set(changesetId, metrics);\n }\n\n /**\n * Record a cache invalidation for metrics tracking.\n *\n * @param changesetId - ID of the changeset\n */\n private recordInvalidation(changesetId: string): void {\n const metrics = this.projectionCache.metrics.get(changesetId) || {\n hits: 0,\n misses: 0,\n invalidations: 0,\n };\n metrics.invalidations++;\n metrics.lastInvalidation = new Date().toISOString();\n this.projectionCache.metrics.set(changesetId, metrics);\n }\n\n /**\n * Get cache metrics for a changeset (for monitoring and debugging).\n *\n * @param changesetId - ID of the changeset\n * @returns Cache metrics or undefined if no metrics exist\n */\n getCacheMetrics(changesetId: string): CacheMetrics | undefined {\n return this.projectionCache.metrics.get(changesetId);\n }\n\n /**\n * Invalidate projection cache when changes are staged.\n * Removes cached projections to ensure fresh computation next time.\n *\n * @param changesetId - ID of the changeset being modified\n * @param layerName - Optional: specific layer to invalidate (all if omitted)\n *\n * @remarks\n * If layerName is provided, only that layer's projection is invalidated.\n * Otherwise, all projections for the changeset are invalidated.\n */\n invalidateOnStage(changesetId: string, layerName?: string): void {\n if (layerName) {\n // Invalidate specific layer projection\n const cacheKey = `${changesetId}:${layerName}`;\n this.projectionCache.cache.delete(cacheKey);\n this.recordInvalidation(changesetId);\n } else {\n // Invalidate all projections for this changeset\n for (const key of this.projectionCache.cache.keys()) {\n if (key.startsWith(`${changesetId}:`)) {\n this.projectionCache.cache.delete(key);\n }\n }\n this.recordInvalidation(changesetId);\n }\n }\n\n /**\n * Invalidate projection cache when changes are unstaged.\n * Uses layer-specific invalidation for the affected element's layers.\n *\n * @param changesetId - ID of the changeset being modified\n * @param elementId - Optional: ID of element being unstaged (enables granular invalidation)\n *\n * @remarks\n * If elementId is provided, only the layers containing that element are invalidated.\n * This is more efficient than invalidating the entire changeset cache when\n * unstaging elements from a multi-layer changeset.\n * If elementId is omitted, invalidates all projections for the changeset.\n */\n async invalidateOnUnstage(changesetId: string, elementId?: string): Promise<void> {\n if (elementId) {\n // Layer-specific invalidation: only invalidate affected layers\n const affectedLayers = await this.getAffectedLayers(changesetId, elementId);\n for (const layerName of affectedLayers) {\n const cacheKey = `${changesetId}:${layerName}`;\n this.projectionCache.cache.delete(cacheKey);\n }\n if (affectedLayers.size > 0) {\n this.recordInvalidation(changesetId);\n }\n } else {\n // Full invalidation: clear all projections for this changeset\n for (const key of this.projectionCache.cache.keys()) {\n if (key.startsWith(`${changesetId}:`)) {\n this.projectionCache.cache.delete(key);\n }\n }\n this.recordInvalidation(changesetId);\n }\n }\n\n /**\n * Invalidate all projections for a changeset when it's discarded.\n * Clears all cached projections for this changeset to free memory.\n *\n * @param changesetId - ID of the changeset being discarded\n */\n invalidateOnDiscard(changesetId: string): void {\n for (const key of this.projectionCache.cache.keys()) {\n if (key.startsWith(`${changesetId}:`)) {\n this.projectionCache.cache.delete(key);\n }\n }\n }\n\n /**\n * Clone a layer to create an independent copy.\n * Shallow clones all elements and metadata to avoid mutations.\n * Cloned layer is marked clean to prevent unintended saves.\n *\n * @param layer - The layer to clone\n * @returns New layer with cloned elements and metadata\n *\n * @remarks\n * Cloning strategy:\n * 1. Create new Layer with same name\n * 2. Clone each element: shallow copy attributes object and array references\n * 3. Copy layer metadata if present\n * 4. Mark cloned layer as clean to prevent automatic saves\n * This ensures changes to projection don't affect base layer.\n * Note: Shallow cloning is sufficient since attributes are read-only in projections.\n */\n private cloneLayer(layer: Layer): Layer {\n const cloned = new LayerClass(layer.name);\n\n // Clone all elements (shallow copy - read-only in projection)\n for (const element of layer.listElements()) {\n const elementClone = new ElementClass({\n id: element.id,\n path: element.path,\n spec_node_id: element.spec_node_id,\n type: element.type,\n layer_id: element.layer_id,\n name: element.name,\n description: element.description,\n attributes: { ...element.attributes },\n references: [...(element.references || [])],\n relationships: [...(element.relationships || [])],\n layer: element.layer,\n source_reference: element.source_reference,\n metadata: element.metadata,\n });\n cloned.addElement(elementClone);\n }\n\n // Preserve layer metadata if present\n if (layer.metadata) {\n cloned.metadata = { ...layer.metadata };\n }\n\n // Mark as clean to prevent projection from being saved\n cloned.markClean();\n return cloned;\n }\n\n /**\n * Clean up expired cache entries periodically (every 60 seconds).\n * Removes entries that exceed the maxAge TTL.\n * Runs at most once per minute to limit overhead.\n *\n * @remarks\n * Cleanup is triggered after each projection computation.\n * Early exit if last cleanup was less than 60 seconds ago.\n * Entries are marked for deletion based on age calculation from computedAt timestamp.\n */\n private cleanupExpiredCache(): void {\n const now = Date.now();\n\n // Limit cleanup frequency to at most every 60 seconds\n if (now - this.projectionCache.lastCleanup < 60 * 1000) {\n return;\n }\n\n // Remove entries that have exceeded their TTL\n for (const [key, entry] of this.projectionCache.cache.entries()) {\n const age = now - new Date(entry.computedAt).getTime();\n if (age >= this.projectionCache.maxAge) {\n this.projectionCache.cache.delete(key);\n }\n }\n\n this.projectionCache.lastCleanup = now;\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -88,6 +88,7 @@ class ArchiMateExporter {
88
88
  businessevent: "BusinessEvent",
89
89
  businessservice: "BusinessService",
90
90
  businessobject: "BusinessObject",
91
+ businesscapability: "Capability",
91
92
  contract: "Contract",
92
93
  product: "Product",
93
94
  representation: "Representation"
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/export/archimate-exporter.ts"],
4
- "sourcesContent": ["import type { Model } from \"../core/model.js\";\nimport type { Exporter, ExportOptions } from \"./types.js\";\nimport { escapeXml } from \"./types.js\";\nimport { isTelemetryEnabled, startSpan, endSpan } from \"../telemetry/index.js\";\nimport { getErrorMessage } from \"../utils/errors.js\";\n\n/**\n * ArchiMate XML Exporter for layers 1, 2, 5, 6 (Motivation, Business, Application, Technology)\n * Generates valid ArchiMate 3.2 XML format\n * Note: Product layer (layer 3) does not participate in ArchiMate export\n */\nexport class ArchiMateExporter implements Exporter {\n name = \"ArchiMate\";\n supportedLayers = [\"motivation\", \"business\", \"application\", \"technology\"];\n\n async export(model: Model, options: ExportOptions = {}): Promise<string> {\n const span = isTelemetryEnabled\n ? startSpan(\"export.format.archimate\", {\n \"export.layerCount\": options.layers?.length || this.supportedLayers.length,\n })\n : null;\n\n try {\n const lines: string[] = [];\n\n // XML declaration\n lines.push('<?xml version=\"1.0\" encoding=\"UTF-8\"?>');\n\n // Root element with namespaces\n lines.push('<model xmlns=\"http://www.opengroup.org/xsd/archimate/3.0/\"');\n lines.push(' xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"');\n lines.push(\n ' xsi:schemaLocation=\"http://www.opengroup.org/xsd/archimate/3.0/ http://www.opengroup.org/xsd/archimate/3.1/archimate3_Diagram.xsd\">'\n );\n\n // Model metadata\n lines.push(` <name>${escapeXml(model.manifest.name)}</name>`);\n if (model.manifest.description) {\n lines.push(` <documentation>${escapeXml(model.manifest.description)}</documentation>`);\n }\n\n // Export elements - load from each layer directly\n lines.push(\" <elements>\");\n\n const layersToExport = options.layers || this.supportedLayers;\n const elementsByLayer: Array<{ layer: string; element: any }> = [];\n\n // Load elements from each supported layer\n for (const layerName of layersToExport) {\n if (!this.supportedLayers.includes(layerName)) continue;\n\n const layer = await model.getLayer(layerName);\n if (!layer) continue;\n const layerElements = layer.listElements();\n for (const element of layerElements) {\n elementsByLayer.push({ layer: layerName, element });\n }\n }\n\n if (isTelemetryEnabled && span) {\n (span as any).setAttribute(\"export.elementCount\", elementsByLayer.length);\n }\n\n for (const { layer, element } of elementsByLayer) {\n const archiType = this.mapToArchiMateType(element.type, layer);\n lines.push(` <element identifier=\"${element.path}\" xsi:type=\"${archiType}\">`);\n lines.push(` <name>${escapeXml(element.name)}</name>`);\n\n if (element.description) {\n lines.push(` <documentation>${escapeXml(element.description)}</documentation>`);\n }\n\n // Add properties section\n lines.push(\" <properties>\");\n\n // Handle source_reference from element (if present)\n if (element.source_reference) {\n const flattenedProps = this.flattenSourceReference(element.source_reference);\n for (const [flatKey, flatValue] of Object.entries(flattenedProps)) {\n lines.push(\n ` <property key=\"${escapeXml(flatKey)}\" value=\"${escapeXml(String(flatValue))}\" />`\n );\n }\n }\n\n // Add element attributes as properties\n const attrKeys = Object.keys(element.attributes || {});\n if (attrKeys.length > 0) {\n for (const key of attrKeys) {\n const val = element.attributes?.[key];\n const strValue = this.valueToString(val);\n lines.push(\n ` <property key=\"${escapeXml(key)}\" value=\"${escapeXml(strValue)}\" />`\n );\n }\n }\n\n lines.push(\" </properties>\");\n lines.push(\" </element>\");\n }\n\n lines.push(\" </elements>\");\n\n // Export relationships\n lines.push(\" <relationships>\");\n\n let relationshipCount = 0;\n const elementIds = new Set(elementsByLayer.map((e) => e.element.path));\n\n // Filter relationships to those between exported elements\n for (const rel of model.relationships.getAll()) {\n if (!elementIds.has(rel.source) || !elementIds.has(rel.target)) {\n continue;\n }\n\n const relId = this.escapeId(`${rel.source}-${rel.predicate}-${rel.target}`);\n lines.push(` <relationship identifier=\"${relId}\" `);\n lines.push(` source=\"${rel.source}\" target=\"${rel.target}\" `);\n lines.push(` xsi:type=\"Association\">`);\n lines.push(` <name>${rel.predicate}</name>`);\n lines.push(` </relationship>`);\n relationshipCount++;\n }\n\n lines.push(\" </relationships>\");\n lines.push(\"</model>\");\n\n const result = lines.join(\"\\n\");\n\n if (isTelemetryEnabled && span) {\n (span as any).setAttribute(\"export.relationshipCount\", relationshipCount);\n (span as any).setAttribute(\"export.size\", result.length);\n (span as any).setStatus({ code: 0 });\n }\n\n return result;\n } catch (error) {\n if (isTelemetryEnabled && span) {\n (span as any).recordException(error as Error);\n (span as any).setStatus({\n code: 2,\n message: getErrorMessage(error),\n });\n }\n throw error;\n } finally {\n endSpan(span);\n }\n }\n\n /**\n * Map element type and layer to ArchiMate type\n */\n private mapToArchiMateType(type: string, layer: string): string {\n const mapping: Record<string, Record<string, string>> = {\n motivation: {\n stakeholder: \"Stakeholder\",\n driver: \"Driver\",\n assessment: \"Assessment\",\n goal: \"Goal\",\n outcome: \"Outcome\",\n principle: \"Principle\",\n requirement: \"Requirement\",\n constraint: \"Constraint\",\n meaning: \"Meaning\",\n value: \"Value\",\n },\n business: {\n businessactor: \"BusinessActor\",\n businessrole: \"BusinessRole\",\n businesscollaboration: \"BusinessCollaboration\",\n businessinterface: \"BusinessInterface\",\n businessprocess: \"BusinessProcess\",\n businessfunction: \"BusinessFunction\",\n businessinteraction: \"BusinessInteraction\",\n businessevent: \"BusinessEvent\",\n businessservice: \"BusinessService\",\n businessobject: \"BusinessObject\",\n contract: \"Contract\",\n product: \"Product\",\n representation: \"Representation\",\n },\n application: {\n applicationcomponent: \"ApplicationComponent\",\n applicationcollaboration: \"ApplicationCollaboration\",\n applicationinterface: \"ApplicationInterface\",\n applicationfunction: \"ApplicationFunction\",\n applicationinteraction: \"ApplicationInteraction\",\n applicationprocess: \"ApplicationProcess\",\n applicationevent: \"ApplicationEvent\",\n applicationservice: \"ApplicationService\",\n dataobject: \"DataObject\",\n },\n technology: {\n node: \"Node\",\n device: \"Device\",\n systemsoftware: \"SystemSoftware\",\n technologycollaboration: \"TechnologyCollaboration\",\n technologyinterface: \"TechnologyInterface\",\n path: \"Path\",\n communicationnetwork: \"CommunicationNetwork\",\n technologyfunction: \"TechnologyFunction\",\n technologyprocess: \"TechnologyProcess\",\n technologyinteraction: \"TechnologyInteraction\",\n technologyevent: \"TechnologyEvent\",\n technologyservice: \"TechnologyService\",\n artifact: \"Artifact\",\n },\n };\n\n return mapping[layer]?.[type] || \"Element\";\n }\n\n /**\n * Escape ID characters for use in identifiers\n */\n private escapeId(str: string): string {\n return str.replace(/[^a-zA-Z0-9_-]/g, \"_\");\n }\n\n /**\n * Convert value to string representation\n */\n private valueToString(value: unknown): string {\n if (typeof value === \"string\") return value;\n if (typeof value === \"number\") return String(value);\n if (typeof value === \"boolean\") return String(value);\n if (Array.isArray(value)) return `[${value.map((v) => this.valueToString(v)).join(\", \")}]`;\n if (value && typeof value === \"object\") {\n return JSON.stringify(value);\n }\n return String(value);\n }\n\n /**\n * Flatten source reference structure into ArchiMate properties\n * Converts nested structure like { provenance: \"extracted\", locations: [...] }\n * into flat properties like \"source.provenance\", \"source.file.0\", etc.\n */\n private flattenSourceReference(sourceRef: any): Record<string, string> {\n const props: Record<string, string> = {};\n\n if (!sourceRef || typeof sourceRef !== \"object\") {\n return props;\n }\n\n // Add provenance\n if (sourceRef.provenance) {\n props[\"source.provenance\"] = sourceRef.provenance;\n }\n\n // Add locations\n if (Array.isArray(sourceRef.locations)) {\n sourceRef.locations.forEach((location: any, index: number) => {\n if (location.file) {\n props[`source.file.${index}`] = location.file;\n }\n if (location.symbol) {\n props[`source.symbol.${index}`] = location.symbol;\n }\n if (location.line !== undefined) {\n props[`source.line.${index}`] = String(location.line);\n }\n if (location.column !== undefined) {\n props[`source.column.${index}`] = String(location.column);\n }\n });\n }\n\n // Add repository info\n if (sourceRef.repository) {\n if (sourceRef.repository.url) {\n props[\"source.repository.url\"] = sourceRef.repository.url;\n }\n if (sourceRef.repository.commit) {\n props[\"source.repository.commit\"] = sourceRef.repository.commit;\n }\n if (sourceRef.repository.branch) {\n props[\"source.repository.branch\"] = sourceRef.repository.branch;\n }\n }\n\n return props;\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type { Model } from \"../core/model.js\";\nimport type { Exporter, ExportOptions } from \"./types.js\";\nimport { escapeXml } from \"./types.js\";\nimport { isTelemetryEnabled, startSpan, endSpan } from \"../telemetry/index.js\";\nimport { getErrorMessage } from \"../utils/errors.js\";\n\n/**\n * ArchiMate XML Exporter for layers 1, 2, 5, 6 (Motivation, Business, Application, Technology)\n * Generates valid ArchiMate 3.2 XML format\n * Note: Product layer (layer 3) does not participate in ArchiMate export\n */\nexport class ArchiMateExporter implements Exporter {\n name = \"ArchiMate\";\n supportedLayers = [\"motivation\", \"business\", \"application\", \"technology\"];\n\n async export(model: Model, options: ExportOptions = {}): Promise<string> {\n const span = isTelemetryEnabled\n ? startSpan(\"export.format.archimate\", {\n \"export.layerCount\": options.layers?.length || this.supportedLayers.length,\n })\n : null;\n\n try {\n const lines: string[] = [];\n\n // XML declaration\n lines.push('<?xml version=\"1.0\" encoding=\"UTF-8\"?>');\n\n // Root element with namespaces\n lines.push('<model xmlns=\"http://www.opengroup.org/xsd/archimate/3.0/\"');\n lines.push(' xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"');\n lines.push(\n ' xsi:schemaLocation=\"http://www.opengroup.org/xsd/archimate/3.0/ http://www.opengroup.org/xsd/archimate/3.1/archimate3_Diagram.xsd\">'\n );\n\n // Model metadata\n lines.push(` <name>${escapeXml(model.manifest.name)}</name>`);\n if (model.manifest.description) {\n lines.push(` <documentation>${escapeXml(model.manifest.description)}</documentation>`);\n }\n\n // Export elements - load from each layer directly\n lines.push(\" <elements>\");\n\n const layersToExport = options.layers || this.supportedLayers;\n const elementsByLayer: Array<{ layer: string; element: any }> = [];\n\n // Load elements from each supported layer\n for (const layerName of layersToExport) {\n if (!this.supportedLayers.includes(layerName)) continue;\n\n const layer = await model.getLayer(layerName);\n if (!layer) continue;\n const layerElements = layer.listElements();\n for (const element of layerElements) {\n elementsByLayer.push({ layer: layerName, element });\n }\n }\n\n if (isTelemetryEnabled && span) {\n (span as any).setAttribute(\"export.elementCount\", elementsByLayer.length);\n }\n\n for (const { layer, element } of elementsByLayer) {\n const archiType = this.mapToArchiMateType(element.type, layer);\n lines.push(` <element identifier=\"${element.path}\" xsi:type=\"${archiType}\">`);\n lines.push(` <name>${escapeXml(element.name)}</name>`);\n\n if (element.description) {\n lines.push(` <documentation>${escapeXml(element.description)}</documentation>`);\n }\n\n // Add properties section\n lines.push(\" <properties>\");\n\n // Handle source_reference from element (if present)\n if (element.source_reference) {\n const flattenedProps = this.flattenSourceReference(element.source_reference);\n for (const [flatKey, flatValue] of Object.entries(flattenedProps)) {\n lines.push(\n ` <property key=\"${escapeXml(flatKey)}\" value=\"${escapeXml(String(flatValue))}\" />`\n );\n }\n }\n\n // Add element attributes as properties\n const attrKeys = Object.keys(element.attributes || {});\n if (attrKeys.length > 0) {\n for (const key of attrKeys) {\n const val = element.attributes?.[key];\n const strValue = this.valueToString(val);\n lines.push(\n ` <property key=\"${escapeXml(key)}\" value=\"${escapeXml(strValue)}\" />`\n );\n }\n }\n\n lines.push(\" </properties>\");\n lines.push(\" </element>\");\n }\n\n lines.push(\" </elements>\");\n\n // Export relationships\n lines.push(\" <relationships>\");\n\n let relationshipCount = 0;\n const elementIds = new Set(elementsByLayer.map((e) => e.element.path));\n\n // Filter relationships to those between exported elements\n for (const rel of model.relationships.getAll()) {\n if (!elementIds.has(rel.source) || !elementIds.has(rel.target)) {\n continue;\n }\n\n const relId = this.escapeId(`${rel.source}-${rel.predicate}-${rel.target}`);\n lines.push(` <relationship identifier=\"${relId}\" `);\n lines.push(` source=\"${rel.source}\" target=\"${rel.target}\" `);\n lines.push(` xsi:type=\"Association\">`);\n lines.push(` <name>${rel.predicate}</name>`);\n lines.push(` </relationship>`);\n relationshipCount++;\n }\n\n lines.push(\" </relationships>\");\n lines.push(\"</model>\");\n\n const result = lines.join(\"\\n\");\n\n if (isTelemetryEnabled && span) {\n (span as any).setAttribute(\"export.relationshipCount\", relationshipCount);\n (span as any).setAttribute(\"export.size\", result.length);\n (span as any).setStatus({ code: 0 });\n }\n\n return result;\n } catch (error) {\n if (isTelemetryEnabled && span) {\n (span as any).recordException(error as Error);\n (span as any).setStatus({\n code: 2,\n message: getErrorMessage(error),\n });\n }\n throw error;\n } finally {\n endSpan(span);\n }\n }\n\n /**\n * Map element type and layer to ArchiMate type\n */\n private mapToArchiMateType(type: string, layer: string): string {\n const mapping: Record<string, Record<string, string>> = {\n motivation: {\n stakeholder: \"Stakeholder\",\n driver: \"Driver\",\n assessment: \"Assessment\",\n goal: \"Goal\",\n outcome: \"Outcome\",\n principle: \"Principle\",\n requirement: \"Requirement\",\n constraint: \"Constraint\",\n meaning: \"Meaning\",\n value: \"Value\",\n },\n business: {\n businessactor: \"BusinessActor\",\n businessrole: \"BusinessRole\",\n businesscollaboration: \"BusinessCollaboration\",\n businessinterface: \"BusinessInterface\",\n businessprocess: \"BusinessProcess\",\n businessfunction: \"BusinessFunction\",\n businessinteraction: \"BusinessInteraction\",\n businessevent: \"BusinessEvent\",\n businessservice: \"BusinessService\",\n businessobject: \"BusinessObject\",\n businesscapability: \"Capability\",\n contract: \"Contract\",\n product: \"Product\",\n representation: \"Representation\",\n },\n application: {\n applicationcomponent: \"ApplicationComponent\",\n applicationcollaboration: \"ApplicationCollaboration\",\n applicationinterface: \"ApplicationInterface\",\n applicationfunction: \"ApplicationFunction\",\n applicationinteraction: \"ApplicationInteraction\",\n applicationprocess: \"ApplicationProcess\",\n applicationevent: \"ApplicationEvent\",\n applicationservice: \"ApplicationService\",\n dataobject: \"DataObject\",\n },\n technology: {\n node: \"Node\",\n device: \"Device\",\n systemsoftware: \"SystemSoftware\",\n technologycollaboration: \"TechnologyCollaboration\",\n technologyinterface: \"TechnologyInterface\",\n path: \"Path\",\n communicationnetwork: \"CommunicationNetwork\",\n technologyfunction: \"TechnologyFunction\",\n technologyprocess: \"TechnologyProcess\",\n technologyinteraction: \"TechnologyInteraction\",\n technologyevent: \"TechnologyEvent\",\n technologyservice: \"TechnologyService\",\n artifact: \"Artifact\",\n },\n };\n\n return mapping[layer]?.[type] || \"Element\";\n }\n\n /**\n * Escape ID characters for use in identifiers\n */\n private escapeId(str: string): string {\n return str.replace(/[^a-zA-Z0-9_-]/g, \"_\");\n }\n\n /**\n * Convert value to string representation\n */\n private valueToString(value: unknown): string {\n if (typeof value === \"string\") return value;\n if (typeof value === \"number\") return String(value);\n if (typeof value === \"boolean\") return String(value);\n if (Array.isArray(value)) return `[${value.map((v) => this.valueToString(v)).join(\", \")}]`;\n if (value && typeof value === \"object\") {\n return JSON.stringify(value);\n }\n return String(value);\n }\n\n /**\n * Flatten source reference structure into ArchiMate properties\n * Converts nested structure like { provenance: \"extracted\", locations: [...] }\n * into flat properties like \"source.provenance\", \"source.file.0\", etc.\n */\n private flattenSourceReference(sourceRef: any): Record<string, string> {\n const props: Record<string, string> = {};\n\n if (!sourceRef || typeof sourceRef !== \"object\") {\n return props;\n }\n\n // Add provenance\n if (sourceRef.provenance) {\n props[\"source.provenance\"] = sourceRef.provenance;\n }\n\n // Add locations\n if (Array.isArray(sourceRef.locations)) {\n sourceRef.locations.forEach((location: any, index: number) => {\n if (location.file) {\n props[`source.file.${index}`] = location.file;\n }\n if (location.symbol) {\n props[`source.symbol.${index}`] = location.symbol;\n }\n if (location.line !== undefined) {\n props[`source.line.${index}`] = String(location.line);\n }\n if (location.column !== undefined) {\n props[`source.column.${index}`] = String(location.column);\n }\n });\n }\n\n // Add repository info\n if (sourceRef.repository) {\n if (sourceRef.repository.url) {\n props[\"source.repository.url\"] = sourceRef.repository.url;\n }\n if (sourceRef.repository.commit) {\n props[\"source.repository.commit\"] = sourceRef.repository.commit;\n }\n if (sourceRef.repository.branch) {\n props[\"source.repository.branch\"] = sourceRef.repository.branch;\n }\n }\n\n return props;\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -6,8 +6,8 @@ const sharedAjv = (() => {
6
6
  strict: !1,
7
7
  validateFormats: !0
8
8
  });
9
- return addFormats(ajv), ajv.addSchema({ $schema: "http://json-schema.org/draft-07/schema#", title: "SpecNode", description: "Base schema for all spec node types. Each node type schema extends this with type-specific attribute constraints via allOf.", type: "object", required: ["id", "path", "spec_node_id", "type", "name"], additionalProperties: !1, properties: { id: { type: "string", format: "uuid", description: "Unique node instance identifier (UUIDv4). Globally unique across the entire model.", examples: ["550e8400-e29b-41d4-a716-446655440000"] }, path: { type: "string", pattern: "^[a-z][a-z0-9-]*\\.[a-z][a-z0-9-]*\\.[a-z][a-z0-9-]*$", description: "Human-readable element path in format {layer}.{type}.{name} (e.g., 'motivation.goal.increase-revenue')" }, spec_node_id: { type: "string", pattern: "^[a-z-]+\\.[a-z][a-z0-9-]*$", description: "Reference to the spec node type that this node conforms to (e.g., 'motivation.goal')" }, type: { type: "string", description: "Denormalized node type for efficient filtering and queries. Extracted from spec_node_id (the part after the dot).", examples: ["goal", "requirement", "endpoint", "table"] }, layer_id: { type: "string", pattern: "^[a-z][a-z0-9-]*$", description: "Denormalized layer ID for efficient layer-scoped queries. Extracted from spec_node_id (the part before the dot)." }, name: { type: "string", description: "Human-readable instance name", examples: ["Improve Customer Satisfaction", "User Login API", "Customer Table"] }, description: { type: "string", description: "Optional detailed description of this specific node instance" }, attributes: { type: "object", description: "Attribute values for this node instance. Keys must correspond to attributes defined in the per-type schema, and values must conform to the type constraints." }, source_reference: { $ref: "urn:dr:spec:base:source-references#/definitions/SourceReference", description: "Optional provenance tracking linking this node to source code locations" }, metadata: { type: "object", description: "Optional metadata about the lifecycle and version of this node instance", additionalProperties: !1, properties: { created_at: { type: "string", format: "date-time", description: "ISO 8601 timestamp when this node was created" }, updated_at: { type: "string", format: "date-time", description: "ISO 8601 timestamp of the last modification" }, created_by: { type: "string", description: "User or system that created this node" }, version: { type: "integer", minimum: 1, description: "Version number of this node (incremented on updates)" } } } } }, "urn:dr:spec:base:spec-node"), ajv.addSchema({ $schema: "http://json-schema.org/draft-07/schema#", title: "SpecNodeRelationship", description: "Base type for relationship type definitions in the specification. Defines valid relationships between node types, including cardinality, strength, and semantic properties.", type: "object", required: ["id", "source_spec_node_id", "destination_spec_node_id", "predicate"], additionalProperties: !1, properties: { id: { type: "string", pattern: "^[a-z-]+\\.[a-z-]+\\.[a-z-]+$", description: "Unique relationship ID in format: {source-layer}.{predicate}.{dest-layer}. All components use lowercase with hyphens.", examples: ["motivation.supports.motivation", "motivation.realizes.business", "api.exposes.data-model"] }, source_spec_node_id: { type: "string", pattern: "^[a-z-]+\\.[a-z][a-z0-9-]*$", description: "SpecNode ID that can serve as the source of this relationship type" }, source_layer: { type: "string", pattern: "^[a-z][a-z0-9-]*$", description: "Denormalized layer ID extracted from source_spec_node_id for efficient queries" }, destination_spec_node_id: { type: "string", pattern: "^[a-z-]+\\.[a-z][a-z0-9-]*$", description: "SpecNode ID that can serve as the destination of this relationship type" }, destination_layer: { type: "string", pattern: "^[a-z][a-z0-9-]*$", description: "Denormalized layer ID extracted from destination_spec_node_id for efficient queries" }, predicate: { type: "string", description: "Semantic predicate from PredicateCatalog describing the relationship type. Must be a valid predicate name.", examples: ["supports", "realizes", "fulfills", "implements", "uses", "consumes"] }, cardinality: { type: "string", enum: ["one-to-one", "one-to-many", "many-to-one", "many-to-many"], description: "Multiplicity constraint on this relationship type. Defines how many source nodes can relate to how many destination nodes.", default: "many-to-many" }, strength: { type: "string", enum: ["critical", "high", "medium", "low"], description: "Typical importance or strength of this relationship type", default: "medium" }, required: { type: "boolean", description: "Whether instances of the source node type must have at least one relationship of this type", default: !1 }, attributes: { type: "object", description: "Optional schema defining attributes that can appear on relationship instances of this type", additionalProperties: { $ref: "urn:dr:spec:base:attribute-spec#/definitions/AttributeSpec" }, minProperties: 0, examples: [{ reason: { type: "string", description: "Explanation for why this relationship exists" }, strength_override: { type: "enum", enum_values: ["critical", "high", "medium", "low"], description: "Instance-specific strength override" } }] } } }, "urn:dr:spec:base:spec-node-relationship"), ajv.addSchema({ $schema: "http://json-schema.org/draft-07/schema#", title: "Source Code Reference Definitions", description: "Reusable JSON Schema definitions for linking architecture elements to source code locations", version: "1.0.0", definitions: { ProvenanceType: { type: "string", enum: ["extracted", "manual", "inferred", "generated"], description: "How this reference was created: extracted (automated ingestion), manual (human added), inferred (pattern matching), generated (code generated from model)" }, SourceLocation: { type: "object", description: "A specific location in source code, identified by file path and optional symbol", required: ["file"], properties: { file: { type: "string", minLength: 1, description: "File path relative to repository root" }, symbol: { type: "string", description: "Named code element (e.g., ClassName.methodName, function_name)" } } }, RepositoryContext: { type: "object", description: "Repository context for the source reference", properties: { url: { type: "string", format: "uri", description: "Git remote URL (HTTPS or SSH format)" }, commit: { type: "string", pattern: "^[0-9a-f]{40}$", description: "Full 40-character Git commit SHA" } } }, SourceReference: { type: "object", description: "Links entity to source code location(s) with provenance tracking. For inferred or generated elements, locations may be omitted when no source file exists yet.", required: ["provenance"], properties: { provenance: { $ref: "#/definitions/ProvenanceType" }, locations: { type: "array", minItems: 1, items: { $ref: "#/definitions/SourceLocation" }, description: "One or more source code locations. Required for extracted and manual provenance; optional for inferred and generated." }, repository: { $ref: "#/definitions/RepositoryContext" } } } } }, "urn:dr:spec:base:source-references"), ajv.addSchema({ $schema: "http://json-schema.org/draft-07/schema#", title: "AttributeSpec Definitions", description: "Reusable definition for attribute specifications used in spec-level schemas (e.g., spec-node-relationship attributes)", definitions: { AttributeSpec: { type: "object", title: "AttributeSpec", description: "Specification for a single attribute that can appear on node or relationship instances", required: ["type", "description"], additionalProperties: !1, properties: { type: { type: "string", enum: ["string", "integer", "number", "boolean", "array", "object", "enum"], description: "The JSON type of this attribute" }, description: { type: "string", description: "Human-readable description of this attribute's purpose" }, enum_values: { type: "array", items: { type: "string" }, description: "Required when type is 'enum'. Lists the valid string values for this attribute.", examples: [["high", "medium", "low"], ["active", "inactive", "archived"]] }, format: { type: "string", description: "Optional format constraint for string types (e.g., 'email', 'uri', 'date-time')", examples: ["email", "uri", "date-time", "uuid"] }, default: { description: "Default value for this attribute when not provided on a node instance. Can be any JSON value." } }, if: { properties: { type: { const: "enum" } }, required: ["type"] }, then: { required: ["type", "description", "enum_values"] } } } }, "urn:dr:spec:base:attribute-spec"), ajv;
10
- })(), validateSpecNode = sharedAjv.compile({ $schema: "http://json-schema.org/draft-07/schema#", title: "SpecNode", description: "Base schema for all spec node types. Each node type schema extends this with type-specific attribute constraints via allOf.", type: "object", required: ["id", "path", "spec_node_id", "type", "name"], additionalProperties: !1, properties: { id: { type: "string", format: "uuid", description: "Unique node instance identifier (UUIDv4). Globally unique across the entire model.", examples: ["550e8400-e29b-41d4-a716-446655440000"] }, path: { type: "string", pattern: "^[a-z][a-z0-9-]*\\.[a-z][a-z0-9-]*\\.[a-z][a-z0-9-]*$", description: "Human-readable element path in format {layer}.{type}.{name} (e.g., 'motivation.goal.increase-revenue')" }, spec_node_id: { type: "string", pattern: "^[a-z-]+\\.[a-z][a-z0-9-]*$", description: "Reference to the spec node type that this node conforms to (e.g., 'motivation.goal')" }, type: { type: "string", description: "Denormalized node type for efficient filtering and queries. Extracted from spec_node_id (the part after the dot).", examples: ["goal", "requirement", "endpoint", "table"] }, layer_id: { type: "string", pattern: "^[a-z][a-z0-9-]*$", description: "Denormalized layer ID for efficient layer-scoped queries. Extracted from spec_node_id (the part before the dot)." }, name: { type: "string", description: "Human-readable instance name", examples: ["Improve Customer Satisfaction", "User Login API", "Customer Table"] }, description: { type: "string", description: "Optional detailed description of this specific node instance" }, attributes: { type: "object", description: "Attribute values for this node instance. Keys must correspond to attributes defined in the per-type schema, and values must conform to the type constraints." }, source_reference: { $ref: "urn:dr:spec:base:source-references#/definitions/SourceReference", description: "Optional provenance tracking linking this node to source code locations" }, metadata: { type: "object", description: "Optional metadata about the lifecycle and version of this node instance", additionalProperties: !1, properties: { created_at: { type: "string", format: "date-time", description: "ISO 8601 timestamp when this node was created" }, updated_at: { type: "string", format: "date-time", description: "ISO 8601 timestamp of the last modification" }, created_by: { type: "string", description: "User or system that created this node" }, version: { type: "integer", minimum: 1, description: "Version number of this node (incremented on updates)" } } } } }), validateSpecNodeRelationship = sharedAjv.compile({ $schema: "http://json-schema.org/draft-07/schema#", title: "SpecNodeRelationship", description: "Base type for relationship type definitions in the specification. Defines valid relationships between node types, including cardinality, strength, and semantic properties.", type: "object", required: ["id", "source_spec_node_id", "destination_spec_node_id", "predicate"], additionalProperties: !1, properties: { id: { type: "string", pattern: "^[a-z-]+\\.[a-z-]+\\.[a-z-]+$", description: "Unique relationship ID in format: {source-layer}.{predicate}.{dest-layer}. All components use lowercase with hyphens.", examples: ["motivation.supports.motivation", "motivation.realizes.business", "api.exposes.data-model"] }, source_spec_node_id: { type: "string", pattern: "^[a-z-]+\\.[a-z][a-z0-9-]*$", description: "SpecNode ID that can serve as the source of this relationship type" }, source_layer: { type: "string", pattern: "^[a-z][a-z0-9-]*$", description: "Denormalized layer ID extracted from source_spec_node_id for efficient queries" }, destination_spec_node_id: { type: "string", pattern: "^[a-z-]+\\.[a-z][a-z0-9-]*$", description: "SpecNode ID that can serve as the destination of this relationship type" }, destination_layer: { type: "string", pattern: "^[a-z][a-z0-9-]*$", description: "Denormalized layer ID extracted from destination_spec_node_id for efficient queries" }, predicate: { type: "string", description: "Semantic predicate from PredicateCatalog describing the relationship type. Must be a valid predicate name.", examples: ["supports", "realizes", "fulfills", "implements", "uses", "consumes"] }, cardinality: { type: "string", enum: ["one-to-one", "one-to-many", "many-to-one", "many-to-many"], description: "Multiplicity constraint on this relationship type. Defines how many source nodes can relate to how many destination nodes.", default: "many-to-many" }, strength: { type: "string", enum: ["critical", "high", "medium", "low"], description: "Typical importance or strength of this relationship type", default: "medium" }, required: { type: "boolean", description: "Whether instances of the source node type must have at least one relationship of this type", default: !1 }, attributes: { type: "object", description: "Optional schema defining attributes that can appear on relationship instances of this type", additionalProperties: { $ref: "urn:dr:spec:base:attribute-spec#/definitions/AttributeSpec" }, minProperties: 0, examples: [{ reason: { type: "string", description: "Explanation for why this relationship exists" }, strength_override: { type: "enum", enum_values: ["critical", "high", "medium", "low"], description: "Instance-specific strength override" } }] } } }), validateSourceReference = sharedAjv.compile({ $schema: "http://json-schema.org/draft-07/schema#", title: "Source Code Reference Definitions", description: "Reusable JSON Schema definitions for linking architecture elements to source code locations", version: "1.0.0", definitions: { ProvenanceType: { type: "string", enum: ["extracted", "manual", "inferred", "generated"], description: "How this reference was created: extracted (automated ingestion), manual (human added), inferred (pattern matching), generated (code generated from model)" }, SourceLocation: { type: "object", description: "A specific location in source code, identified by file path and optional symbol", required: ["file"], properties: { file: { type: "string", minLength: 1, description: "File path relative to repository root" }, symbol: { type: "string", description: "Named code element (e.g., ClassName.methodName, function_name)" } } }, RepositoryContext: { type: "object", description: "Repository context for the source reference", properties: { url: { type: "string", format: "uri", description: "Git remote URL (HTTPS or SSH format)" }, commit: { type: "string", pattern: "^[0-9a-f]{40}$", description: "Full 40-character Git commit SHA" } } }, SourceReference: { type: "object", description: "Links entity to source code location(s) with provenance tracking. For inferred or generated elements, locations may be omitted when no source file exists yet.", required: ["provenance"], properties: { provenance: { $ref: "#/definitions/ProvenanceType" }, locations: { type: "array", minItems: 1, items: { $ref: "#/definitions/SourceLocation" }, description: "One or more source code locations. Required for extracted and manual provenance; optional for inferred and generated." }, repository: { $ref: "#/definitions/RepositoryContext" } } } } }), validateAttributeSpec = sharedAjv.compile({ $schema: "http://json-schema.org/draft-07/schema#", title: "AttributeSpec Definitions", description: "Reusable definition for attribute specifications used in spec-level schemas (e.g., spec-node-relationship attributes)", definitions: { AttributeSpec: { type: "object", title: "AttributeSpec", description: "Specification for a single attribute that can appear on node or relationship instances", required: ["type", "description"], additionalProperties: !1, properties: { type: { type: "string", enum: ["string", "integer", "number", "boolean", "array", "object", "enum"], description: "The JSON type of this attribute" }, description: { type: "string", description: "Human-readable description of this attribute's purpose" }, enum_values: { type: "array", items: { type: "string" }, description: "Required when type is 'enum'. Lists the valid string values for this attribute.", examples: [["high", "medium", "low"], ["active", "inactive", "archived"]] }, format: { type: "string", description: "Optional format constraint for string types (e.g., 'email', 'uri', 'date-time')", examples: ["email", "uri", "date-time", "uuid"] }, default: { description: "Default value for this attribute when not provided on a node instance. Can be any JSON value." } }, if: { properties: { type: { const: "enum" } }, required: ["type"] }, then: { required: ["type", "description", "enum_values"] } } } });
9
+ return addFormats(ajv), ajv.addSchema({ $schema: "http://json-schema.org/draft-07/schema#", title: "SpecNode", description: "Base schema for all spec node types. Each node type schema extends this with type-specific attribute constraints via allOf.", type: "object", required: ["id", "path", "spec_node_id", "type", "name"], additionalProperties: !1, properties: { id: { type: "string", format: "uuid", description: "Unique node instance identifier (UUIDv4). Globally unique across the entire model.", examples: ["550e8400-e29b-41d4-a716-446655440000"] }, path: { type: "string", pattern: "^[a-z][a-z0-9-]*\\.[a-z][a-z0-9-]*\\.[a-z][a-z0-9-]*$", description: "Human-readable element path in format {layer}.{type}.{name} (e.g., 'motivation.goal.increase-revenue')" }, spec_node_id: { type: "string", pattern: "^[a-z-]+\\.[a-z][a-z0-9-]*$", description: "Reference to the spec node type that this node conforms to (e.g., 'motivation.goal')" }, type: { type: "string", description: "Denormalized node type for efficient filtering and queries. Extracted from spec_node_id (the part after the dot).", examples: ["goal", "requirement", "endpoint", "table"] }, layer_id: { type: "string", pattern: "^[a-z][a-z0-9-]*$", description: "Denormalized layer ID for efficient layer-scoped queries. Extracted from spec_node_id (the part before the dot)." }, name: { type: "string", description: "Human-readable instance name", examples: ["Improve Customer Satisfaction", "User Login API", "Customer Table"] }, description: { type: "string", description: "Optional detailed description of this specific node instance" }, attributes: { type: "object", description: "Attribute values for this node instance. Keys must correspond to attributes defined in the per-type schema, and values must conform to the type constraints." }, source_reference: { $ref: "urn:dr:spec:base:source-references#/definitions/SourceReference", description: "Optional provenance tracking linking this node to source code locations" }, metadata: { type: "object", description: "Optional metadata about the lifecycle and version of this node instance", additionalProperties: !1, properties: { created_at: { type: "string", format: "date-time", description: "ISO 8601 timestamp when this node was created" }, updated_at: { type: "string", format: "date-time", description: "ISO 8601 timestamp of the last modification" }, created_by: { type: "string", description: "User or system that created this node" }, version: { type: "integer", minimum: 1, description: "Version number of this node (incremented on updates)" } } } } }, "urn:dr:spec:base:spec-node"), ajv.addSchema({ $schema: "http://json-schema.org/draft-07/schema#", title: "SpecNodeRelationship", description: "Base type for relationship type definitions in the specification. Defines valid relationships between node types, including cardinality, strength, and semantic properties.", type: "object", required: ["id", "source_spec_node_id", "destination_spec_node_id", "predicate"], additionalProperties: !1, properties: { id: { type: "string", pattern: "^[a-z-]+\\.[a-z-]+\\.[a-z-]+$", description: "Unique relationship ID in format: {source-layer}.{predicate}.{dest-layer}. All components use lowercase with hyphens.", examples: ["motivation.supports.motivation", "motivation.realizes.business", "api.exposes.data-model"] }, source_spec_node_id: { type: "string", pattern: "^[a-z-]+\\.[a-z][a-z0-9-]*$", description: "SpecNode ID that can serve as the source of this relationship type" }, source_layer: { type: "string", pattern: "^[a-z][a-z0-9-]*$", description: "Denormalized layer ID extracted from source_spec_node_id for efficient queries" }, destination_spec_node_id: { type: "string", pattern: "^[a-z-]+\\.[a-z][a-z0-9-]*$", description: "SpecNode ID that can serve as the destination of this relationship type" }, destination_layer: { type: "string", pattern: "^[a-z][a-z0-9-]*$", description: "Denormalized layer ID extracted from destination_spec_node_id for efficient queries" }, predicate: { type: "string", description: "Semantic predicate from PredicateCatalog describing the relationship type. Must be a valid predicate name.", examples: ["supports", "realizes", "fulfills", "uses", "consumes"] }, cardinality: { type: "string", enum: ["one-to-one", "one-to-many", "many-to-one", "many-to-many"], description: "Multiplicity constraint on this relationship type. Defines how many source nodes can relate to how many destination nodes.", default: "many-to-many" }, strength: { type: "string", enum: ["critical", "high", "medium", "low"], description: "Typical importance or strength of this relationship type", default: "medium" }, required: { type: "boolean", description: "Whether instances of the source node type must have at least one relationship of this type", default: !1 }, attributes: { type: "object", description: "Optional schema defining attributes that can appear on relationship instances of this type", additionalProperties: { $ref: "urn:dr:spec:base:attribute-spec#/definitions/AttributeSpec" }, minProperties: 0, examples: [{ reason: { type: "string", description: "Explanation for why this relationship exists" }, strength_override: { type: "enum", enum_values: ["critical", "high", "medium", "low"], description: "Instance-specific strength override" } }] } } }, "urn:dr:spec:base:spec-node-relationship"), ajv.addSchema({ $schema: "http://json-schema.org/draft-07/schema#", title: "Source Code Reference Definitions", description: "Reusable JSON Schema definitions for linking architecture elements to source code locations", version: "1.0.0", definitions: { ProvenanceType: { type: "string", enum: ["extracted", "manual", "inferred", "generated"], description: "How this reference was created: extracted (automated ingestion), manual (human added), inferred (pattern matching), generated (code generated from model)" }, SourceLocation: { type: "object", description: "A specific location in source code, identified by file path and optional symbol", required: ["file"], properties: { file: { type: "string", minLength: 1, description: "File path relative to repository root" }, symbol: { type: "string", description: "Named code element (e.g., ClassName.methodName, function_name)" } } }, RepositoryContext: { type: "object", description: "Repository context for the source reference", properties: { url: { type: "string", format: "uri", description: "Git remote URL (HTTPS or SSH format)" }, commit: { type: "string", pattern: "^[0-9a-f]{40}$", description: "Full 40-character Git commit SHA" } } }, SourceReference: { type: "object", description: "Links entity to source code location(s) with provenance tracking. For inferred or generated elements, locations may be omitted when no source file exists yet.", required: ["provenance"], properties: { provenance: { $ref: "#/definitions/ProvenanceType" }, locations: { type: "array", minItems: 1, items: { $ref: "#/definitions/SourceLocation" }, description: "One or more source code locations. Required for extracted and manual provenance; optional for inferred and generated." }, repository: { $ref: "#/definitions/RepositoryContext" } } } } }, "urn:dr:spec:base:source-references"), ajv.addSchema({ $schema: "http://json-schema.org/draft-07/schema#", title: "AttributeSpec Definitions", description: "Reusable definition for attribute specifications used in spec-level schemas (e.g., spec-node-relationship attributes)", definitions: { AttributeSpec: { type: "object", title: "AttributeSpec", description: "Specification for a single attribute that can appear on node or relationship instances", required: ["type", "description"], additionalProperties: !1, properties: { type: { type: "string", enum: ["string", "integer", "number", "boolean", "array", "object", "enum"], description: "The JSON type of this attribute" }, description: { type: "string", description: "Human-readable description of this attribute's purpose" }, enum_values: { type: "array", items: { type: "string" }, description: "Required when type is 'enum'. Lists the valid string values for this attribute.", examples: [["high", "medium", "low"], ["active", "inactive", "archived"]] }, format: { type: "string", description: "Optional format constraint for string types (e.g., 'email', 'uri', 'date-time')", examples: ["email", "uri", "date-time", "uuid"] }, default: { description: "Default value for this attribute when not provided on a node instance. Can be any JSON value." } }, if: { properties: { type: { const: "enum" } }, required: ["type"] }, then: { required: ["type", "description", "enum_values"] } } } }, "urn:dr:spec:base:attribute-spec"), ajv;
10
+ })(), validateSpecNode = sharedAjv.compile({ $schema: "http://json-schema.org/draft-07/schema#", title: "SpecNode", description: "Base schema for all spec node types. Each node type schema extends this with type-specific attribute constraints via allOf.", type: "object", required: ["id", "path", "spec_node_id", "type", "name"], additionalProperties: !1, properties: { id: { type: "string", format: "uuid", description: "Unique node instance identifier (UUIDv4). Globally unique across the entire model.", examples: ["550e8400-e29b-41d4-a716-446655440000"] }, path: { type: "string", pattern: "^[a-z][a-z0-9-]*\\.[a-z][a-z0-9-]*\\.[a-z][a-z0-9-]*$", description: "Human-readable element path in format {layer}.{type}.{name} (e.g., 'motivation.goal.increase-revenue')" }, spec_node_id: { type: "string", pattern: "^[a-z-]+\\.[a-z][a-z0-9-]*$", description: "Reference to the spec node type that this node conforms to (e.g., 'motivation.goal')" }, type: { type: "string", description: "Denormalized node type for efficient filtering and queries. Extracted from spec_node_id (the part after the dot).", examples: ["goal", "requirement", "endpoint", "table"] }, layer_id: { type: "string", pattern: "^[a-z][a-z0-9-]*$", description: "Denormalized layer ID for efficient layer-scoped queries. Extracted from spec_node_id (the part before the dot)." }, name: { type: "string", description: "Human-readable instance name", examples: ["Improve Customer Satisfaction", "User Login API", "Customer Table"] }, description: { type: "string", description: "Optional detailed description of this specific node instance" }, attributes: { type: "object", description: "Attribute values for this node instance. Keys must correspond to attributes defined in the per-type schema, and values must conform to the type constraints." }, source_reference: { $ref: "urn:dr:spec:base:source-references#/definitions/SourceReference", description: "Optional provenance tracking linking this node to source code locations" }, metadata: { type: "object", description: "Optional metadata about the lifecycle and version of this node instance", additionalProperties: !1, properties: { created_at: { type: "string", format: "date-time", description: "ISO 8601 timestamp when this node was created" }, updated_at: { type: "string", format: "date-time", description: "ISO 8601 timestamp of the last modification" }, created_by: { type: "string", description: "User or system that created this node" }, version: { type: "integer", minimum: 1, description: "Version number of this node (incremented on updates)" } } } } }), validateSpecNodeRelationship = sharedAjv.compile({ $schema: "http://json-schema.org/draft-07/schema#", title: "SpecNodeRelationship", description: "Base type for relationship type definitions in the specification. Defines valid relationships between node types, including cardinality, strength, and semantic properties.", type: "object", required: ["id", "source_spec_node_id", "destination_spec_node_id", "predicate"], additionalProperties: !1, properties: { id: { type: "string", pattern: "^[a-z-]+\\.[a-z-]+\\.[a-z-]+$", description: "Unique relationship ID in format: {source-layer}.{predicate}.{dest-layer}. All components use lowercase with hyphens.", examples: ["motivation.supports.motivation", "motivation.realizes.business", "api.exposes.data-model"] }, source_spec_node_id: { type: "string", pattern: "^[a-z-]+\\.[a-z][a-z0-9-]*$", description: "SpecNode ID that can serve as the source of this relationship type" }, source_layer: { type: "string", pattern: "^[a-z][a-z0-9-]*$", description: "Denormalized layer ID extracted from source_spec_node_id for efficient queries" }, destination_spec_node_id: { type: "string", pattern: "^[a-z-]+\\.[a-z][a-z0-9-]*$", description: "SpecNode ID that can serve as the destination of this relationship type" }, destination_layer: { type: "string", pattern: "^[a-z][a-z0-9-]*$", description: "Denormalized layer ID extracted from destination_spec_node_id for efficient queries" }, predicate: { type: "string", description: "Semantic predicate from PredicateCatalog describing the relationship type. Must be a valid predicate name.", examples: ["supports", "realizes", "fulfills", "uses", "consumes"] }, cardinality: { type: "string", enum: ["one-to-one", "one-to-many", "many-to-one", "many-to-many"], description: "Multiplicity constraint on this relationship type. Defines how many source nodes can relate to how many destination nodes.", default: "many-to-many" }, strength: { type: "string", enum: ["critical", "high", "medium", "low"], description: "Typical importance or strength of this relationship type", default: "medium" }, required: { type: "boolean", description: "Whether instances of the source node type must have at least one relationship of this type", default: !1 }, attributes: { type: "object", description: "Optional schema defining attributes that can appear on relationship instances of this type", additionalProperties: { $ref: "urn:dr:spec:base:attribute-spec#/definitions/AttributeSpec" }, minProperties: 0, examples: [{ reason: { type: "string", description: "Explanation for why this relationship exists" }, strength_override: { type: "enum", enum_values: ["critical", "high", "medium", "low"], description: "Instance-specific strength override" } }] } } }), validateSourceReference = sharedAjv.compile({ $schema: "http://json-schema.org/draft-07/schema#", title: "Source Code Reference Definitions", description: "Reusable JSON Schema definitions for linking architecture elements to source code locations", version: "1.0.0", definitions: { ProvenanceType: { type: "string", enum: ["extracted", "manual", "inferred", "generated"], description: "How this reference was created: extracted (automated ingestion), manual (human added), inferred (pattern matching), generated (code generated from model)" }, SourceLocation: { type: "object", description: "A specific location in source code, identified by file path and optional symbol", required: ["file"], properties: { file: { type: "string", minLength: 1, description: "File path relative to repository root" }, symbol: { type: "string", description: "Named code element (e.g., ClassName.methodName, function_name)" } } }, RepositoryContext: { type: "object", description: "Repository context for the source reference", properties: { url: { type: "string", format: "uri", description: "Git remote URL (HTTPS or SSH format)" }, commit: { type: "string", pattern: "^[0-9a-f]{40}$", description: "Full 40-character Git commit SHA" } } }, SourceReference: { type: "object", description: "Links entity to source code location(s) with provenance tracking. For inferred or generated elements, locations may be omitted when no source file exists yet.", required: ["provenance"], properties: { provenance: { $ref: "#/definitions/ProvenanceType" }, locations: { type: "array", minItems: 1, items: { $ref: "#/definitions/SourceLocation" }, description: "One or more source code locations. Required for extracted and manual provenance; optional for inferred and generated." }, repository: { $ref: "#/definitions/RepositoryContext" } } } } }), validateAttributeSpec = sharedAjv.compile({ $schema: "http://json-schema.org/draft-07/schema#", title: "AttributeSpec Definitions", description: "Reusable definition for attribute specifications used in spec-level schemas (e.g., spec-node-relationship attributes)", definitions: { AttributeSpec: { type: "object", title: "AttributeSpec", description: "Specification for a single attribute that can appear on node or relationship instances", required: ["type", "description"], additionalProperties: !1, properties: { type: { type: "string", enum: ["string", "integer", "number", "boolean", "array", "object", "enum"], description: "The JSON type of this attribute" }, description: { type: "string", description: "Human-readable description of this attribute's purpose" }, enum_values: { type: "array", items: { type: "string" }, description: "Required when type is 'enum'. Lists the valid string values for this attribute.", examples: [["high", "medium", "low"], ["active", "inactive", "archived"]] }, format: { type: "string", description: "Optional format constraint for string types (e.g., 'email', 'uri', 'date-time')", examples: ["email", "uri", "date-time", "uuid"] }, default: { description: "Default value for this attribute when not provided on a node instance. Can be any JSON value." } }, if: { properties: { type: { const: "enum" } }, required: ["type"] }, then: { required: ["type", "description", "enum_values"] } } } });
11
11
  export {
12
12
  validateAttributeSpec,
13
13
  validateSourceReference,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/generated/compiled-validators.ts"],
4
- "sourcesContent": ["/**\n * GENERATED FILE - DO NOT EDIT\n * This file is automatically generated by scripts/generate-validators.ts\n * during the build process. Changes will be overwritten.\n *\n * Pre-compiled AJV validators for base schemas\n * Eliminates runtime schema loading overhead by baking validators into the bundle\n *\n * Source: cli/src/schemas/bundled/base/\n * Build-time generation prevents runtime file I/O and schema compilation\n */\n\nimport Ajv from \"ajv\";\nimport { ValidateFunction } from \"ajv\";\nimport addFormats from \"ajv-formats\";\n\n\n// Shared AJV instance for all validators to handle schema references\nconst sharedAjv = (() => {\n const ajv = new Ajv({\n allErrors: true,\n strict: false,\n validateFormats: true,\n });\n addFormats(ajv);\n\n // Register all base schemas for reference resolution\n ajv.addSchema({\"$schema\":\"http://json-schema.org/draft-07/schema#\",\"title\":\"SpecNode\",\"description\":\"Base schema for all spec node types. Each node type schema extends this with type-specific attribute constraints via allOf.\",\"type\":\"object\",\"required\":[\"id\",\"path\",\"spec_node_id\",\"type\",\"name\"],\"additionalProperties\":false,\"properties\":{\"id\":{\"type\":\"string\",\"format\":\"uuid\",\"description\":\"Unique node instance identifier (UUIDv4). Globally unique across the entire model.\",\"examples\":[\"550e8400-e29b-41d4-a716-446655440000\"]},\"path\":{\"type\":\"string\",\"pattern\":\"^[a-z][a-z0-9-]*\\\\.[a-z][a-z0-9-]*\\\\.[a-z][a-z0-9-]*$\",\"description\":\"Human-readable element path in format {layer}.{type}.{name} (e.g., 'motivation.goal.increase-revenue')\"},\"spec_node_id\":{\"type\":\"string\",\"pattern\":\"^[a-z-]+\\\\.[a-z][a-z0-9-]*$\",\"description\":\"Reference to the spec node type that this node conforms to (e.g., 'motivation.goal')\"},\"type\":{\"type\":\"string\",\"description\":\"Denormalized node type for efficient filtering and queries. Extracted from spec_node_id (the part after the dot).\",\"examples\":[\"goal\",\"requirement\",\"endpoint\",\"table\"]},\"layer_id\":{\"type\":\"string\",\"pattern\":\"^[a-z][a-z0-9-]*$\",\"description\":\"Denormalized layer ID for efficient layer-scoped queries. Extracted from spec_node_id (the part before the dot).\"},\"name\":{\"type\":\"string\",\"description\":\"Human-readable instance name\",\"examples\":[\"Improve Customer Satisfaction\",\"User Login API\",\"Customer Table\"]},\"description\":{\"type\":\"string\",\"description\":\"Optional detailed description of this specific node instance\"},\"attributes\":{\"type\":\"object\",\"description\":\"Attribute values for this node instance. Keys must correspond to attributes defined in the per-type schema, and values must conform to the type constraints.\"},\"source_reference\":{\"$ref\":\"urn:dr:spec:base:source-references#/definitions/SourceReference\",\"description\":\"Optional provenance tracking linking this node to source code locations\"},\"metadata\":{\"type\":\"object\",\"description\":\"Optional metadata about the lifecycle and version of this node instance\",\"additionalProperties\":false,\"properties\":{\"created_at\":{\"type\":\"string\",\"format\":\"date-time\",\"description\":\"ISO 8601 timestamp when this node was created\"},\"updated_at\":{\"type\":\"string\",\"format\":\"date-time\",\"description\":\"ISO 8601 timestamp of the last modification\"},\"created_by\":{\"type\":\"string\",\"description\":\"User or system that created this node\"},\"version\":{\"type\":\"integer\",\"minimum\":1,\"description\":\"Version number of this node (incremented on updates)\"}}}}}, \"urn:dr:spec:base:spec-node\");\n ajv.addSchema({\"$schema\":\"http://json-schema.org/draft-07/schema#\",\"title\":\"SpecNodeRelationship\",\"description\":\"Base type for relationship type definitions in the specification. Defines valid relationships between node types, including cardinality, strength, and semantic properties.\",\"type\":\"object\",\"required\":[\"id\",\"source_spec_node_id\",\"destination_spec_node_id\",\"predicate\"],\"additionalProperties\":false,\"properties\":{\"id\":{\"type\":\"string\",\"pattern\":\"^[a-z-]+\\\\.[a-z-]+\\\\.[a-z-]+$\",\"description\":\"Unique relationship ID in format: {source-layer}.{predicate}.{dest-layer}. All components use lowercase with hyphens.\",\"examples\":[\"motivation.supports.motivation\",\"motivation.realizes.business\",\"api.exposes.data-model\"]},\"source_spec_node_id\":{\"type\":\"string\",\"pattern\":\"^[a-z-]+\\\\.[a-z][a-z0-9-]*$\",\"description\":\"SpecNode ID that can serve as the source of this relationship type\"},\"source_layer\":{\"type\":\"string\",\"pattern\":\"^[a-z][a-z0-9-]*$\",\"description\":\"Denormalized layer ID extracted from source_spec_node_id for efficient queries\"},\"destination_spec_node_id\":{\"type\":\"string\",\"pattern\":\"^[a-z-]+\\\\.[a-z][a-z0-9-]*$\",\"description\":\"SpecNode ID that can serve as the destination of this relationship type\"},\"destination_layer\":{\"type\":\"string\",\"pattern\":\"^[a-z][a-z0-9-]*$\",\"description\":\"Denormalized layer ID extracted from destination_spec_node_id for efficient queries\"},\"predicate\":{\"type\":\"string\",\"description\":\"Semantic predicate from PredicateCatalog describing the relationship type. Must be a valid predicate name.\",\"examples\":[\"supports\",\"realizes\",\"fulfills\",\"implements\",\"uses\",\"consumes\"]},\"cardinality\":{\"type\":\"string\",\"enum\":[\"one-to-one\",\"one-to-many\",\"many-to-one\",\"many-to-many\"],\"description\":\"Multiplicity constraint on this relationship type. Defines how many source nodes can relate to how many destination nodes.\",\"default\":\"many-to-many\"},\"strength\":{\"type\":\"string\",\"enum\":[\"critical\",\"high\",\"medium\",\"low\"],\"description\":\"Typical importance or strength of this relationship type\",\"default\":\"medium\"},\"required\":{\"type\":\"boolean\",\"description\":\"Whether instances of the source node type must have at least one relationship of this type\",\"default\":false},\"attributes\":{\"type\":\"object\",\"description\":\"Optional schema defining attributes that can appear on relationship instances of this type\",\"additionalProperties\":{\"$ref\":\"urn:dr:spec:base:attribute-spec#/definitions/AttributeSpec\"},\"minProperties\":0,\"examples\":[{\"reason\":{\"type\":\"string\",\"description\":\"Explanation for why this relationship exists\"},\"strength_override\":{\"type\":\"enum\",\"enum_values\":[\"critical\",\"high\",\"medium\",\"low\"],\"description\":\"Instance-specific strength override\"}}]}}}, \"urn:dr:spec:base:spec-node-relationship\");\n ajv.addSchema({\"$schema\":\"http://json-schema.org/draft-07/schema#\",\"title\":\"Source Code Reference Definitions\",\"description\":\"Reusable JSON Schema definitions for linking architecture elements to source code locations\",\"version\":\"1.0.0\",\"definitions\":{\"ProvenanceType\":{\"type\":\"string\",\"enum\":[\"extracted\",\"manual\",\"inferred\",\"generated\"],\"description\":\"How this reference was created: extracted (automated ingestion), manual (human added), inferred (pattern matching), generated (code generated from model)\"},\"SourceLocation\":{\"type\":\"object\",\"description\":\"A specific location in source code, identified by file path and optional symbol\",\"required\":[\"file\"],\"properties\":{\"file\":{\"type\":\"string\",\"minLength\":1,\"description\":\"File path relative to repository root\"},\"symbol\":{\"type\":\"string\",\"description\":\"Named code element (e.g., ClassName.methodName, function_name)\"}}},\"RepositoryContext\":{\"type\":\"object\",\"description\":\"Repository context for the source reference\",\"properties\":{\"url\":{\"type\":\"string\",\"format\":\"uri\",\"description\":\"Git remote URL (HTTPS or SSH format)\"},\"commit\":{\"type\":\"string\",\"pattern\":\"^[0-9a-f]{40}$\",\"description\":\"Full 40-character Git commit SHA\"}}},\"SourceReference\":{\"type\":\"object\",\"description\":\"Links entity to source code location(s) with provenance tracking. For inferred or generated elements, locations may be omitted when no source file exists yet.\",\"required\":[\"provenance\"],\"properties\":{\"provenance\":{\"$ref\":\"#/definitions/ProvenanceType\"},\"locations\":{\"type\":\"array\",\"minItems\":1,\"items\":{\"$ref\":\"#/definitions/SourceLocation\"},\"description\":\"One or more source code locations. Required for extracted and manual provenance; optional for inferred and generated.\"},\"repository\":{\"$ref\":\"#/definitions/RepositoryContext\"}}}}}, \"urn:dr:spec:base:source-references\");\n ajv.addSchema({\"$schema\":\"http://json-schema.org/draft-07/schema#\",\"title\":\"AttributeSpec Definitions\",\"description\":\"Reusable definition for attribute specifications used in spec-level schemas (e.g., spec-node-relationship attributes)\",\"definitions\":{\"AttributeSpec\":{\"type\":\"object\",\"title\":\"AttributeSpec\",\"description\":\"Specification for a single attribute that can appear on node or relationship instances\",\"required\":[\"type\",\"description\"],\"additionalProperties\":false,\"properties\":{\"type\":{\"type\":\"string\",\"enum\":[\"string\",\"integer\",\"number\",\"boolean\",\"array\",\"object\",\"enum\"],\"description\":\"The JSON type of this attribute\"},\"description\":{\"type\":\"string\",\"description\":\"Human-readable description of this attribute's purpose\"},\"enum_values\":{\"type\":\"array\",\"items\":{\"type\":\"string\"},\"description\":\"Required when type is 'enum'. Lists the valid string values for this attribute.\",\"examples\":[[\"high\",\"medium\",\"low\"],[\"active\",\"inactive\",\"archived\"]]},\"format\":{\"type\":\"string\",\"description\":\"Optional format constraint for string types (e.g., 'email', 'uri', 'date-time')\",\"examples\":[\"email\",\"uri\",\"date-time\",\"uuid\"]},\"default\":{\"description\":\"Default value for this attribute when not provided on a node instance. Can be any JSON value.\"}},\"if\":{\"properties\":{\"type\":{\"const\":\"enum\"}},\"required\":[\"type\"]},\"then\":{\"required\":[\"type\",\"description\",\"enum_values\"]}}}}, \"urn:dr:spec:base:attribute-spec\");\n\n return ajv;\n})();\n\n/**\n * Pre-compiled validator for SpecNode\n * Compiled once at module load, pre-cached for use throughout runtime\n */\nexport const validateSpecNode: ValidateFunction = sharedAjv.compile({\"$schema\":\"http://json-schema.org/draft-07/schema#\",\"title\":\"SpecNode\",\"description\":\"Base schema for all spec node types. Each node type schema extends this with type-specific attribute constraints via allOf.\",\"type\":\"object\",\"required\":[\"id\",\"path\",\"spec_node_id\",\"type\",\"name\"],\"additionalProperties\":false,\"properties\":{\"id\":{\"type\":\"string\",\"format\":\"uuid\",\"description\":\"Unique node instance identifier (UUIDv4). Globally unique across the entire model.\",\"examples\":[\"550e8400-e29b-41d4-a716-446655440000\"]},\"path\":{\"type\":\"string\",\"pattern\":\"^[a-z][a-z0-9-]*\\\\.[a-z][a-z0-9-]*\\\\.[a-z][a-z0-9-]*$\",\"description\":\"Human-readable element path in format {layer}.{type}.{name} (e.g., 'motivation.goal.increase-revenue')\"},\"spec_node_id\":{\"type\":\"string\",\"pattern\":\"^[a-z-]+\\\\.[a-z][a-z0-9-]*$\",\"description\":\"Reference to the spec node type that this node conforms to (e.g., 'motivation.goal')\"},\"type\":{\"type\":\"string\",\"description\":\"Denormalized node type for efficient filtering and queries. Extracted from spec_node_id (the part after the dot).\",\"examples\":[\"goal\",\"requirement\",\"endpoint\",\"table\"]},\"layer_id\":{\"type\":\"string\",\"pattern\":\"^[a-z][a-z0-9-]*$\",\"description\":\"Denormalized layer ID for efficient layer-scoped queries. Extracted from spec_node_id (the part before the dot).\"},\"name\":{\"type\":\"string\",\"description\":\"Human-readable instance name\",\"examples\":[\"Improve Customer Satisfaction\",\"User Login API\",\"Customer Table\"]},\"description\":{\"type\":\"string\",\"description\":\"Optional detailed description of this specific node instance\"},\"attributes\":{\"type\":\"object\",\"description\":\"Attribute values for this node instance. Keys must correspond to attributes defined in the per-type schema, and values must conform to the type constraints.\"},\"source_reference\":{\"$ref\":\"urn:dr:spec:base:source-references#/definitions/SourceReference\",\"description\":\"Optional provenance tracking linking this node to source code locations\"},\"metadata\":{\"type\":\"object\",\"description\":\"Optional metadata about the lifecycle and version of this node instance\",\"additionalProperties\":false,\"properties\":{\"created_at\":{\"type\":\"string\",\"format\":\"date-time\",\"description\":\"ISO 8601 timestamp when this node was created\"},\"updated_at\":{\"type\":\"string\",\"format\":\"date-time\",\"description\":\"ISO 8601 timestamp of the last modification\"},\"created_by\":{\"type\":\"string\",\"description\":\"User or system that created this node\"},\"version\":{\"type\":\"integer\",\"minimum\":1,\"description\":\"Version number of this node (incremented on updates)\"}}}}});\n/**\n * Pre-compiled validator for SpecNodeRelationship\n * Compiled once at module load, pre-cached for use throughout runtime\n */\nexport const validateSpecNodeRelationship: ValidateFunction = sharedAjv.compile({\"$schema\":\"http://json-schema.org/draft-07/schema#\",\"title\":\"SpecNodeRelationship\",\"description\":\"Base type for relationship type definitions in the specification. Defines valid relationships between node types, including cardinality, strength, and semantic properties.\",\"type\":\"object\",\"required\":[\"id\",\"source_spec_node_id\",\"destination_spec_node_id\",\"predicate\"],\"additionalProperties\":false,\"properties\":{\"id\":{\"type\":\"string\",\"pattern\":\"^[a-z-]+\\\\.[a-z-]+\\\\.[a-z-]+$\",\"description\":\"Unique relationship ID in format: {source-layer}.{predicate}.{dest-layer}. All components use lowercase with hyphens.\",\"examples\":[\"motivation.supports.motivation\",\"motivation.realizes.business\",\"api.exposes.data-model\"]},\"source_spec_node_id\":{\"type\":\"string\",\"pattern\":\"^[a-z-]+\\\\.[a-z][a-z0-9-]*$\",\"description\":\"SpecNode ID that can serve as the source of this relationship type\"},\"source_layer\":{\"type\":\"string\",\"pattern\":\"^[a-z][a-z0-9-]*$\",\"description\":\"Denormalized layer ID extracted from source_spec_node_id for efficient queries\"},\"destination_spec_node_id\":{\"type\":\"string\",\"pattern\":\"^[a-z-]+\\\\.[a-z][a-z0-9-]*$\",\"description\":\"SpecNode ID that can serve as the destination of this relationship type\"},\"destination_layer\":{\"type\":\"string\",\"pattern\":\"^[a-z][a-z0-9-]*$\",\"description\":\"Denormalized layer ID extracted from destination_spec_node_id for efficient queries\"},\"predicate\":{\"type\":\"string\",\"description\":\"Semantic predicate from PredicateCatalog describing the relationship type. Must be a valid predicate name.\",\"examples\":[\"supports\",\"realizes\",\"fulfills\",\"implements\",\"uses\",\"consumes\"]},\"cardinality\":{\"type\":\"string\",\"enum\":[\"one-to-one\",\"one-to-many\",\"many-to-one\",\"many-to-many\"],\"description\":\"Multiplicity constraint on this relationship type. Defines how many source nodes can relate to how many destination nodes.\",\"default\":\"many-to-many\"},\"strength\":{\"type\":\"string\",\"enum\":[\"critical\",\"high\",\"medium\",\"low\"],\"description\":\"Typical importance or strength of this relationship type\",\"default\":\"medium\"},\"required\":{\"type\":\"boolean\",\"description\":\"Whether instances of the source node type must have at least one relationship of this type\",\"default\":false},\"attributes\":{\"type\":\"object\",\"description\":\"Optional schema defining attributes that can appear on relationship instances of this type\",\"additionalProperties\":{\"$ref\":\"urn:dr:spec:base:attribute-spec#/definitions/AttributeSpec\"},\"minProperties\":0,\"examples\":[{\"reason\":{\"type\":\"string\",\"description\":\"Explanation for why this relationship exists\"},\"strength_override\":{\"type\":\"enum\",\"enum_values\":[\"critical\",\"high\",\"medium\",\"low\"],\"description\":\"Instance-specific strength override\"}}]}}});\n/**\n * Pre-compiled validator for Source Code Reference Definitions\n * Compiled once at module load, pre-cached for use throughout runtime\n */\nexport const validateSourceReference: ValidateFunction = sharedAjv.compile({\"$schema\":\"http://json-schema.org/draft-07/schema#\",\"title\":\"Source Code Reference Definitions\",\"description\":\"Reusable JSON Schema definitions for linking architecture elements to source code locations\",\"version\":\"1.0.0\",\"definitions\":{\"ProvenanceType\":{\"type\":\"string\",\"enum\":[\"extracted\",\"manual\",\"inferred\",\"generated\"],\"description\":\"How this reference was created: extracted (automated ingestion), manual (human added), inferred (pattern matching), generated (code generated from model)\"},\"SourceLocation\":{\"type\":\"object\",\"description\":\"A specific location in source code, identified by file path and optional symbol\",\"required\":[\"file\"],\"properties\":{\"file\":{\"type\":\"string\",\"minLength\":1,\"description\":\"File path relative to repository root\"},\"symbol\":{\"type\":\"string\",\"description\":\"Named code element (e.g., ClassName.methodName, function_name)\"}}},\"RepositoryContext\":{\"type\":\"object\",\"description\":\"Repository context for the source reference\",\"properties\":{\"url\":{\"type\":\"string\",\"format\":\"uri\",\"description\":\"Git remote URL (HTTPS or SSH format)\"},\"commit\":{\"type\":\"string\",\"pattern\":\"^[0-9a-f]{40}$\",\"description\":\"Full 40-character Git commit SHA\"}}},\"SourceReference\":{\"type\":\"object\",\"description\":\"Links entity to source code location(s) with provenance tracking. For inferred or generated elements, locations may be omitted when no source file exists yet.\",\"required\":[\"provenance\"],\"properties\":{\"provenance\":{\"$ref\":\"#/definitions/ProvenanceType\"},\"locations\":{\"type\":\"array\",\"minItems\":1,\"items\":{\"$ref\":\"#/definitions/SourceLocation\"},\"description\":\"One or more source code locations. Required for extracted and manual provenance; optional for inferred and generated.\"},\"repository\":{\"$ref\":\"#/definitions/RepositoryContext\"}}}}});\n/**\n * Pre-compiled validator for AttributeSpec Definitions\n * Compiled once at module load, pre-cached for use throughout runtime\n */\nexport const validateAttributeSpec: ValidateFunction = sharedAjv.compile({\"$schema\":\"http://json-schema.org/draft-07/schema#\",\"title\":\"AttributeSpec Definitions\",\"description\":\"Reusable definition for attribute specifications used in spec-level schemas (e.g., spec-node-relationship attributes)\",\"definitions\":{\"AttributeSpec\":{\"type\":\"object\",\"title\":\"AttributeSpec\",\"description\":\"Specification for a single attribute that can appear on node or relationship instances\",\"required\":[\"type\",\"description\"],\"additionalProperties\":false,\"properties\":{\"type\":{\"type\":\"string\",\"enum\":[\"string\",\"integer\",\"number\",\"boolean\",\"array\",\"object\",\"enum\"],\"description\":\"The JSON type of this attribute\"},\"description\":{\"type\":\"string\",\"description\":\"Human-readable description of this attribute's purpose\"},\"enum_values\":{\"type\":\"array\",\"items\":{\"type\":\"string\"},\"description\":\"Required when type is 'enum'. Lists the valid string values for this attribute.\",\"examples\":[[\"high\",\"medium\",\"low\"],[\"active\",\"inactive\",\"archived\"]]},\"format\":{\"type\":\"string\",\"description\":\"Optional format constraint for string types (e.g., 'email', 'uri', 'date-time')\",\"examples\":[\"email\",\"uri\",\"date-time\",\"uuid\"]},\"default\":{\"description\":\"Default value for this attribute when not provided on a node instance. Can be any JSON value.\"}},\"if\":{\"properties\":{\"type\":{\"const\":\"enum\"}},\"required\":[\"type\"]},\"then\":{\"required\":[\"type\",\"description\",\"enum_values\"]}}}});\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * GENERATED FILE - DO NOT EDIT\n * This file is automatically generated by scripts/generate-validators.ts\n * during the build process. Changes will be overwritten.\n *\n * Pre-compiled AJV validators for base schemas\n * Eliminates runtime schema loading overhead by baking validators into the bundle\n *\n * Source: cli/src/schemas/bundled/base/\n * Build-time generation prevents runtime file I/O and schema compilation\n */\n\nimport Ajv from \"ajv\";\nimport { ValidateFunction } from \"ajv\";\nimport addFormats from \"ajv-formats\";\n\n\n// Shared AJV instance for all validators to handle schema references\nconst sharedAjv = (() => {\n const ajv = new Ajv({\n allErrors: true,\n strict: false,\n validateFormats: true,\n });\n addFormats(ajv);\n\n // Register all base schemas for reference resolution\n ajv.addSchema({\"$schema\":\"http://json-schema.org/draft-07/schema#\",\"title\":\"SpecNode\",\"description\":\"Base schema for all spec node types. Each node type schema extends this with type-specific attribute constraints via allOf.\",\"type\":\"object\",\"required\":[\"id\",\"path\",\"spec_node_id\",\"type\",\"name\"],\"additionalProperties\":false,\"properties\":{\"id\":{\"type\":\"string\",\"format\":\"uuid\",\"description\":\"Unique node instance identifier (UUIDv4). Globally unique across the entire model.\",\"examples\":[\"550e8400-e29b-41d4-a716-446655440000\"]},\"path\":{\"type\":\"string\",\"pattern\":\"^[a-z][a-z0-9-]*\\\\.[a-z][a-z0-9-]*\\\\.[a-z][a-z0-9-]*$\",\"description\":\"Human-readable element path in format {layer}.{type}.{name} (e.g., 'motivation.goal.increase-revenue')\"},\"spec_node_id\":{\"type\":\"string\",\"pattern\":\"^[a-z-]+\\\\.[a-z][a-z0-9-]*$\",\"description\":\"Reference to the spec node type that this node conforms to (e.g., 'motivation.goal')\"},\"type\":{\"type\":\"string\",\"description\":\"Denormalized node type for efficient filtering and queries. Extracted from spec_node_id (the part after the dot).\",\"examples\":[\"goal\",\"requirement\",\"endpoint\",\"table\"]},\"layer_id\":{\"type\":\"string\",\"pattern\":\"^[a-z][a-z0-9-]*$\",\"description\":\"Denormalized layer ID for efficient layer-scoped queries. Extracted from spec_node_id (the part before the dot).\"},\"name\":{\"type\":\"string\",\"description\":\"Human-readable instance name\",\"examples\":[\"Improve Customer Satisfaction\",\"User Login API\",\"Customer Table\"]},\"description\":{\"type\":\"string\",\"description\":\"Optional detailed description of this specific node instance\"},\"attributes\":{\"type\":\"object\",\"description\":\"Attribute values for this node instance. Keys must correspond to attributes defined in the per-type schema, and values must conform to the type constraints.\"},\"source_reference\":{\"$ref\":\"urn:dr:spec:base:source-references#/definitions/SourceReference\",\"description\":\"Optional provenance tracking linking this node to source code locations\"},\"metadata\":{\"type\":\"object\",\"description\":\"Optional metadata about the lifecycle and version of this node instance\",\"additionalProperties\":false,\"properties\":{\"created_at\":{\"type\":\"string\",\"format\":\"date-time\",\"description\":\"ISO 8601 timestamp when this node was created\"},\"updated_at\":{\"type\":\"string\",\"format\":\"date-time\",\"description\":\"ISO 8601 timestamp of the last modification\"},\"created_by\":{\"type\":\"string\",\"description\":\"User or system that created this node\"},\"version\":{\"type\":\"integer\",\"minimum\":1,\"description\":\"Version number of this node (incremented on updates)\"}}}}}, \"urn:dr:spec:base:spec-node\");\n ajv.addSchema({\"$schema\":\"http://json-schema.org/draft-07/schema#\",\"title\":\"SpecNodeRelationship\",\"description\":\"Base type for relationship type definitions in the specification. Defines valid relationships between node types, including cardinality, strength, and semantic properties.\",\"type\":\"object\",\"required\":[\"id\",\"source_spec_node_id\",\"destination_spec_node_id\",\"predicate\"],\"additionalProperties\":false,\"properties\":{\"id\":{\"type\":\"string\",\"pattern\":\"^[a-z-]+\\\\.[a-z-]+\\\\.[a-z-]+$\",\"description\":\"Unique relationship ID in format: {source-layer}.{predicate}.{dest-layer}. All components use lowercase with hyphens.\",\"examples\":[\"motivation.supports.motivation\",\"motivation.realizes.business\",\"api.exposes.data-model\"]},\"source_spec_node_id\":{\"type\":\"string\",\"pattern\":\"^[a-z-]+\\\\.[a-z][a-z0-9-]*$\",\"description\":\"SpecNode ID that can serve as the source of this relationship type\"},\"source_layer\":{\"type\":\"string\",\"pattern\":\"^[a-z][a-z0-9-]*$\",\"description\":\"Denormalized layer ID extracted from source_spec_node_id for efficient queries\"},\"destination_spec_node_id\":{\"type\":\"string\",\"pattern\":\"^[a-z-]+\\\\.[a-z][a-z0-9-]*$\",\"description\":\"SpecNode ID that can serve as the destination of this relationship type\"},\"destination_layer\":{\"type\":\"string\",\"pattern\":\"^[a-z][a-z0-9-]*$\",\"description\":\"Denormalized layer ID extracted from destination_spec_node_id for efficient queries\"},\"predicate\":{\"type\":\"string\",\"description\":\"Semantic predicate from PredicateCatalog describing the relationship type. Must be a valid predicate name.\",\"examples\":[\"supports\",\"realizes\",\"fulfills\",\"uses\",\"consumes\"]},\"cardinality\":{\"type\":\"string\",\"enum\":[\"one-to-one\",\"one-to-many\",\"many-to-one\",\"many-to-many\"],\"description\":\"Multiplicity constraint on this relationship type. Defines how many source nodes can relate to how many destination nodes.\",\"default\":\"many-to-many\"},\"strength\":{\"type\":\"string\",\"enum\":[\"critical\",\"high\",\"medium\",\"low\"],\"description\":\"Typical importance or strength of this relationship type\",\"default\":\"medium\"},\"required\":{\"type\":\"boolean\",\"description\":\"Whether instances of the source node type must have at least one relationship of this type\",\"default\":false},\"attributes\":{\"type\":\"object\",\"description\":\"Optional schema defining attributes that can appear on relationship instances of this type\",\"additionalProperties\":{\"$ref\":\"urn:dr:spec:base:attribute-spec#/definitions/AttributeSpec\"},\"minProperties\":0,\"examples\":[{\"reason\":{\"type\":\"string\",\"description\":\"Explanation for why this relationship exists\"},\"strength_override\":{\"type\":\"enum\",\"enum_values\":[\"critical\",\"high\",\"medium\",\"low\"],\"description\":\"Instance-specific strength override\"}}]}}}, \"urn:dr:spec:base:spec-node-relationship\");\n ajv.addSchema({\"$schema\":\"http://json-schema.org/draft-07/schema#\",\"title\":\"Source Code Reference Definitions\",\"description\":\"Reusable JSON Schema definitions for linking architecture elements to source code locations\",\"version\":\"1.0.0\",\"definitions\":{\"ProvenanceType\":{\"type\":\"string\",\"enum\":[\"extracted\",\"manual\",\"inferred\",\"generated\"],\"description\":\"How this reference was created: extracted (automated ingestion), manual (human added), inferred (pattern matching), generated (code generated from model)\"},\"SourceLocation\":{\"type\":\"object\",\"description\":\"A specific location in source code, identified by file path and optional symbol\",\"required\":[\"file\"],\"properties\":{\"file\":{\"type\":\"string\",\"minLength\":1,\"description\":\"File path relative to repository root\"},\"symbol\":{\"type\":\"string\",\"description\":\"Named code element (e.g., ClassName.methodName, function_name)\"}}},\"RepositoryContext\":{\"type\":\"object\",\"description\":\"Repository context for the source reference\",\"properties\":{\"url\":{\"type\":\"string\",\"format\":\"uri\",\"description\":\"Git remote URL (HTTPS or SSH format)\"},\"commit\":{\"type\":\"string\",\"pattern\":\"^[0-9a-f]{40}$\",\"description\":\"Full 40-character Git commit SHA\"}}},\"SourceReference\":{\"type\":\"object\",\"description\":\"Links entity to source code location(s) with provenance tracking. For inferred or generated elements, locations may be omitted when no source file exists yet.\",\"required\":[\"provenance\"],\"properties\":{\"provenance\":{\"$ref\":\"#/definitions/ProvenanceType\"},\"locations\":{\"type\":\"array\",\"minItems\":1,\"items\":{\"$ref\":\"#/definitions/SourceLocation\"},\"description\":\"One or more source code locations. Required for extracted and manual provenance; optional for inferred and generated.\"},\"repository\":{\"$ref\":\"#/definitions/RepositoryContext\"}}}}}, \"urn:dr:spec:base:source-references\");\n ajv.addSchema({\"$schema\":\"http://json-schema.org/draft-07/schema#\",\"title\":\"AttributeSpec Definitions\",\"description\":\"Reusable definition for attribute specifications used in spec-level schemas (e.g., spec-node-relationship attributes)\",\"definitions\":{\"AttributeSpec\":{\"type\":\"object\",\"title\":\"AttributeSpec\",\"description\":\"Specification for a single attribute that can appear on node or relationship instances\",\"required\":[\"type\",\"description\"],\"additionalProperties\":false,\"properties\":{\"type\":{\"type\":\"string\",\"enum\":[\"string\",\"integer\",\"number\",\"boolean\",\"array\",\"object\",\"enum\"],\"description\":\"The JSON type of this attribute\"},\"description\":{\"type\":\"string\",\"description\":\"Human-readable description of this attribute's purpose\"},\"enum_values\":{\"type\":\"array\",\"items\":{\"type\":\"string\"},\"description\":\"Required when type is 'enum'. Lists the valid string values for this attribute.\",\"examples\":[[\"high\",\"medium\",\"low\"],[\"active\",\"inactive\",\"archived\"]]},\"format\":{\"type\":\"string\",\"description\":\"Optional format constraint for string types (e.g., 'email', 'uri', 'date-time')\",\"examples\":[\"email\",\"uri\",\"date-time\",\"uuid\"]},\"default\":{\"description\":\"Default value for this attribute when not provided on a node instance. Can be any JSON value.\"}},\"if\":{\"properties\":{\"type\":{\"const\":\"enum\"}},\"required\":[\"type\"]},\"then\":{\"required\":[\"type\",\"description\",\"enum_values\"]}}}}, \"urn:dr:spec:base:attribute-spec\");\n\n return ajv;\n})();\n\n/**\n * Pre-compiled validator for SpecNode\n * Compiled once at module load, pre-cached for use throughout runtime\n */\nexport const validateSpecNode: ValidateFunction = sharedAjv.compile({\"$schema\":\"http://json-schema.org/draft-07/schema#\",\"title\":\"SpecNode\",\"description\":\"Base schema for all spec node types. Each node type schema extends this with type-specific attribute constraints via allOf.\",\"type\":\"object\",\"required\":[\"id\",\"path\",\"spec_node_id\",\"type\",\"name\"],\"additionalProperties\":false,\"properties\":{\"id\":{\"type\":\"string\",\"format\":\"uuid\",\"description\":\"Unique node instance identifier (UUIDv4). Globally unique across the entire model.\",\"examples\":[\"550e8400-e29b-41d4-a716-446655440000\"]},\"path\":{\"type\":\"string\",\"pattern\":\"^[a-z][a-z0-9-]*\\\\.[a-z][a-z0-9-]*\\\\.[a-z][a-z0-9-]*$\",\"description\":\"Human-readable element path in format {layer}.{type}.{name} (e.g., 'motivation.goal.increase-revenue')\"},\"spec_node_id\":{\"type\":\"string\",\"pattern\":\"^[a-z-]+\\\\.[a-z][a-z0-9-]*$\",\"description\":\"Reference to the spec node type that this node conforms to (e.g., 'motivation.goal')\"},\"type\":{\"type\":\"string\",\"description\":\"Denormalized node type for efficient filtering and queries. Extracted from spec_node_id (the part after the dot).\",\"examples\":[\"goal\",\"requirement\",\"endpoint\",\"table\"]},\"layer_id\":{\"type\":\"string\",\"pattern\":\"^[a-z][a-z0-9-]*$\",\"description\":\"Denormalized layer ID for efficient layer-scoped queries. Extracted from spec_node_id (the part before the dot).\"},\"name\":{\"type\":\"string\",\"description\":\"Human-readable instance name\",\"examples\":[\"Improve Customer Satisfaction\",\"User Login API\",\"Customer Table\"]},\"description\":{\"type\":\"string\",\"description\":\"Optional detailed description of this specific node instance\"},\"attributes\":{\"type\":\"object\",\"description\":\"Attribute values for this node instance. Keys must correspond to attributes defined in the per-type schema, and values must conform to the type constraints.\"},\"source_reference\":{\"$ref\":\"urn:dr:spec:base:source-references#/definitions/SourceReference\",\"description\":\"Optional provenance tracking linking this node to source code locations\"},\"metadata\":{\"type\":\"object\",\"description\":\"Optional metadata about the lifecycle and version of this node instance\",\"additionalProperties\":false,\"properties\":{\"created_at\":{\"type\":\"string\",\"format\":\"date-time\",\"description\":\"ISO 8601 timestamp when this node was created\"},\"updated_at\":{\"type\":\"string\",\"format\":\"date-time\",\"description\":\"ISO 8601 timestamp of the last modification\"},\"created_by\":{\"type\":\"string\",\"description\":\"User or system that created this node\"},\"version\":{\"type\":\"integer\",\"minimum\":1,\"description\":\"Version number of this node (incremented on updates)\"}}}}});\n/**\n * Pre-compiled validator for SpecNodeRelationship\n * Compiled once at module load, pre-cached for use throughout runtime\n */\nexport const validateSpecNodeRelationship: ValidateFunction = sharedAjv.compile({\"$schema\":\"http://json-schema.org/draft-07/schema#\",\"title\":\"SpecNodeRelationship\",\"description\":\"Base type for relationship type definitions in the specification. Defines valid relationships between node types, including cardinality, strength, and semantic properties.\",\"type\":\"object\",\"required\":[\"id\",\"source_spec_node_id\",\"destination_spec_node_id\",\"predicate\"],\"additionalProperties\":false,\"properties\":{\"id\":{\"type\":\"string\",\"pattern\":\"^[a-z-]+\\\\.[a-z-]+\\\\.[a-z-]+$\",\"description\":\"Unique relationship ID in format: {source-layer}.{predicate}.{dest-layer}. All components use lowercase with hyphens.\",\"examples\":[\"motivation.supports.motivation\",\"motivation.realizes.business\",\"api.exposes.data-model\"]},\"source_spec_node_id\":{\"type\":\"string\",\"pattern\":\"^[a-z-]+\\\\.[a-z][a-z0-9-]*$\",\"description\":\"SpecNode ID that can serve as the source of this relationship type\"},\"source_layer\":{\"type\":\"string\",\"pattern\":\"^[a-z][a-z0-9-]*$\",\"description\":\"Denormalized layer ID extracted from source_spec_node_id for efficient queries\"},\"destination_spec_node_id\":{\"type\":\"string\",\"pattern\":\"^[a-z-]+\\\\.[a-z][a-z0-9-]*$\",\"description\":\"SpecNode ID that can serve as the destination of this relationship type\"},\"destination_layer\":{\"type\":\"string\",\"pattern\":\"^[a-z][a-z0-9-]*$\",\"description\":\"Denormalized layer ID extracted from destination_spec_node_id for efficient queries\"},\"predicate\":{\"type\":\"string\",\"description\":\"Semantic predicate from PredicateCatalog describing the relationship type. Must be a valid predicate name.\",\"examples\":[\"supports\",\"realizes\",\"fulfills\",\"uses\",\"consumes\"]},\"cardinality\":{\"type\":\"string\",\"enum\":[\"one-to-one\",\"one-to-many\",\"many-to-one\",\"many-to-many\"],\"description\":\"Multiplicity constraint on this relationship type. Defines how many source nodes can relate to how many destination nodes.\",\"default\":\"many-to-many\"},\"strength\":{\"type\":\"string\",\"enum\":[\"critical\",\"high\",\"medium\",\"low\"],\"description\":\"Typical importance or strength of this relationship type\",\"default\":\"medium\"},\"required\":{\"type\":\"boolean\",\"description\":\"Whether instances of the source node type must have at least one relationship of this type\",\"default\":false},\"attributes\":{\"type\":\"object\",\"description\":\"Optional schema defining attributes that can appear on relationship instances of this type\",\"additionalProperties\":{\"$ref\":\"urn:dr:spec:base:attribute-spec#/definitions/AttributeSpec\"},\"minProperties\":0,\"examples\":[{\"reason\":{\"type\":\"string\",\"description\":\"Explanation for why this relationship exists\"},\"strength_override\":{\"type\":\"enum\",\"enum_values\":[\"critical\",\"high\",\"medium\",\"low\"],\"description\":\"Instance-specific strength override\"}}]}}});\n/**\n * Pre-compiled validator for Source Code Reference Definitions\n * Compiled once at module load, pre-cached for use throughout runtime\n */\nexport const validateSourceReference: ValidateFunction = sharedAjv.compile({\"$schema\":\"http://json-schema.org/draft-07/schema#\",\"title\":\"Source Code Reference Definitions\",\"description\":\"Reusable JSON Schema definitions for linking architecture elements to source code locations\",\"version\":\"1.0.0\",\"definitions\":{\"ProvenanceType\":{\"type\":\"string\",\"enum\":[\"extracted\",\"manual\",\"inferred\",\"generated\"],\"description\":\"How this reference was created: extracted (automated ingestion), manual (human added), inferred (pattern matching), generated (code generated from model)\"},\"SourceLocation\":{\"type\":\"object\",\"description\":\"A specific location in source code, identified by file path and optional symbol\",\"required\":[\"file\"],\"properties\":{\"file\":{\"type\":\"string\",\"minLength\":1,\"description\":\"File path relative to repository root\"},\"symbol\":{\"type\":\"string\",\"description\":\"Named code element (e.g., ClassName.methodName, function_name)\"}}},\"RepositoryContext\":{\"type\":\"object\",\"description\":\"Repository context for the source reference\",\"properties\":{\"url\":{\"type\":\"string\",\"format\":\"uri\",\"description\":\"Git remote URL (HTTPS or SSH format)\"},\"commit\":{\"type\":\"string\",\"pattern\":\"^[0-9a-f]{40}$\",\"description\":\"Full 40-character Git commit SHA\"}}},\"SourceReference\":{\"type\":\"object\",\"description\":\"Links entity to source code location(s) with provenance tracking. For inferred or generated elements, locations may be omitted when no source file exists yet.\",\"required\":[\"provenance\"],\"properties\":{\"provenance\":{\"$ref\":\"#/definitions/ProvenanceType\"},\"locations\":{\"type\":\"array\",\"minItems\":1,\"items\":{\"$ref\":\"#/definitions/SourceLocation\"},\"description\":\"One or more source code locations. Required for extracted and manual provenance; optional for inferred and generated.\"},\"repository\":{\"$ref\":\"#/definitions/RepositoryContext\"}}}}});\n/**\n * Pre-compiled validator for AttributeSpec Definitions\n * Compiled once at module load, pre-cached for use throughout runtime\n */\nexport const validateAttributeSpec: ValidateFunction = sharedAjv.compile({\"$schema\":\"http://json-schema.org/draft-07/schema#\",\"title\":\"AttributeSpec Definitions\",\"description\":\"Reusable definition for attribute specifications used in spec-level schemas (e.g., spec-node-relationship attributes)\",\"definitions\":{\"AttributeSpec\":{\"type\":\"object\",\"title\":\"AttributeSpec\",\"description\":\"Specification for a single attribute that can appear on node or relationship instances\",\"required\":[\"type\",\"description\"],\"additionalProperties\":false,\"properties\":{\"type\":{\"type\":\"string\",\"enum\":[\"string\",\"integer\",\"number\",\"boolean\",\"array\",\"object\",\"enum\"],\"description\":\"The JSON type of this attribute\"},\"description\":{\"type\":\"string\",\"description\":\"Human-readable description of this attribute's purpose\"},\"enum_values\":{\"type\":\"array\",\"items\":{\"type\":\"string\"},\"description\":\"Required when type is 'enum'. Lists the valid string values for this attribute.\",\"examples\":[[\"high\",\"medium\",\"low\"],[\"active\",\"inactive\",\"archived\"]]},\"format\":{\"type\":\"string\",\"description\":\"Optional format constraint for string types (e.g., 'email', 'uri', 'date-time')\",\"examples\":[\"email\",\"uri\",\"date-time\",\"uuid\"]},\"default\":{\"description\":\"Default value for this attribute when not provided on a node instance. Can be any JSON value.\"}},\"if\":{\"properties\":{\"type\":{\"const\":\"enum\"}},\"required\":[\"type\"]},\"then\":{\"required\":[\"type\",\"description\",\"enum_values\"]}}}});\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }