@documentation-robotics/cli 0.1.8 → 0.1.10

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 (120) hide show
  1. package/README.md +18 -17
  2. package/dist/audit/nodes/ai/prompts.js +1 -0
  3. package/dist/audit/nodes/ai/prompts.js.map +2 -2
  4. package/dist/audit/relationships/ai/prompts.js +20 -29
  5. package/dist/audit/relationships/ai/prompts.js.map +2 -2
  6. package/dist/audit/relationships/analysis/gap-analyzer.js.map +1 -1
  7. package/dist/audit/relationships/analysis/layer-templates.js +36 -0
  8. package/dist/audit/relationships/analysis/layer-templates.js.map +2 -2
  9. package/dist/cli.js +8 -8
  10. package/dist/cli.js.map +2 -2
  11. package/dist/commands/reports.js +3 -3
  12. package/dist/commands/reports.js.map +1 -1
  13. package/dist/commands/show.js.map +1 -1
  14. package/dist/commands/upgrade.js +1 -1
  15. package/dist/commands/upgrade.js.map +1 -1
  16. package/dist/commands/validate.js.map +1 -1
  17. package/dist/commands/version.js +1 -1
  18. package/dist/core/layers.js +1 -0
  19. package/dist/core/layers.js.map +2 -2
  20. package/dist/core/migration-registry.js +59 -2
  21. package/dist/core/migration-registry.js.map +2 -2
  22. package/dist/core/model.js +3 -16
  23. package/dist/core/model.js.map +2 -2
  24. package/dist/core/spec-loader.js.map +1 -1
  25. package/dist/core/stats-collector.js +2 -0
  26. package/dist/core/stats-collector.js.map +2 -2
  27. package/dist/export/archimate-exporter.js.map +2 -2
  28. package/dist/export/json-schema-exporter.js.map +1 -1
  29. package/dist/export/markdown-exporter.js.map +1 -1
  30. package/dist/export/markdown-utils.js +1 -0
  31. package/dist/export/markdown-utils.js.map +2 -2
  32. package/dist/export/mermaid-markdown-exporter.js.map +1 -1
  33. package/dist/export/openapi-exporter.js.map +1 -1
  34. package/dist/export/plantuml-exporter.js.map +1 -1
  35. package/dist/export/report-formatters.js +2 -2
  36. package/dist/export/report-formatters.js.map +1 -1
  37. package/dist/export/types.js +1 -0
  38. package/dist/export/types.js.map +2 -2
  39. package/dist/generated/layer-registry.js +44 -31
  40. package/dist/generated/layer-registry.js.map +2 -2
  41. package/dist/generated/layer-types.js +1 -1
  42. package/dist/generated/layer-types.js.map +2 -2
  43. package/dist/generated/node-types.js +45 -0
  44. package/dist/generated/node-types.js.map +2 -2
  45. package/dist/generated/relationship-index.js +201 -19
  46. package/dist/generated/relationship-index.js.map +2 -2
  47. package/dist/import/archimate-importer.js.map +1 -1
  48. package/dist/import/openapi-importer.js.map +1 -1
  49. package/dist/integrations/claude_code/agents/dr-advisor.md +14 -13
  50. package/dist/integrations/claude_code/agents/dr-extractor.md +2 -2
  51. package/dist/integrations/claude_code/commands/dr-info.md +1 -1
  52. package/dist/integrations/claude_code/commands/dr-init.md +3 -3
  53. package/dist/integrations/claude_code/commands/dr-map.md +2 -2
  54. package/dist/integrations/claude_code/commands/dr-model.md +1 -1
  55. package/dist/integrations/claude_code/commands/dr-relate.md +14 -4
  56. package/dist/integrations/claude_code/docs/END_TO_END_WALKTHROUGH.md +3 -3
  57. package/dist/integrations/claude_code/docs/QUICK_START.md +1 -1
  58. package/dist/integrations/claude_code/docs/README.md +2 -2
  59. package/dist/integrations/claude_code/skills/dr_01_motivation_layer/SKILL.md +2 -2
  60. package/dist/integrations/claude_code/skills/dr_03_product_layer/SKILL.md +679 -0
  61. package/dist/integrations/claude_code/skills/{dr_08_dataset_layer → dr_09_dataset_layer}/SKILL.md +1 -1
  62. package/dist/integrations/claude_code/skills/dr_engineering_guide/SKILL.md +2 -2
  63. package/dist/integrations/github_copilot/agents/dr-advisor.md +14 -13
  64. package/dist/integrations/github_copilot/agents/dr-architect.md +15 -14
  65. package/dist/integrations/github_copilot/skills/dr_01_motivation_layer/SKILL.md +2 -2
  66. package/dist/integrations/github_copilot/skills/dr_03_product_layer/SKILL.md +253 -0
  67. package/dist/reports/model-report-orchestrator.js +3 -3
  68. package/dist/reports/model-report-orchestrator.js.map +1 -1
  69. package/dist/schemas/bundled/analyzers/cbm.json +2 -2
  70. package/dist/schemas/bundled/analyzers/manifest.json +2 -2
  71. package/dist/schemas/bundled/api.json +3 -3
  72. package/dist/schemas/bundled/apm.json +3 -3
  73. package/dist/schemas/bundled/application.json +3 -3
  74. package/dist/schemas/bundled/base.json +29 -1
  75. package/dist/schemas/bundled/business.json +1 -1
  76. package/dist/schemas/bundled/data-model.json +3 -3
  77. package/dist/schemas/bundled/data-store.json +3 -3
  78. package/dist/schemas/bundled/manifest.json +20 -13
  79. package/dist/schemas/bundled/motivation.json +1 -1
  80. package/dist/schemas/bundled/navigation.json +3 -3
  81. package/dist/schemas/bundled/product.json +469 -0
  82. package/dist/schemas/bundled/security.json +3 -3
  83. package/dist/schemas/bundled/technology.json +3 -3
  84. package/dist/schemas/bundled/testing.json +3 -3
  85. package/dist/schemas/bundled/ux.json +3 -3
  86. package/dist/server/server.js +4 -15
  87. package/dist/server/server.js.map +2 -2
  88. package/dist/telemetry/index.js +1 -1
  89. package/dist/utils/spec-installer.js +2 -2
  90. package/dist/utils/spec-installer.js.map +1 -1
  91. package/dist/utils/spec-version.js +1 -1
  92. package/dist/utils/spec-version.js.map +2 -2
  93. package/dist/viewer/README.md +6 -6
  94. package/dist/viewer/assets/main-BRPZyc36.css +1 -0
  95. package/dist/viewer/assets/main-BrpLargo.js +81 -0
  96. package/dist/viewer/index.html +2 -2
  97. package/dist/viewer/manifest.json +10 -10
  98. package/dist/viewer/version.json +1 -1
  99. package/package.json +1 -1
  100. package/dist/viewer/assets/main-CY0Xufuj.css +0 -1
  101. package/dist/viewer/assets/main-DtgErnwF.js +0 -81
  102. /package/dist/integrations/claude_code/skills/{dr_03_security_layer → dr_04_security_layer}/SKILL.md +0 -0
  103. /package/dist/integrations/claude_code/skills/{dr_04_application_layer → dr_05_application_layer}/SKILL.md +0 -0
  104. /package/dist/integrations/claude_code/skills/{dr_05_technology_layer → dr_06_technology_layer}/SKILL.md +0 -0
  105. /package/dist/integrations/claude_code/skills/{dr_06_api_layer → dr_07_api_layer}/SKILL.md +0 -0
  106. /package/dist/integrations/claude_code/skills/{dr_07_data_model_layer → dr_08_data_model_layer}/SKILL.md +0 -0
  107. /package/dist/integrations/claude_code/skills/{dr_09_ux_layer → dr_10_ux_layer}/SKILL.md +0 -0
  108. /package/dist/integrations/claude_code/skills/{dr_10_navigation_layer → dr_11_navigation_layer}/SKILL.md +0 -0
  109. /package/dist/integrations/claude_code/skills/{dr_11_apm_layer → dr_12_apm_layer}/SKILL.md +0 -0
  110. /package/dist/integrations/claude_code/skills/{dr_12_testing_layer → dr_13_testing_layer}/SKILL.md +0 -0
  111. /package/dist/integrations/github_copilot/skills/{dr_03_security_layer → dr_04_security_layer}/SKILL.md +0 -0
  112. /package/dist/integrations/github_copilot/skills/{dr_04_application_layer → dr_05_application_layer}/SKILL.md +0 -0
  113. /package/dist/integrations/github_copilot/skills/{dr_05_technology_layer → dr_06_technology_layer}/SKILL.md +0 -0
  114. /package/dist/integrations/github_copilot/skills/{dr_06_api_layer → dr_07_api_layer}/SKILL.md +0 -0
  115. /package/dist/integrations/github_copilot/skills/{dr_07_data_model_layer → dr_08_data_model_layer}/SKILL.md +0 -0
  116. /package/dist/integrations/github_copilot/skills/{dr_08_dataset_layer → dr_09_dataset_layer}/SKILL.md +0 -0
  117. /package/dist/integrations/github_copilot/skills/{dr_09_ux_layer → dr_10_ux_layer}/SKILL.md +0 -0
  118. /package/dist/integrations/github_copilot/skills/{dr_10_navigation_layer → dr_11_navigation_layer}/SKILL.md +0 -0
  119. /package/dist/integrations/github_copilot/skills/{dr_11_apm_layer → dr_12_apm_layer}/SKILL.md +0 -0
  120. /package/dist/integrations/github_copilot/skills/{dr_12_testing_layer → dr_13_testing_layer}/SKILL.md +0 -0
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/export/markdown-exporter.ts"],
4
- "sourcesContent": ["import type { Model } from \"../core/model.js\";\nimport type { Exporter, ExportOptions } from \"./types.js\";\nimport { ALL_LAYERS } from \"./types.js\";\nimport { isTelemetryEnabled, startSpan, endSpan } from \"../telemetry/index.js\";\nimport { formatLayerName } from \"../utils/layer-name-formatter.js\";\nimport { getErrorMessage } from \"../utils/errors.js\";\nimport { escapeMarkdown, valueToMarkdown, getLayerDescription } from \"./markdown-utils.js\";\n\n/**\n * Markdown Exporter - generates comprehensive markdown documentation\n * Supports all 12 layers\n */\nexport class MarkdownExporter implements Exporter {\n name = \"Markdown\";\n supportedLayers = ALL_LAYERS;\n\n async export(model: Model, options: ExportOptions = {}): Promise<string> {\n const span = isTelemetryEnabled\n ? startSpan(\"export.format.markdown\", {\n \"export.layerCount\": options.layers?.length || this.supportedLayers.length,\n })\n : null;\n\n try {\n const lines: string[] = [];\n\n // Document header\n lines.push(`# ${this.escapeMarkdownLocal(model.manifest.name)}`);\n lines.push(\"\");\n\n if (model.manifest.description) {\n lines.push(`${model.manifest.description}`);\n lines.push(\"\");\n }\n\n // Model metadata\n lines.push(\"## Model Information\");\n lines.push(\"\");\n lines.push(`| Property | Value |`);\n lines.push(`| -------- | ----- |`);\n lines.push(`| Version | ${model.manifest.version || \"1.0.0\"} |`);\n if (model.manifest.author) {\n lines.push(`| Author | ${this.escapeMarkdownLocal(model.manifest.author)} |`);\n }\n if (model.manifest.created) {\n lines.push(`| Created | ${model.manifest.created} |`);\n }\n if (model.manifest.modified) {\n lines.push(`| Modified | ${model.manifest.modified} |`);\n }\n lines.push(\"\");\n\n const layersToExport = options.layers || this.supportedLayers;\n\n // Generate documentation for each layer\n for (const layerName of layersToExport) {\n const layer = await model.getLayer(layerName);\n if (!layer) continue;\n\n const elements = Array.from(layer.listElements());\n if (elements.length === 0) continue;\n\n lines.push(`## Layer: ${this.formatLayerName(layerName)}`);\n lines.push(\"\");\n\n const description = this.getLayerDescription(layerName);\n if (description) {\n lines.push(`*${description}*`);\n lines.push(\"\");\n }\n\n lines.push(`### Elements (${elements.length})`);\n lines.push(\"\");\n\n // Element table\n lines.push(`| ID | Name | Type | Description |`);\n lines.push(`| -- | ---- | ---- | ----------- |`);\n\n for (const element of elements) {\n const displayId = element.path || element.id;\n const id = this.escapeMarkdownLocal(displayId);\n const name = this.escapeMarkdownLocal(element.name);\n const type = this.escapeMarkdownLocal(element.type);\n const desc = element.description\n ? this.escapeMarkdownLocal(element.description).substring(0, 100)\n : \"\";\n\n lines.push(`| \\`${id}\\` | ${name} | ${type} | ${desc} |`);\n }\n\n lines.push(\"\");\n\n // Element details\n lines.push(`### Element Details`);\n lines.push(\"\");\n\n for (const element of elements) {\n const displayId = element.path || element.id;\n lines.push(`#### ${this.escapeMarkdownLocal(element.name)} (\\`${displayId}\\`)`);\n lines.push(\"\");\n\n if (element.description) {\n lines.push(`${element.description}`);\n lines.push(\"\");\n }\n\n lines.push(\"**Type:** \" + element.type);\n lines.push(\"\");\n\n // Source Reference\n const sourceRef = element.getSourceReference();\n if (sourceRef) {\n lines.push(\"### Source Code Location\");\n lines.push(\"\");\n lines.push(`**Provenance**: ${sourceRef.provenance}`);\n lines.push(\"\");\n\n lines.push(\"**Locations:**\");\n lines.push(\"\");\n (sourceRef.locations ?? []).forEach((loc, idx) => {\n lines.push(`${idx + 1}. \\`${this.escapeMarkdownLocal(loc.file)}\\``);\n if (loc.symbol) {\n lines.push(` - Symbol: \\`${this.escapeMarkdownLocal(loc.symbol)}\\``);\n }\n });\n lines.push(\"\");\n\n if (sourceRef.repository) {\n lines.push(\"**Repository Context:**\");\n lines.push(\"\");\n if (sourceRef.repository.url) {\n lines.push(`- Remote: ${sourceRef.repository.url}`);\n }\n if (sourceRef.repository.commit) {\n const shortCommit = sourceRef.repository.commit.substring(0, 7);\n if (sourceRef.repository.url) {\n lines.push(\n `- Commit: [\\`${shortCommit}\\`](${sourceRef.repository.url}/commit/${sourceRef.repository.commit})`\n );\n } else {\n lines.push(`- Commit: \\`${shortCommit}\\``);\n }\n }\n lines.push(\"\");\n }\n }\n\n // Properties (attributes)\n if (Object.keys(element.attributes).length > 0) {\n lines.push(\"**Properties:**\");\n lines.push(\"\");\n lines.push(`| Property | Value |`);\n lines.push(`| -------- | ----- |`);\n\n for (const [key, value] of Object.entries(element.attributes)) {\n const displayValue = this.valueToMarkdownLocal(value);\n lines.push(`| \\`${key}\\` | ${displayValue} |`);\n }\n lines.push(\"\");\n }\n\n // References\n if (element.references.length > 0) {\n lines.push(\"**Cross-Layer References:**\");\n lines.push(\"\");\n\n for (const ref of element.references) {\n const refDesc = ref.description ? ` - ${this.escapeMarkdownLocal(ref.description)}` : \"\";\n lines.push(`- **${ref.type}**: \\`${ref.target}\\`${refDesc}`);\n }\n lines.push(\"\");\n }\n\n // Relationships\n if (element.relationships.length > 0) {\n lines.push(\"**Relationships:**\");\n lines.push(\"\");\n\n for (const rel of element.relationships) {\n lines.push(`- **${rel.predicate}**: \\`${rel.target}\\``);\n }\n lines.push(\"\");\n }\n }\n\n // Layer summary\n lines.push(`### Layer Summary`);\n lines.push(\"\");\n lines.push(`- **Total Elements:** ${elements.length}`);\n\n const refCount = elements.reduce((sum, e) => sum + e.references.length, 0);\n const relCount = elements.reduce((sum, e) => sum + e.relationships.length, 0);\n\n lines.push(`- **Cross-Layer References:** ${refCount}`);\n lines.push(`- **Relationships:** ${relCount}`);\n\n lines.push(\"\");\n lines.push(\"---\");\n lines.push(\"\");\n }\n\n // Architecture Summary\n lines.push(\"## Architecture Summary\");\n lines.push(\"\");\n\n let totalElements = 0;\n let totalReferences = 0;\n let totalRelationships = 0;\n\n for (const layerName of layersToExport) {\n const layer = await model.getLayer(layerName);\n if (!layer) continue;\n\n for (const element of layer.listElements()) {\n totalElements++;\n totalReferences += element.references.length;\n totalRelationships += element.relationships.length;\n }\n }\n\n lines.push(`| Metric | Count |`);\n lines.push(`| ------ | ----- |`);\n lines.push(`| Total Elements | ${totalElements} |`);\n lines.push(`| Cross-Layer References | ${totalReferences} |`);\n lines.push(`| Relationships | ${totalRelationships} |`);\n lines.push(\"\");\n\n const result = lines.join(\"\\n\");\n\n if (isTelemetryEnabled && span) {\n (span as any).setAttribute(\"export.elementCount\", totalElements);\n (span as any).setAttribute(\"export.referenceCount\", totalReferences);\n (span as any).setAttribute(\"export.relationshipCount\", totalRelationships);\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 * Escape markdown special characters\n */\n private escapeMarkdownLocal(str: string): string {\n return escapeMarkdown(str);\n }\n\n /**\n * Format layer name for display\n */\n private formatLayerName(name: string): string {\n return formatLayerName(name);\n }\n\n /**\n * Get layer description\n */\n private getLayerDescription(layer: string): string {\n return getLayerDescription(layer);\n }\n\n /**\n * Convert value to markdown representation\n */\n private valueToMarkdownLocal(value: unknown): string {\n return valueToMarkdown(value);\n }\n}\n"],
4
+ "sourcesContent": ["import type { Model } from \"../core/model.js\";\nimport type { Exporter, ExportOptions } from \"./types.js\";\nimport { ALL_LAYERS } from \"./types.js\";\nimport { isTelemetryEnabled, startSpan, endSpan } from \"../telemetry/index.js\";\nimport { formatLayerName } from \"../utils/layer-name-formatter.js\";\nimport { getErrorMessage } from \"../utils/errors.js\";\nimport { escapeMarkdown, valueToMarkdown, getLayerDescription } from \"./markdown-utils.js\";\n\n/**\n * Markdown Exporter - generates comprehensive markdown documentation\n * Supports all 13 layers\n */\nexport class MarkdownExporter implements Exporter {\n name = \"Markdown\";\n supportedLayers = ALL_LAYERS;\n\n async export(model: Model, options: ExportOptions = {}): Promise<string> {\n const span = isTelemetryEnabled\n ? startSpan(\"export.format.markdown\", {\n \"export.layerCount\": options.layers?.length || this.supportedLayers.length,\n })\n : null;\n\n try {\n const lines: string[] = [];\n\n // Document header\n lines.push(`# ${this.escapeMarkdownLocal(model.manifest.name)}`);\n lines.push(\"\");\n\n if (model.manifest.description) {\n lines.push(`${model.manifest.description}`);\n lines.push(\"\");\n }\n\n // Model metadata\n lines.push(\"## Model Information\");\n lines.push(\"\");\n lines.push(`| Property | Value |`);\n lines.push(`| -------- | ----- |`);\n lines.push(`| Version | ${model.manifest.version || \"1.0.0\"} |`);\n if (model.manifest.author) {\n lines.push(`| Author | ${this.escapeMarkdownLocal(model.manifest.author)} |`);\n }\n if (model.manifest.created) {\n lines.push(`| Created | ${model.manifest.created} |`);\n }\n if (model.manifest.modified) {\n lines.push(`| Modified | ${model.manifest.modified} |`);\n }\n lines.push(\"\");\n\n const layersToExport = options.layers || this.supportedLayers;\n\n // Generate documentation for each layer\n for (const layerName of layersToExport) {\n const layer = await model.getLayer(layerName);\n if (!layer) continue;\n\n const elements = Array.from(layer.listElements());\n if (elements.length === 0) continue;\n\n lines.push(`## Layer: ${this.formatLayerName(layerName)}`);\n lines.push(\"\");\n\n const description = this.getLayerDescription(layerName);\n if (description) {\n lines.push(`*${description}*`);\n lines.push(\"\");\n }\n\n lines.push(`### Elements (${elements.length})`);\n lines.push(\"\");\n\n // Element table\n lines.push(`| ID | Name | Type | Description |`);\n lines.push(`| -- | ---- | ---- | ----------- |`);\n\n for (const element of elements) {\n const displayId = element.path || element.id;\n const id = this.escapeMarkdownLocal(displayId);\n const name = this.escapeMarkdownLocal(element.name);\n const type = this.escapeMarkdownLocal(element.type);\n const desc = element.description\n ? this.escapeMarkdownLocal(element.description).substring(0, 100)\n : \"\";\n\n lines.push(`| \\`${id}\\` | ${name} | ${type} | ${desc} |`);\n }\n\n lines.push(\"\");\n\n // Element details\n lines.push(`### Element Details`);\n lines.push(\"\");\n\n for (const element of elements) {\n const displayId = element.path || element.id;\n lines.push(`#### ${this.escapeMarkdownLocal(element.name)} (\\`${displayId}\\`)`);\n lines.push(\"\");\n\n if (element.description) {\n lines.push(`${element.description}`);\n lines.push(\"\");\n }\n\n lines.push(\"**Type:** \" + element.type);\n lines.push(\"\");\n\n // Source Reference\n const sourceRef = element.getSourceReference();\n if (sourceRef) {\n lines.push(\"### Source Code Location\");\n lines.push(\"\");\n lines.push(`**Provenance**: ${sourceRef.provenance}`);\n lines.push(\"\");\n\n lines.push(\"**Locations:**\");\n lines.push(\"\");\n (sourceRef.locations ?? []).forEach((loc, idx) => {\n lines.push(`${idx + 1}. \\`${this.escapeMarkdownLocal(loc.file)}\\``);\n if (loc.symbol) {\n lines.push(` - Symbol: \\`${this.escapeMarkdownLocal(loc.symbol)}\\``);\n }\n });\n lines.push(\"\");\n\n if (sourceRef.repository) {\n lines.push(\"**Repository Context:**\");\n lines.push(\"\");\n if (sourceRef.repository.url) {\n lines.push(`- Remote: ${sourceRef.repository.url}`);\n }\n if (sourceRef.repository.commit) {\n const shortCommit = sourceRef.repository.commit.substring(0, 7);\n if (sourceRef.repository.url) {\n lines.push(\n `- Commit: [\\`${shortCommit}\\`](${sourceRef.repository.url}/commit/${sourceRef.repository.commit})`\n );\n } else {\n lines.push(`- Commit: \\`${shortCommit}\\``);\n }\n }\n lines.push(\"\");\n }\n }\n\n // Properties (attributes)\n if (Object.keys(element.attributes).length > 0) {\n lines.push(\"**Properties:**\");\n lines.push(\"\");\n lines.push(`| Property | Value |`);\n lines.push(`| -------- | ----- |`);\n\n for (const [key, value] of Object.entries(element.attributes)) {\n const displayValue = this.valueToMarkdownLocal(value);\n lines.push(`| \\`${key}\\` | ${displayValue} |`);\n }\n lines.push(\"\");\n }\n\n // References\n if (element.references.length > 0) {\n lines.push(\"**Cross-Layer References:**\");\n lines.push(\"\");\n\n for (const ref of element.references) {\n const refDesc = ref.description ? ` - ${this.escapeMarkdownLocal(ref.description)}` : \"\";\n lines.push(`- **${ref.type}**: \\`${ref.target}\\`${refDesc}`);\n }\n lines.push(\"\");\n }\n\n // Relationships\n if (element.relationships.length > 0) {\n lines.push(\"**Relationships:**\");\n lines.push(\"\");\n\n for (const rel of element.relationships) {\n lines.push(`- **${rel.predicate}**: \\`${rel.target}\\``);\n }\n lines.push(\"\");\n }\n }\n\n // Layer summary\n lines.push(`### Layer Summary`);\n lines.push(\"\");\n lines.push(`- **Total Elements:** ${elements.length}`);\n\n const refCount = elements.reduce((sum, e) => sum + e.references.length, 0);\n const relCount = elements.reduce((sum, e) => sum + e.relationships.length, 0);\n\n lines.push(`- **Cross-Layer References:** ${refCount}`);\n lines.push(`- **Relationships:** ${relCount}`);\n\n lines.push(\"\");\n lines.push(\"---\");\n lines.push(\"\");\n }\n\n // Architecture Summary\n lines.push(\"## Architecture Summary\");\n lines.push(\"\");\n\n let totalElements = 0;\n let totalReferences = 0;\n let totalRelationships = 0;\n\n for (const layerName of layersToExport) {\n const layer = await model.getLayer(layerName);\n if (!layer) continue;\n\n for (const element of layer.listElements()) {\n totalElements++;\n totalReferences += element.references.length;\n totalRelationships += element.relationships.length;\n }\n }\n\n lines.push(`| Metric | Count |`);\n lines.push(`| ------ | ----- |`);\n lines.push(`| Total Elements | ${totalElements} |`);\n lines.push(`| Cross-Layer References | ${totalReferences} |`);\n lines.push(`| Relationships | ${totalRelationships} |`);\n lines.push(\"\");\n\n const result = lines.join(\"\\n\");\n\n if (isTelemetryEnabled && span) {\n (span as any).setAttribute(\"export.elementCount\", totalElements);\n (span as any).setAttribute(\"export.referenceCount\", totalReferences);\n (span as any).setAttribute(\"export.relationshipCount\", totalRelationships);\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 * Escape markdown special characters\n */\n private escapeMarkdownLocal(str: string): string {\n return escapeMarkdown(str);\n }\n\n /**\n * Format layer name for display\n */\n private formatLayerName(name: string): string {\n return formatLayerName(name);\n }\n\n /**\n * Get layer description\n */\n private getLayerDescription(layer: string): string {\n return getLayerDescription(layer);\n }\n\n /**\n * Convert value to markdown representation\n */\n private valueToMarkdownLocal(value: unknown): string {\n return valueToMarkdown(value);\n }\n}\n"],
5
5
  "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,6 +1,7 @@
1
1
  const LAYER_DESCRIPTIONS = {
2
2
  motivation: "Goals, requirements, drivers, and strategic outcomes of the architecture.",
3
3
  business: "Business processes, functions, roles, and services.",
4
+ product: "Product features, capabilities, personas, and milestones.",
4
5
  security: "Authentication, authorization, security threats, and controls.",
5
6
  application: "Application components, services, and interactions.",
6
7
  technology: "Infrastructure, platforms, systems, and technology components.",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/export/markdown-utils.ts"],
4
- "sourcesContent": ["/**\n * Shared markdown utilities for exporters\n */\n\n/**\n * Layer descriptions for documentation\n */\nexport const LAYER_DESCRIPTIONS = {\n motivation: \"Goals, requirements, drivers, and strategic outcomes of the architecture.\",\n business: \"Business processes, functions, roles, and services.\",\n security: \"Authentication, authorization, security threats, and controls.\",\n application: \"Application components, services, and interactions.\",\n technology: \"Infrastructure, platforms, systems, and technology components.\",\n api: \"REST APIs, operations, endpoints, and API integrations.\",\n \"data-model\": \"Data entities, relationships, and data structure definitions.\",\n \"data-store\": \"Databases, data stores, and persistence mechanisms.\",\n ux: \"User interface components, screens, and user experience elements.\",\n navigation: \"Application routing, navigation flows, and page structures.\",\n apm: \"Observability, monitoring, metrics, logging, and tracing.\",\n testing: \"Test strategies, test cases, test data, and test coverage.\",\n} as const;\n\n/**\n * Escape markdown special characters for safe display in markdown documents\n *\n * Escapes the following characters:\n * - `\\` \u2192 `\\\\` (backslash: prevents escape sequences)\n * - `|` \u2192 `\\|` (pipe: prevents table syntax interpretation)\n * - `*` \u2192 `\\*` (asterisk: prevents bold/italic formatting)\n * - `[` \u2192 `\\[` (bracket: prevents link syntax)\n * - `]` \u2192 `\\]` (bracket: prevents link syntax)\n * - `{` \u2192 `\\{` (brace: prevents code interpolation)\n * - `}` \u2192 `\\}` (brace: prevents code interpolation)\n * - `<` \u2192 `&lt;` (less-than: HTML entity for safety)\n * - `>` \u2192 `&gt;` (greater-than: HTML entity for safety)\n *\n * Note: Backticks (`) and underscores (_) are intentionally NOT escaped to allow\n * inline code and emphasis formatting in natural text output.\n */\nexport function escapeMarkdown(str: string): string {\n return str\n .replace(/\\\\/g, \"\\\\\\\\\")\n .replace(/\\|/g, \"\\\\|\")\n .replace(/\\*/g, \"\\\\*\")\n .replace(/\\[/g, \"\\\\[\")\n .replace(/\\]/g, \"\\\\]\")\n .replace(/\\{/g, \"\\\\{\")\n .replace(/\\}/g, \"\\\\}\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\");\n}\n\n/**\n * Convert any value to a safely escaped string representation for markdown display\n *\n * Handles different types with type-specific formatting:\n * - **Strings**: Fully escaped via escapeMarkdown() to prevent markdown interpretation\n * - **Numbers**: Rendered as plain numeric strings (no formatting needed)\n * - **Booleans**: Rendered as \"true\" or \"false\" strings\n * - **Arrays**: Rendered as `[item1, item2, ...]` with recursive escaping of elements\n * - **Objects**: Rendered as inline code block with JSON stringification: `{...}`\n * - **Null/Undefined**: Rendered as string representation\n */\nexport function valueToMarkdown(value: unknown): string {\n if (typeof value === \"string\") return escapeMarkdown(value);\n if (typeof value === \"number\") return String(value);\n if (typeof value === \"boolean\") return String(value);\n if (Array.isArray(value)) {\n return `[${value.map((v) => valueToMarkdown(v)).join(\", \")}]`;\n }\n if (value && typeof value === \"object\") {\n return `\\`${JSON.stringify(value)}\\``;\n }\n return String(value);\n}\n\n/**\n * Get layer description by layer name\n */\nexport function getLayerDescription(layer: string): string {\n return LAYER_DESCRIPTIONS[layer as keyof typeof LAYER_DESCRIPTIONS] || \"Architecture layer\";\n}\n"],
5
- "mappings": "AAOO,MAAM,qBAAqB;EAChC,YAAY;EACZ,UAAU;EACV,UAAU;EACV,aAAa;EACb,YAAY;EACZ,KAAK;EACL,cAAc;EACd,cAAc;EACd,IAAI;EACJ,YAAY;EACZ,KAAK;EACL,SAAS;;AAoBL,SAAU,eAAe,KAAW;AACxC,SAAO,IACJ,QAAQ,OAAO,MAAM,EACrB,QAAQ,OAAO,KAAK,EACpB,QAAQ,OAAO,KAAK,EACpB,QAAQ,OAAO,KAAK,EACpB,QAAQ,OAAO,KAAK,EACpB,QAAQ,OAAO,KAAK,EACpB,QAAQ,OAAO,KAAK,EACpB,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,MAAM;AACzB;AAaM,SAAU,gBAAgB,OAAc;AAC5C,SAAI,OAAO,SAAU,WAAiB,eAAe,KAAK,IACtD,OAAO,SAAU,YACjB,OAAO,SAAU,YAAkB,OAAO,KAAK,IAC/C,MAAM,QAAQ,KAAK,IACd,IAAI,MAAM,IAAI,CAAC,MAAM,gBAAgB,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC,MAExD,SAAS,OAAO,SAAU,WACrB,KAAK,KAAK,UAAU,KAAK,CAAC,OAE5B,OAAO,KAAK;AACrB;AAKM,SAAU,oBAAoB,OAAa;AAC/C,SAAO,mBAAmB,KAAwC,KAAK;AACzE;",
4
+ "sourcesContent": ["/**\n * Shared markdown utilities for exporters\n */\n\n/**\n * Layer descriptions for documentation\n */\nexport const LAYER_DESCRIPTIONS = {\n motivation: \"Goals, requirements, drivers, and strategic outcomes of the architecture.\",\n business: \"Business processes, functions, roles, and services.\",\n product: \"Product features, capabilities, personas, and milestones.\",\n security: \"Authentication, authorization, security threats, and controls.\",\n application: \"Application components, services, and interactions.\",\n technology: \"Infrastructure, platforms, systems, and technology components.\",\n api: \"REST APIs, operations, endpoints, and API integrations.\",\n \"data-model\": \"Data entities, relationships, and data structure definitions.\",\n \"data-store\": \"Databases, data stores, and persistence mechanisms.\",\n ux: \"User interface components, screens, and user experience elements.\",\n navigation: \"Application routing, navigation flows, and page structures.\",\n apm: \"Observability, monitoring, metrics, logging, and tracing.\",\n testing: \"Test strategies, test cases, test data, and test coverage.\",\n} as const;\n\n/**\n * Escape markdown special characters for safe display in markdown documents\n *\n * Escapes the following characters:\n * - `\\` \u2192 `\\\\` (backslash: prevents escape sequences)\n * - `|` \u2192 `\\|` (pipe: prevents table syntax interpretation)\n * - `*` \u2192 `\\*` (asterisk: prevents bold/italic formatting)\n * - `[` \u2192 `\\[` (bracket: prevents link syntax)\n * - `]` \u2192 `\\]` (bracket: prevents link syntax)\n * - `{` \u2192 `\\{` (brace: prevents code interpolation)\n * - `}` \u2192 `\\}` (brace: prevents code interpolation)\n * - `<` \u2192 `&lt;` (less-than: HTML entity for safety)\n * - `>` \u2192 `&gt;` (greater-than: HTML entity for safety)\n *\n * Note: Backticks (`) and underscores (_) are intentionally NOT escaped to allow\n * inline code and emphasis formatting in natural text output.\n */\nexport function escapeMarkdown(str: string): string {\n return str\n .replace(/\\\\/g, \"\\\\\\\\\")\n .replace(/\\|/g, \"\\\\|\")\n .replace(/\\*/g, \"\\\\*\")\n .replace(/\\[/g, \"\\\\[\")\n .replace(/\\]/g, \"\\\\]\")\n .replace(/\\{/g, \"\\\\{\")\n .replace(/\\}/g, \"\\\\}\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\");\n}\n\n/**\n * Convert any value to a safely escaped string representation for markdown display\n *\n * Handles different types with type-specific formatting:\n * - **Strings**: Fully escaped via escapeMarkdown() to prevent markdown interpretation\n * - **Numbers**: Rendered as plain numeric strings (no formatting needed)\n * - **Booleans**: Rendered as \"true\" or \"false\" strings\n * - **Arrays**: Rendered as `[item1, item2, ...]` with recursive escaping of elements\n * - **Objects**: Rendered as inline code block with JSON stringification: `{...}`\n * - **Null/Undefined**: Rendered as string representation\n */\nexport function valueToMarkdown(value: unknown): string {\n if (typeof value === \"string\") return escapeMarkdown(value);\n if (typeof value === \"number\") return String(value);\n if (typeof value === \"boolean\") return String(value);\n if (Array.isArray(value)) {\n return `[${value.map((v) => valueToMarkdown(v)).join(\", \")}]`;\n }\n if (value && typeof value === \"object\") {\n return `\\`${JSON.stringify(value)}\\``;\n }\n return String(value);\n}\n\n/**\n * Get layer description by layer name\n */\nexport function getLayerDescription(layer: string): string {\n return LAYER_DESCRIPTIONS[layer as keyof typeof LAYER_DESCRIPTIONS] || \"Architecture layer\";\n}\n"],
5
+ "mappings": "AAOO,MAAM,qBAAqB;EAChC,YAAY;EACZ,UAAU;EACV,SAAS;EACT,UAAU;EACV,aAAa;EACb,YAAY;EACZ,KAAK;EACL,cAAc;EACd,cAAc;EACd,IAAI;EACJ,YAAY;EACZ,KAAK;EACL,SAAS;;AAoBL,SAAU,eAAe,KAAW;AACxC,SAAO,IACJ,QAAQ,OAAO,MAAM,EACrB,QAAQ,OAAO,KAAK,EACpB,QAAQ,OAAO,KAAK,EACpB,QAAQ,OAAO,KAAK,EACpB,QAAQ,OAAO,KAAK,EACpB,QAAQ,OAAO,KAAK,EACpB,QAAQ,OAAO,KAAK,EACpB,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,MAAM;AACzB;AAaM,SAAU,gBAAgB,OAAc;AAC5C,SAAI,OAAO,SAAU,WAAiB,eAAe,KAAK,IACtD,OAAO,SAAU,YACjB,OAAO,SAAU,YAAkB,OAAO,KAAK,IAC/C,MAAM,QAAQ,KAAK,IACd,IAAI,MAAM,IAAI,CAAC,MAAM,gBAAgB,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC,MAExD,SAAS,OAAO,SAAU,WACrB,KAAK,KAAK,UAAU,KAAK,CAAC,OAE5B,OAAO,KAAK;AACrB;AAKM,SAAU,oBAAoB,OAAa;AAC/C,SAAO,mBAAmB,KAAwC,KAAK;AACzE;",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/export/mermaid-markdown-exporter.ts"],
4
- "sourcesContent": ["import type { Model } from \"../core/model.js\";\nimport type { Exporter, ExportOptions } from \"./types.js\";\nimport { ALL_LAYERS } from \"./types.js\";\nimport { MarkdownGenerator, type MarkdownGeneratorOptions } from \"./markdown-generator.js\";\nimport { isTelemetryEnabled, startSpan, endSpan } from \"../telemetry/index.js\";\nimport { getErrorMessage } from \"../utils/errors.js\";\n\n/**\n * Mermaid Markdown Exporter - generates comprehensive markdown documentation\n * with Mermaid diagrams and formatted tables\n *\n * Supports all 12 layers and includes:\n * - Architecture overview diagrams with Mermaid\n * - Layer-specific visualizations\n * - Formatted markdown tables\n * - Cross-layer relationship diagrams\n * - Element properties and relationship details\n */\nexport class MermaidMarkdownExporter implements Exporter {\n name = \"Mermaid Markdown\";\n supportedLayers = ALL_LAYERS;\n\n async export(model: Model, options: ExportOptions = {}): Promise<string> {\n const span = isTelemetryEnabled\n ? startSpan(\"export.format.mermaid-markdown\", {\n \"export.layerCount\": options.layers?.length || this.supportedLayers.length,\n })\n : null;\n\n try {\n // Create markdown generator with appropriate options\n const generatorOptions: MarkdownGeneratorOptions = {\n includeMermaid: true,\n includeTables: true,\n maxTableRows: 50,\n diagramType: \"graph\",\n };\n\n const generator = new MarkdownGenerator(model, generatorOptions);\n const markdown = await generator.generate();\n\n if (isTelemetryEnabled && span) {\n const totalElements = model.graph.nodes.size;\n const totalRelationships = model.graph.getAllEdges().length;\n\n (span as any).setAttribute(\"export.elementCount\", totalElements);\n (span as any).setAttribute(\"export.relationshipCount\", totalRelationships);\n (span as any).setAttribute(\"export.size\", markdown.length);\n (span as any).setStatus({ code: 0 });\n }\n\n return markdown;\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"],
4
+ "sourcesContent": ["import type { Model } from \"../core/model.js\";\nimport type { Exporter, ExportOptions } from \"./types.js\";\nimport { ALL_LAYERS } from \"./types.js\";\nimport { MarkdownGenerator, type MarkdownGeneratorOptions } from \"./markdown-generator.js\";\nimport { isTelemetryEnabled, startSpan, endSpan } from \"../telemetry/index.js\";\nimport { getErrorMessage } from \"../utils/errors.js\";\n\n/**\n * Mermaid Markdown Exporter - generates comprehensive markdown documentation\n * with Mermaid diagrams and formatted tables\n *\n * Supports all 13 layers and includes:\n * - Architecture overview diagrams with Mermaid\n * - Layer-specific visualizations\n * - Formatted markdown tables\n * - Cross-layer relationship diagrams\n * - Element properties and relationship details\n */\nexport class MermaidMarkdownExporter implements Exporter {\n name = \"Mermaid Markdown\";\n supportedLayers = ALL_LAYERS;\n\n async export(model: Model, options: ExportOptions = {}): Promise<string> {\n const span = isTelemetryEnabled\n ? startSpan(\"export.format.mermaid-markdown\", {\n \"export.layerCount\": options.layers?.length || this.supportedLayers.length,\n })\n : null;\n\n try {\n // Create markdown generator with appropriate options\n const generatorOptions: MarkdownGeneratorOptions = {\n includeMermaid: true,\n includeTables: true,\n maxTableRows: 50,\n diagramType: \"graph\",\n };\n\n const generator = new MarkdownGenerator(model, generatorOptions);\n const markdown = await generator.generate();\n\n if (isTelemetryEnabled && span) {\n const totalElements = model.graph.nodes.size;\n const totalRelationships = model.graph.getAllEdges().length;\n\n (span as any).setAttribute(\"export.elementCount\", totalElements);\n (span as any).setAttribute(\"export.relationshipCount\", totalRelationships);\n (span as any).setAttribute(\"export.size\", markdown.length);\n (span as any).setStatus({ code: 0 });\n }\n\n return markdown;\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"],
5
5
  "mappings": "AAEA,SAAS,kBAAkB;AAC3B,SAAS,yBAAwD;AACjE,SAAS,oBAAoB,WAAW,eAAe;AACvD,SAAS,uBAAuB;AAa1B,MAAO,wBAAuB;EAClC,OAAO;EACP,kBAAkB;EAElB,MAAM,OAAO,OAAc,UAAyB,CAAA,GAAE;AACpD,UAAM,OAAO,qBACT,UAAU,kCAAkC;MAC1C,qBAAqB,QAAQ,QAAQ,UAAU,KAAK,gBAAgB;KACrE,IACD;AAEJ,QAAI;AAEF,YAAM,mBAA6C;QACjD,gBAAgB;QAChB,eAAe;QACf,cAAc;QACd,aAAa;SAIT,WAAW,MADC,IAAI,kBAAkB,OAAO,gBAAgB,EAC9B,SAAQ;AAEzC,UAAI,sBAAsB,MAAM;AAC9B,cAAM,gBAAgB,MAAM,MAAM,MAAM,MAClC,qBAAqB,MAAM,MAAM,YAAW,EAAG;AAEpD,aAAa,aAAa,uBAAuB,aAAa,GAC9D,KAAa,aAAa,4BAA4B,kBAAkB,GACxE,KAAa,aAAa,eAAe,SAAS,MAAM,GACxD,KAAa,UAAU,EAAE,MAAM,EAAC,CAAE;MACrC;AAEA,aAAO;IACT,SAAS,OAAO;AACd,YAAI,sBAAsB,SACvB,KAAa,gBAAgB,KAAc,GAC3C,KAAa,UAAU;QACtB,MAAM;QACN,SAAS,gBAAgB,KAAK;OAC/B,IAEG;IACR;AACE,cAAQ,IAAI;IACd;EACF;;",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/export/openapi-exporter.ts"],
4
- "sourcesContent": ["import type { Model } from \"../core/model.js\";\nimport type { Exporter, ExportOptions } from \"./types.js\";\nimport { isTelemetryEnabled, startSpan, endSpan } from \"../telemetry/index.js\";\nimport { getErrorMessage } from \"../utils/errors.js\";\n\n/**\n * OpenAPI server definition\n * Specifies base URL and optional description for API access\n */\ninterface OpenAPIServer {\n url: string;\n description?: string;\n}\n\n/**\n * OpenAPI tag definition\n * Logical grouping for operations\n */\ninterface OpenAPITag {\n name: string;\n description?: string;\n}\n\n/**\n * OpenAPI external documentation link\n * Reference to external documentation\n */\ninterface OpenAPIExternalDocs {\n url: string;\n description?: string;\n}\n\n/**\n * OpenAPI info object\n * Metadata about the API\n */\ninterface OpenAPIInfo {\n title: string;\n version: string;\n description?: string;\n}\n\n/**\n * OpenAPI components section\n * Reusable schema definitions and other components\n */\ninterface OpenAPIComponents {\n schemas?: Record<string, unknown>;\n responses?: Record<string, unknown>;\n parameters?: Record<string, unknown>;\n requestBodies?: Record<string, unknown>;\n headers?: Record<string, unknown>;\n securitySchemes?: Record<string, unknown>;\n}\n\n/**\n * OpenAPI specification root\n * Complete OpenAPI 3.0 document structure\n */\ninterface OpenAPISpec {\n openapi: string;\n info: OpenAPIInfo;\n paths: Record<string, unknown>;\n components: OpenAPIComponents;\n servers?: OpenAPIServer[];\n tags?: OpenAPITag[];\n externalDocs?: OpenAPIExternalDocs;\n security?: unknown[];\n}\n\n/**\n * Endpoint mapping entry\n * Groups endpoints by path and method for processing\n */\ninterface EndpointData {\n name: string;\n id: string;\n description?: string;\n getProperty: (key: string) => unknown;\n getSourceReference: () => unknown;\n}\n\ninterface EndpointMapping {\n method: string;\n element: EndpointData;\n}\n\n/**\n * OpenAPI 3.0 Exporter for layer 6 (API)\n */\nexport class OpenAPIExporter implements Exporter {\n name = \"OpenAPI\";\n supportedLayers = [\"api\"];\n\n async export(model: Model, _options: ExportOptions = {}): Promise<string> {\n const span = isTelemetryEnabled ? startSpan(\"export.format.openapi\") : null;\n\n try {\n // Load API layer elements\n const apiLayer = await model.getLayer(\"api\");\n if (!apiLayer) {\n throw new Error(\"No API layer found in model\");\n }\n const elements = apiLayer.listElements();\n if (elements.length === 0) {\n throw new Error(\"No API layer found in model\");\n }\n\n // Note: _options is not used for OpenAPI exporter as it only supports the api layer\n // The parameter is kept for interface consistency with other exporters\n\n const spec: OpenAPISpec = {\n openapi: \"3.0.0\",\n info: {\n title: model.manifest.name,\n version: model.manifest.version || \"1.0.0\",\n },\n paths: {},\n components: {\n schemas: {},\n responses: {},\n parameters: {},\n requestBodies: {},\n headers: {},\n securitySchemes: {},\n },\n };\n\n if (model.manifest.description) {\n spec.info.description = model.manifest.description;\n }\n\n // Group operations by operationId-derived path\n const pathGroups = new Map<string, EndpointMapping[]>();\n\n // Iterate layer elements for operation/endpoint nodes\n for (const element of elements) {\n if (element.type === \"operation\" || element.type === \"endpoint\") {\n const operationId =\n (element.attributes?.operationId as string) || element.name;\n\n // Derive URL path from element attributes (for endpoints) or slug (for operations)\n let pathKey: string;\n const attrPath = element.attributes?.path as string;\n if (attrPath) {\n // Use path from attributes (e.g., \"/api/orders\")\n pathKey = attrPath;\n } else {\n // Derive URL path from element slug (last segment of path)\n // e.g., api.operation.get-user-profile \u2192 /get-user-profile\n const slugSegment = (element as { path?: string }).path?.split(\".\").pop();\n pathKey = slugSegment ? `/${slugSegment}` : `/${operationId}`;\n }\n\n // Infer HTTP method from operationId prefix keywords or use method attribute\n const method = ((element.attributes?.method as string) || (() => {\n const opIdLower = operationId.toLowerCase();\n if (/^(create|post|add|insert|register|submit|send)/.test(opIdLower)) {\n return \"post\";\n } else if (/^(update|put|edit|modify|replace|set|save)/.test(opIdLower)) {\n return \"put\";\n } else if (/^(patch|partial)/.test(opIdLower)) {\n return \"patch\";\n } else if (/^(delete|remove|destroy|purge|clear|unregister)/.test(opIdLower)) {\n return \"delete\";\n }\n return \"get\";\n })()).toLowerCase();\n\n if (!pathGroups.has(pathKey)) {\n pathGroups.set(pathKey, []);\n }\n\n const endpointData: EndpointData = {\n name: (element.attributes?.summary as string) || element.name,\n id: element.id,\n description: element.description,\n getProperty: (key: string) => element.attributes?.[key],\n getSourceReference: () => element.getSourceReference(),\n };\n\n pathGroups.get(pathKey)!.push({ method, element: endpointData });\n }\n }\n\n // Build paths section\n for (const [path, endpoints] of pathGroups) {\n const pathItem: Record<string, unknown> = {};\n\n for (const { method, element } of endpoints) {\n const operation: Record<string, unknown> = {\n summary: element.name,\n operationId: (element.getProperty(\"operationId\") as string) || element.id,\n responses: element.getProperty(\"responses\") || {\n \"200\": {\n description: \"Successful response\",\n },\n },\n };\n\n if (element.description) {\n operation.description = element.description;\n }\n\n const tags = element.getProperty(\"tags\");\n if (tags) {\n operation.tags = Array.isArray(tags) ? tags : [tags];\n }\n\n const parameters = element.getProperty(\"parameters\");\n if (parameters) {\n operation.parameters = parameters;\n }\n\n const requestBody = element.getProperty(\"requestBody\");\n if (requestBody) {\n operation.requestBody = requestBody;\n }\n\n const security = element.getProperty(\"security\");\n if (security) {\n operation.security = security;\n }\n\n const deprecated = element.getProperty(\"deprecated\");\n if (deprecated) {\n operation.deprecated = deprecated;\n }\n\n // Add source reference if present\n const sourceRef = element.getSourceReference();\n if (sourceRef) {\n operation[\"x-source-reference\"] = sourceRef;\n }\n\n pathItem[method] = operation;\n }\n\n // Add source reference to PathItem if any endpoint has one\n // (Use first endpoint's source reference for the path)\n if (endpoints.length > 0) {\n const firstSourceRef = endpoints[0].element.getSourceReference();\n if (firstSourceRef) {\n pathItem[\"x-source-reference\"] = firstSourceRef;\n }\n }\n\n (spec.paths as Record<string, unknown>)[path] = pathItem;\n }\n\n // Collect all schema definitions from elements\n for (const element of elements) {\n if (element.type === \"schema\") {\n const schemaName = (element.attributes?.schemaName as string) || element.id;\n const schema = element.attributes?.schema;\n if (schema) {\n spec.components.schemas![schemaName] = schema;\n }\n }\n }\n\n // Collect security schemes if defined\n for (const element of elements) {\n if (element.type === \"security-scheme\") {\n const schemeName = element.name;\n const schemeType = element.attributes?.type as string;\n if (schemeType) {\n const scheme: Record<string, unknown> = {\n type: schemeType,\n };\n\n const schemeProp = element.attributes?.scheme;\n if (schemeProp) {\n scheme.scheme = schemeProp;\n }\n\n const bearerFormat = element.attributes?.bearerFormat;\n if (bearerFormat) {\n scheme.bearerFormat = bearerFormat;\n }\n\n const flows = element.attributes?.flows;\n if (flows) {\n scheme.flows = flows;\n }\n\n const openIdConnectUrl = element.attributes?.openIdConnectUrl;\n if (openIdConnectUrl) {\n scheme.openIdConnectUrl = openIdConnectUrl;\n }\n\n if (element.description) {\n scheme.description = element.description;\n }\n\n spec.components.securitySchemes![schemeName] = scheme;\n }\n }\n }\n\n // Add servers if defined in manifest (would be stored separately)\n // For now, servers would need to be added via layer properties\n // This could be extended in the future\n\n // Remove empty component sections\n const components = spec.components;\n if (components.schemas && Object.keys(components.schemas).length === 0) {\n delete components.schemas;\n }\n if (components.responses && Object.keys(components.responses).length === 0) {\n delete components.responses;\n }\n if (components.parameters && Object.keys(components.parameters).length === 0) {\n delete components.parameters;\n }\n if (components.requestBodies && Object.keys(components.requestBodies).length === 0) {\n delete components.requestBodies;\n }\n if (components.headers && Object.keys(components.headers).length === 0) {\n delete components.headers;\n }\n if (components.securitySchemes && Object.keys(components.securitySchemes).length === 0) {\n delete components.securitySchemes;\n }\n if (Object.keys(components).length === 0) {\n delete (spec as Partial<OpenAPISpec>).components;\n }\n\n const result = JSON.stringify(spec, null, 2) + \"\\n\";\n\n if (isTelemetryEnabled && span) {\n const endpointCount = Array.from(pathGroups.values()).reduce(\n (sum, endpoints) => sum + endpoints.length,\n 0\n );\n (span as any).setAttribute(\"export.endpointCount\", endpointCount);\n (span as any).setAttribute(\"export.pathCount\", pathGroups.size);\n (span as any).setAttribute(\n \"export.schemaCount\",\n Object.keys(spec.components?.schemas || {}).length\n );\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"],
4
+ "sourcesContent": ["import type { Model } from \"../core/model.js\";\nimport type { Exporter, ExportOptions } from \"./types.js\";\nimport { isTelemetryEnabled, startSpan, endSpan } from \"../telemetry/index.js\";\nimport { getErrorMessage } from \"../utils/errors.js\";\n\n/**\n * OpenAPI server definition\n * Specifies base URL and optional description for API access\n */\ninterface OpenAPIServer {\n url: string;\n description?: string;\n}\n\n/**\n * OpenAPI tag definition\n * Logical grouping for operations\n */\ninterface OpenAPITag {\n name: string;\n description?: string;\n}\n\n/**\n * OpenAPI external documentation link\n * Reference to external documentation\n */\ninterface OpenAPIExternalDocs {\n url: string;\n description?: string;\n}\n\n/**\n * OpenAPI info object\n * Metadata about the API\n */\ninterface OpenAPIInfo {\n title: string;\n version: string;\n description?: string;\n}\n\n/**\n * OpenAPI components section\n * Reusable schema definitions and other components\n */\ninterface OpenAPIComponents {\n schemas?: Record<string, unknown>;\n responses?: Record<string, unknown>;\n parameters?: Record<string, unknown>;\n requestBodies?: Record<string, unknown>;\n headers?: Record<string, unknown>;\n securitySchemes?: Record<string, unknown>;\n}\n\n/**\n * OpenAPI specification root\n * Complete OpenAPI 3.0 document structure\n */\ninterface OpenAPISpec {\n openapi: string;\n info: OpenAPIInfo;\n paths: Record<string, unknown>;\n components: OpenAPIComponents;\n servers?: OpenAPIServer[];\n tags?: OpenAPITag[];\n externalDocs?: OpenAPIExternalDocs;\n security?: unknown[];\n}\n\n/**\n * Endpoint mapping entry\n * Groups endpoints by path and method for processing\n */\ninterface EndpointData {\n name: string;\n id: string;\n description?: string;\n getProperty: (key: string) => unknown;\n getSourceReference: () => unknown;\n}\n\ninterface EndpointMapping {\n method: string;\n element: EndpointData;\n}\n\n/**\n * OpenAPI 3.0 Exporter for layer 7 (API)\n */\nexport class OpenAPIExporter implements Exporter {\n name = \"OpenAPI\";\n supportedLayers = [\"api\"];\n\n async export(model: Model, _options: ExportOptions = {}): Promise<string> {\n const span = isTelemetryEnabled ? startSpan(\"export.format.openapi\") : null;\n\n try {\n // Load API layer elements\n const apiLayer = await model.getLayer(\"api\");\n if (!apiLayer) {\n throw new Error(\"No API layer found in model\");\n }\n const elements = apiLayer.listElements();\n if (elements.length === 0) {\n throw new Error(\"No API layer found in model\");\n }\n\n // Note: _options is not used for OpenAPI exporter as it only supports the api layer\n // The parameter is kept for interface consistency with other exporters\n\n const spec: OpenAPISpec = {\n openapi: \"3.0.0\",\n info: {\n title: model.manifest.name,\n version: model.manifest.version || \"1.0.0\",\n },\n paths: {},\n components: {\n schemas: {},\n responses: {},\n parameters: {},\n requestBodies: {},\n headers: {},\n securitySchemes: {},\n },\n };\n\n if (model.manifest.description) {\n spec.info.description = model.manifest.description;\n }\n\n // Group operations by operationId-derived path\n const pathGroups = new Map<string, EndpointMapping[]>();\n\n // Iterate layer elements for operation/endpoint nodes\n for (const element of elements) {\n if (element.type === \"operation\" || element.type === \"endpoint\") {\n const operationId =\n (element.attributes?.operationId as string) || element.name;\n\n // Derive URL path from element attributes (for endpoints) or slug (for operations)\n let pathKey: string;\n const attrPath = element.attributes?.path as string;\n if (attrPath) {\n // Use path from attributes (e.g., \"/api/orders\")\n pathKey = attrPath;\n } else {\n // Derive URL path from element slug (last segment of path)\n // e.g., api.operation.get-user-profile \u2192 /get-user-profile\n const slugSegment = (element as { path?: string }).path?.split(\".\").pop();\n pathKey = slugSegment ? `/${slugSegment}` : `/${operationId}`;\n }\n\n // Infer HTTP method from operationId prefix keywords or use method attribute\n const method = ((element.attributes?.method as string) || (() => {\n const opIdLower = operationId.toLowerCase();\n if (/^(create|post|add|insert|register|submit|send)/.test(opIdLower)) {\n return \"post\";\n } else if (/^(update|put|edit|modify|replace|set|save)/.test(opIdLower)) {\n return \"put\";\n } else if (/^(patch|partial)/.test(opIdLower)) {\n return \"patch\";\n } else if (/^(delete|remove|destroy|purge|clear|unregister)/.test(opIdLower)) {\n return \"delete\";\n }\n return \"get\";\n })()).toLowerCase();\n\n if (!pathGroups.has(pathKey)) {\n pathGroups.set(pathKey, []);\n }\n\n const endpointData: EndpointData = {\n name: (element.attributes?.summary as string) || element.name,\n id: element.id,\n description: element.description,\n getProperty: (key: string) => element.attributes?.[key],\n getSourceReference: () => element.getSourceReference(),\n };\n\n pathGroups.get(pathKey)!.push({ method, element: endpointData });\n }\n }\n\n // Build paths section\n for (const [path, endpoints] of pathGroups) {\n const pathItem: Record<string, unknown> = {};\n\n for (const { method, element } of endpoints) {\n const operation: Record<string, unknown> = {\n summary: element.name,\n operationId: (element.getProperty(\"operationId\") as string) || element.id,\n responses: element.getProperty(\"responses\") || {\n \"200\": {\n description: \"Successful response\",\n },\n },\n };\n\n if (element.description) {\n operation.description = element.description;\n }\n\n const tags = element.getProperty(\"tags\");\n if (tags) {\n operation.tags = Array.isArray(tags) ? tags : [tags];\n }\n\n const parameters = element.getProperty(\"parameters\");\n if (parameters) {\n operation.parameters = parameters;\n }\n\n const requestBody = element.getProperty(\"requestBody\");\n if (requestBody) {\n operation.requestBody = requestBody;\n }\n\n const security = element.getProperty(\"security\");\n if (security) {\n operation.security = security;\n }\n\n const deprecated = element.getProperty(\"deprecated\");\n if (deprecated) {\n operation.deprecated = deprecated;\n }\n\n // Add source reference if present\n const sourceRef = element.getSourceReference();\n if (sourceRef) {\n operation[\"x-source-reference\"] = sourceRef;\n }\n\n pathItem[method] = operation;\n }\n\n // Add source reference to PathItem if any endpoint has one\n // (Use first endpoint's source reference for the path)\n if (endpoints.length > 0) {\n const firstSourceRef = endpoints[0].element.getSourceReference();\n if (firstSourceRef) {\n pathItem[\"x-source-reference\"] = firstSourceRef;\n }\n }\n\n (spec.paths as Record<string, unknown>)[path] = pathItem;\n }\n\n // Collect all schema definitions from elements\n for (const element of elements) {\n if (element.type === \"schema\") {\n const schemaName = (element.attributes?.schemaName as string) || element.id;\n const schema = element.attributes?.schema;\n if (schema) {\n spec.components.schemas![schemaName] = schema;\n }\n }\n }\n\n // Collect security schemes if defined\n for (const element of elements) {\n if (element.type === \"security-scheme\") {\n const schemeName = element.name;\n const schemeType = element.attributes?.type as string;\n if (schemeType) {\n const scheme: Record<string, unknown> = {\n type: schemeType,\n };\n\n const schemeProp = element.attributes?.scheme;\n if (schemeProp) {\n scheme.scheme = schemeProp;\n }\n\n const bearerFormat = element.attributes?.bearerFormat;\n if (bearerFormat) {\n scheme.bearerFormat = bearerFormat;\n }\n\n const flows = element.attributes?.flows;\n if (flows) {\n scheme.flows = flows;\n }\n\n const openIdConnectUrl = element.attributes?.openIdConnectUrl;\n if (openIdConnectUrl) {\n scheme.openIdConnectUrl = openIdConnectUrl;\n }\n\n if (element.description) {\n scheme.description = element.description;\n }\n\n spec.components.securitySchemes![schemeName] = scheme;\n }\n }\n }\n\n // Add servers if defined in manifest (would be stored separately)\n // For now, servers would need to be added via layer properties\n // This could be extended in the future\n\n // Remove empty component sections\n const components = spec.components;\n if (components.schemas && Object.keys(components.schemas).length === 0) {\n delete components.schemas;\n }\n if (components.responses && Object.keys(components.responses).length === 0) {\n delete components.responses;\n }\n if (components.parameters && Object.keys(components.parameters).length === 0) {\n delete components.parameters;\n }\n if (components.requestBodies && Object.keys(components.requestBodies).length === 0) {\n delete components.requestBodies;\n }\n if (components.headers && Object.keys(components.headers).length === 0) {\n delete components.headers;\n }\n if (components.securitySchemes && Object.keys(components.securitySchemes).length === 0) {\n delete components.securitySchemes;\n }\n if (Object.keys(components).length === 0) {\n delete (spec as Partial<OpenAPISpec>).components;\n }\n\n const result = JSON.stringify(spec, null, 2) + \"\\n\";\n\n if (isTelemetryEnabled && span) {\n const endpointCount = Array.from(pathGroups.values()).reduce(\n (sum, endpoints) => sum + endpoints.length,\n 0\n );\n (span as any).setAttribute(\"export.endpointCount\", endpointCount);\n (span as any).setAttribute(\"export.pathCount\", pathGroups.size);\n (span as any).setAttribute(\n \"export.schemaCount\",\n Object.keys(spec.components?.schemas || {}).length\n );\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"],
5
5
  "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/export/plantuml-exporter.ts"],
4
- "sourcesContent": ["import type { Model } from \"../core/model.js\";\nimport type { Exporter, ExportOptions } from \"./types.js\";\nimport { ALL_LAYERS, LAYER_COLORS } from \"./types.js\";\nimport { isTelemetryEnabled, startSpan, endSpan } from \"../telemetry/index.js\";\nimport { getErrorMessage } from \"../utils/errors.js\";\n\n/**\n * PlantUML element entry for diagram generation\n * Contains element metadata for rendering from graph nodes\n */\ninterface PlantUMLElementEntry {\n id: string;\n name: string;\n type: string;\n description?: string;\n}\n\n/**\n * PlantUML Exporter - generates PlantUML syntax for diagram visualization\n * Supports all 12 layers\n *\n * Exports the model as PlantUML component diagram syntax with layers,\n * elements, relationships, and optional source references.\n */\nexport class PlantUMLExporter implements Exporter {\n name = \"PlantUML\";\n supportedLayers = ALL_LAYERS;\n\n async export(model: Model, options: ExportOptions = {}): Promise<string> {\n const span = isTelemetryEnabled\n ? startSpan(\"export.format.plantuml\", {\n \"export.layerCount\": options.layers?.length || this.supportedLayers.length,\n \"export.includeSources\": options.includeSources === true,\n })\n : null;\n\n try {\n const lines: string[] = [];\n\n lines.push(\"@startuml\");\n lines.push(`title \"${this.escapeQuotes(model.manifest.name)}\"`);\n lines.push(\"\");\n\n if (model.manifest.description) {\n lines.push(`note top : \"${this.escapeQuotes(model.manifest.description)}\"`);\n lines.push(\"\");\n }\n\n const layersToExport = options.layers || this.supportedLayers;\n const elementsByLayer = new Map<string, PlantUMLElementEntry[]>();\n const nodesByLayer = new Map<string, any[]>();\n // Map from raw graph node ID \u2192 sanitized PlantUML ID for edge rendering\n const rawToPlantUMLId = new Map<string, string>();\n\n // Collect nodes by layer from graph model\n for (const layerName of layersToExport) {\n const nodes = model.graph.getNodesByLayer(layerName);\n if (nodes.length === 0) continue;\n\n const layerElements: PlantUMLElementEntry[] = [];\n nodesByLayer.set(layerName, nodes);\n\n for (const node of nodes) {\n const pumlId = this.toPlantUMLId(node.id);\n rawToPlantUMLId.set(node.id, pumlId);\n layerElements.push({\n id: pumlId,\n name: node.name,\n type: node.type,\n description: node.description,\n });\n }\n elementsByLayer.set(layerName, layerElements);\n }\n\n // Create packages for each layer\n for (const layerName of layersToExport) {\n const elements = elementsByLayer.get(layerName);\n if (!elements || elements.length === 0) continue;\n\n const color = LAYER_COLORS[layerName] || \"FFFFFF\";\n lines.push(`package \"${layerName}\" #${color} {`);\n\n const nodes = nodesByLayer.get(layerName) || [];\n for (let i = 0; i < elements.length; i++) {\n const element = elements[i];\n lines.push(` component \"${this.escapeQuotes(element.name)}\" as ${element.id}`);\n\n // Add source reference as note if includeSources option is enabled\n if (options.includeSources) {\n const node = nodes[i];\n const sourceRef = this.extractSourceReference(node);\n if (sourceRef) {\n lines.push(` note right of ${element.id}`);\n lines.push(` ${this.escapeQuotes(sourceRef)}`);\n lines.push(` end note`);\n }\n }\n }\n\n lines.push(\"}\");\n lines.push(\"\");\n }\n\n // Add relationships from graph edges\n const edges = model.graph.getAllEdges();\n\n for (const edge of edges) {\n // Only include edges between exported nodes (check raw IDs)\n const srcPuml = rawToPlantUMLId.get(edge.source);\n const dstPuml = rawToPlantUMLId.get(edge.destination);\n if (srcPuml && dstPuml) {\n const arrow = this.getArrowType(edge.predicate);\n lines.push(\n `${srcPuml} ${arrow} ${dstPuml} : ${this.escapeQuotes(edge.predicate)}`\n );\n }\n }\n\n lines.push(\"\");\n lines.push(\"@enduml\");\n\n const result = lines.join(\"\\n\") + \"\\n\";\n\n if (isTelemetryEnabled && span) {\n // Count total elements and relationships\n let totalElements = 0;\n let totalEdges = 0;\n\n for (const elements of elementsByLayer.values()) {\n totalElements += elements.length;\n }\n\n for (const edge of edges) {\n if (rawToPlantUMLId.has(edge.source) && rawToPlantUMLId.has(edge.destination)) {\n totalEdges++;\n }\n }\n\n (span as any).setAttribute(\"export.elementCount\", totalElements);\n (span as any).setAttribute(\"export.relationshipCount\", totalEdges);\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 * Get PlantUML arrow type based on predicate\n */\n private getArrowType(predicate: string): string {\n const arrowMap: Record<string, string> = {\n composes: \"*--\",\n aggregates: \"o--\",\n supports: \"-->\",\n realizes: \"..|>\",\n \"flows-to\": \"-->\",\n \"refers-to\": \"..>\",\n };\n return arrowMap[predicate] || \"-->\";\n }\n\n /**\n * Extract and format source reference from node properties\n */\n private extractSourceReference(node: any): string | null {\n if (!node) return null;\n\n // Try node.source_reference first (primary field on GraphNode)\n let sourceRef = node.source_reference;\n\n // Fall back to x-source-reference in properties\n if (!sourceRef) {\n sourceRef = node.properties?.[\"x-source-reference\"];\n }\n\n // Fall back to nested source.reference format\n if (!sourceRef && node.properties?.source?.reference) {\n sourceRef = node.properties.source.reference;\n }\n\n if (!sourceRef) return null;\n\n // Format source reference for display\n const parts: string[] = [];\n\n if (Array.isArray(sourceRef.locations) && sourceRef.locations.length > 0) {\n const location = sourceRef.locations[0];\n if (location.file) {\n parts.push(`Source: ${location.file}`);\n }\n if (location.symbol) {\n parts.push(`Symbol: ${location.symbol}`);\n }\n }\n\n if (sourceRef.repository?.url) {\n parts.push(`Repo: ${sourceRef.repository.url}`);\n if (sourceRef.repository.commit) {\n parts.push(`Commit: ${sourceRef.repository.commit.substring(0, 8)}`);\n }\n }\n\n return parts.length > 0 ? parts.join(\"\\\\n\") : null;\n }\n\n /**\n * Escape quotes for PlantUML syntax\n */\n private escapeQuotes(str: string): string {\n // Escape double quotes within strings for PlantUML\n return str.replace(/\"/g, '\\\\\"');\n }\n\n /**\n * Convert a raw element ID (path or UUID) to a valid PlantUML identifier.\n * PlantUML identifiers cannot contain dots or hyphens, so replace with underscores.\n */\n private toPlantUMLId(id: string): string {\n return id.replace(/[.\\-]/g, \"_\");\n }\n}\n"],
4
+ "sourcesContent": ["import type { Model } from \"../core/model.js\";\nimport type { Exporter, ExportOptions } from \"./types.js\";\nimport { ALL_LAYERS, LAYER_COLORS } from \"./types.js\";\nimport { isTelemetryEnabled, startSpan, endSpan } from \"../telemetry/index.js\";\nimport { getErrorMessage } from \"../utils/errors.js\";\n\n/**\n * PlantUML element entry for diagram generation\n * Contains element metadata for rendering from graph nodes\n */\ninterface PlantUMLElementEntry {\n id: string;\n name: string;\n type: string;\n description?: string;\n}\n\n/**\n * PlantUML Exporter - generates PlantUML syntax for diagram visualization\n * Supports all 13 layers\n *\n * Exports the model as PlantUML component diagram syntax with layers,\n * elements, relationships, and optional source references.\n */\nexport class PlantUMLExporter implements Exporter {\n name = \"PlantUML\";\n supportedLayers = ALL_LAYERS;\n\n async export(model: Model, options: ExportOptions = {}): Promise<string> {\n const span = isTelemetryEnabled\n ? startSpan(\"export.format.plantuml\", {\n \"export.layerCount\": options.layers?.length || this.supportedLayers.length,\n \"export.includeSources\": options.includeSources === true,\n })\n : null;\n\n try {\n const lines: string[] = [];\n\n lines.push(\"@startuml\");\n lines.push(`title \"${this.escapeQuotes(model.manifest.name)}\"`);\n lines.push(\"\");\n\n if (model.manifest.description) {\n lines.push(`note top : \"${this.escapeQuotes(model.manifest.description)}\"`);\n lines.push(\"\");\n }\n\n const layersToExport = options.layers || this.supportedLayers;\n const elementsByLayer = new Map<string, PlantUMLElementEntry[]>();\n const nodesByLayer = new Map<string, any[]>();\n // Map from raw graph node ID \u2192 sanitized PlantUML ID for edge rendering\n const rawToPlantUMLId = new Map<string, string>();\n\n // Collect nodes by layer from graph model\n for (const layerName of layersToExport) {\n const nodes = model.graph.getNodesByLayer(layerName);\n if (nodes.length === 0) continue;\n\n const layerElements: PlantUMLElementEntry[] = [];\n nodesByLayer.set(layerName, nodes);\n\n for (const node of nodes) {\n const pumlId = this.toPlantUMLId(node.id);\n rawToPlantUMLId.set(node.id, pumlId);\n layerElements.push({\n id: pumlId,\n name: node.name,\n type: node.type,\n description: node.description,\n });\n }\n elementsByLayer.set(layerName, layerElements);\n }\n\n // Create packages for each layer\n for (const layerName of layersToExport) {\n const elements = elementsByLayer.get(layerName);\n if (!elements || elements.length === 0) continue;\n\n const color = LAYER_COLORS[layerName] || \"FFFFFF\";\n lines.push(`package \"${layerName}\" #${color} {`);\n\n const nodes = nodesByLayer.get(layerName) || [];\n for (let i = 0; i < elements.length; i++) {\n const element = elements[i];\n lines.push(` component \"${this.escapeQuotes(element.name)}\" as ${element.id}`);\n\n // Add source reference as note if includeSources option is enabled\n if (options.includeSources) {\n const node = nodes[i];\n const sourceRef = this.extractSourceReference(node);\n if (sourceRef) {\n lines.push(` note right of ${element.id}`);\n lines.push(` ${this.escapeQuotes(sourceRef)}`);\n lines.push(` end note`);\n }\n }\n }\n\n lines.push(\"}\");\n lines.push(\"\");\n }\n\n // Add relationships from graph edges\n const edges = model.graph.getAllEdges();\n\n for (const edge of edges) {\n // Only include edges between exported nodes (check raw IDs)\n const srcPuml = rawToPlantUMLId.get(edge.source);\n const dstPuml = rawToPlantUMLId.get(edge.destination);\n if (srcPuml && dstPuml) {\n const arrow = this.getArrowType(edge.predicate);\n lines.push(\n `${srcPuml} ${arrow} ${dstPuml} : ${this.escapeQuotes(edge.predicate)}`\n );\n }\n }\n\n lines.push(\"\");\n lines.push(\"@enduml\");\n\n const result = lines.join(\"\\n\") + \"\\n\";\n\n if (isTelemetryEnabled && span) {\n // Count total elements and relationships\n let totalElements = 0;\n let totalEdges = 0;\n\n for (const elements of elementsByLayer.values()) {\n totalElements += elements.length;\n }\n\n for (const edge of edges) {\n if (rawToPlantUMLId.has(edge.source) && rawToPlantUMLId.has(edge.destination)) {\n totalEdges++;\n }\n }\n\n (span as any).setAttribute(\"export.elementCount\", totalElements);\n (span as any).setAttribute(\"export.relationshipCount\", totalEdges);\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 * Get PlantUML arrow type based on predicate\n */\n private getArrowType(predicate: string): string {\n const arrowMap: Record<string, string> = {\n composes: \"*--\",\n aggregates: \"o--\",\n supports: \"-->\",\n realizes: \"..|>\",\n \"flows-to\": \"-->\",\n \"refers-to\": \"..>\",\n };\n return arrowMap[predicate] || \"-->\";\n }\n\n /**\n * Extract and format source reference from node properties\n */\n private extractSourceReference(node: any): string | null {\n if (!node) return null;\n\n // Try node.source_reference first (primary field on GraphNode)\n let sourceRef = node.source_reference;\n\n // Fall back to x-source-reference in properties\n if (!sourceRef) {\n sourceRef = node.properties?.[\"x-source-reference\"];\n }\n\n // Fall back to nested source.reference format\n if (!sourceRef && node.properties?.source?.reference) {\n sourceRef = node.properties.source.reference;\n }\n\n if (!sourceRef) return null;\n\n // Format source reference for display\n const parts: string[] = [];\n\n if (Array.isArray(sourceRef.locations) && sourceRef.locations.length > 0) {\n const location = sourceRef.locations[0];\n if (location.file) {\n parts.push(`Source: ${location.file}`);\n }\n if (location.symbol) {\n parts.push(`Symbol: ${location.symbol}`);\n }\n }\n\n if (sourceRef.repository?.url) {\n parts.push(`Repo: ${sourceRef.repository.url}`);\n if (sourceRef.repository.commit) {\n parts.push(`Commit: ${sourceRef.repository.commit.substring(0, 8)}`);\n }\n }\n\n return parts.length > 0 ? parts.join(\"\\\\n\") : null;\n }\n\n /**\n * Escape quotes for PlantUML syntax\n */\n private escapeQuotes(str: string): string {\n // Escape double quotes within strings for PlantUML\n return str.replace(/\"/g, '\\\\\"');\n }\n\n /**\n * Convert a raw element ID (path or UUID) to a valid PlantUML identifier.\n * PlantUML identifiers cannot contain dots or hyphens, so replace with underscores.\n */\n private toPlantUMLId(id: string): string {\n return id.replace(/[.\\-]/g, \"_\");\n }\n}\n"],
5
5
  "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -59,7 +59,7 @@ function formatRelationshipsSection(lines, report) {
59
59
  }
60
60
  function formatDataModelSection(lines, report) {
61
61
  const dataModel = report.dataModel;
62
- if (lines.push(ansis.bold("Data Model (Layer 7):")), lines.push(` ${ansis.gray("Total Entities:")} ${dataModel.entityCount}`), lines.push(` ${ansis.gray("Total Attributes:")} ${dataModel.attributeCount}`), lines.push(` ${ansis.gray("Entity Relationships:")} ${dataModel.relationshipCount}`), lines.push(` ${ansis.gray("Referenced Entities:")} ${dataModel.referencedEntities}`), lines.push(""), dataModel.orphanedEntities.length > 0) {
62
+ if (lines.push(ansis.bold("Data Model (Layer 8):")), lines.push(` ${ansis.gray("Total Entities:")} ${dataModel.entityCount}`), lines.push(` ${ansis.gray("Total Attributes:")} ${dataModel.attributeCount}`), lines.push(` ${ansis.gray("Entity Relationships:")} ${dataModel.relationshipCount}`), lines.push(` ${ansis.gray("Referenced Entities:")} ${dataModel.referencedEntities}`), lines.push(""), dataModel.orphanedEntities.length > 0) {
63
63
  lines.push(ansis.bold(ansis.yellow("\u26A0\uFE0F Orphaned Entities:")));
64
64
  for (const entity of dataModel.orphanedEntities.slice(0, 5))
65
65
  lines.push(` - ${entity}`);
@@ -94,7 +94,7 @@ function formatRelationshipsMarkdown(lines, report) {
94
94
  }
95
95
  function formatDataModelMarkdown(lines, report) {
96
96
  const dataModel = report.dataModel;
97
- if (lines.push("## Data Model (Layer 7)"), lines.push(""), lines.push("### Overview"), lines.push("| Metric | Value |"), lines.push("|--------|-------|"), lines.push(`| Total Entities | ${dataModel.entityCount} |`), lines.push(`| Total Attributes | ${dataModel.attributeCount} |`), lines.push(`| Entity Relationships | ${dataModel.relationshipCount} |`), lines.push(`| Referenced Entities | ${dataModel.referencedEntities} |`), lines.push(""), dataModel.orphanedEntities.length > 0) {
97
+ if (lines.push("## Data Model (Layer 8)"), lines.push(""), lines.push("### Overview"), lines.push("| Metric | Value |"), lines.push("|--------|-------|"), lines.push(`| Total Entities | ${dataModel.entityCount} |`), lines.push(`| Total Attributes | ${dataModel.attributeCount} |`), lines.push(`| Entity Relationships | ${dataModel.relationshipCount} |`), lines.push(`| Referenced Entities | ${dataModel.referencedEntities} |`), lines.push(""), dataModel.orphanedEntities.length > 0) {
98
98
  lines.push("### Orphaned Entities");
99
99
  for (const entity of dataModel.orphanedEntities)
100
100
  lines.push(`- ${entity}`);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/export/report-formatters.ts"],
4
- "sourcesContent": ["/**\n * Report formatters for comprehensive architecture reports\n * Supports text, JSON, and markdown output formats\n */\n\nimport ansis from \"ansis\";\nimport { ReportData, QualityMetrics } from \"../core/report-data-model.js\";\nimport { formatDate } from \"../utils/date-utils.js\";\n\nexport type ReportFormat = \"text\" | \"json\" | \"markdown\" | \"compact\";\n\nexport interface ReportFormatterOptions {\n format: ReportFormat;\n compact?: boolean;\n verbose?: boolean;\n includeDataModel?: boolean;\n includeQuality?: boolean;\n}\n\n/**\n * Format report for output\n */\nexport function formatReport(report: ReportData, options: ReportFormatterOptions): string {\n switch (options.format) {\n case \"json\":\n return formatJSON(report);\n case \"markdown\":\n return formatMarkdown(report, options);\n case \"compact\":\n return formatCompact(report);\n case \"text\":\n default:\n return formatText(report, options);\n }\n}\n\n/**\n * Format as plain text (default)\n */\nfunction formatText(report: ReportData, options: ReportFormatterOptions): string {\n const lines: string[] = [];\n\n // Header\n lines.push(\"\");\n lines.push(ansis.bold(`\uD83D\uDCCA Architecture Report: ${ansis.cyan(report.statistics.project.name)}`));\n lines.push(ansis.dim(\"=\".repeat(80)));\n lines.push(\"\");\n lines.push(`Generated: ${formatDate(report.timestamp)}`);\n lines.push(`Version: ${report.statistics.project.version}`);\n lines.push(\"\");\n\n // Quality Overview\n if (options.includeQuality) {\n formatQualitySection(lines, report.quality);\n lines.push(\"\");\n }\n\n // Statistics\n formatStatisticsSection(lines, report);\n lines.push(\"\");\n\n // Relationships\n formatRelationshipsSection(lines, report);\n lines.push(\"\");\n\n // Data Model\n if (options.includeDataModel) {\n formatDataModelSection(lines, report);\n lines.push(\"\");\n }\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Format as JSON\n */\nfunction formatJSON(report: ReportData): string {\n return JSON.stringify(report, null, 2) + \"\\n\";\n}\n\n/**\n * Format as Markdown\n */\nfunction formatMarkdown(report: ReportData, options: ReportFormatterOptions): string {\n const lines: string[] = [];\n\n // Header\n lines.push(`# Architecture Report: ${report.statistics.project.name}`);\n lines.push(\"\");\n lines.push(`**Generated:** ${formatDate(report.timestamp)}`);\n lines.push(`**Version:** ${report.statistics.project.version}`);\n lines.push(\"\");\n\n // Table of Contents\n lines.push(\"## Contents\");\n lines.push(\"- [Quality Metrics](#quality-metrics)\");\n lines.push(\"- [Statistics](#statistics)\");\n lines.push(\"- [Relationships](#relationships)\");\n if (options.includeDataModel) {\n lines.push(\"- [Data Model](#data-model)\");\n }\n lines.push(\"\");\n\n // Quality Metrics\n if (options.includeQuality) {\n formatQualityMarkdown(lines, report.quality);\n lines.push(\"\");\n }\n\n // Statistics\n formatStatisticsMarkdown(lines, report);\n lines.push(\"\");\n\n // Relationships\n formatRelationshipsMarkdown(lines, report);\n lines.push(\"\");\n\n // Data Model\n if (options.includeDataModel) {\n formatDataModelMarkdown(lines, report);\n lines.push(\"\");\n }\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Format as compact single line\n */\nfunction formatCompact(report: ReportData): string {\n const stats = report.statistics.statistics;\n const quality = report.quality;\n\n return (\n `${report.statistics.project.name} v${report.statistics.project.version}: ` +\n `${stats.totalElements} elements, ` +\n `${stats.totalRelationships} relationships, ` +\n `${report.relationships.circularDependencies.length} circular deps, ` +\n `${Math.round(quality.elementCoverage)}% coverage`\n );\n}\n\n/**\n * Format quality section for text output\n */\nfunction formatQualitySection(lines: string[], quality: QualityMetrics): void {\n lines.push(ansis.bold(\"Quality Metrics:\"));\n lines.push(\n ` ${ansis.gray(\"Element Coverage:\")} ${qualityBar(quality.elementCoverage)} ${quality.elementCoverage.toFixed(0)}%`\n );\n lines.push(\n ` ${ansis.gray(\"Relationship Coverage:\")} ${qualityBar(quality.relationshipCoverage)} ${quality.relationshipCoverage.toFixed(0)}%`\n );\n lines.push(\n ` ${ansis.gray(\"Documentation Coverage:\")} ${qualityBar(quality.documentationCoverage)} ${quality.documentationCoverage.toFixed(0)}%`\n );\n lines.push(\n ` ${ansis.gray(\"Layer Coverage:\")} ${qualityBar(quality.layerCoverage)} ${quality.layerCoverage.toFixed(0)}%`\n );\n lines.push(\"\");\n lines.push(\n ` ${ansis.gray(\"ArchiMate Compliance:\")} ${quality.archimateCompliance.toFixed(0)}%`\n );\n lines.push(\n ` ${ansis.gray(\"Spec Compliance:\")} ${quality.specCompliance.toFixed(0)}%`\n );\n lines.push(\n ` ${ansis.gray(\"Semantic Consistency:\")} ${quality.semanticConsistency.toFixed(0)}%`\n );\n lines.push(\"\");\n lines.push(\n ` ${ansis.gray(\"Orphaned Elements:\")} ${quality.orphanedElements > 0 ? ansis.yellow(quality.orphanedElements) : ansis.green(\"0\")}`\n );\n lines.push(\n ` ${ansis.gray(\"Circular Dependencies:\")} ${quality.circularDependencies > 0 ? ansis.red(quality.circularDependencies) : ansis.green(\"0\")}`\n );\n}\n\n/**\n * Format statistics section for text output\n */\nfunction formatStatisticsSection(lines: string[], report: ReportData): void {\n const stats = report.statistics;\n\n lines.push(ansis.bold(\"Statistics:\"));\n lines.push(\n ` ${ansis.gray(\"Total Elements:\")} ${stats.statistics.totalElements}`\n );\n lines.push(\n ` ${ansis.gray(\"Total Relationships:\")} ${stats.statistics.totalRelationships}`\n );\n lines.push(\n ` ${ansis.gray(\"Populated Layers:\")} ${stats.statistics.populatedLayers}/${stats.statistics.totalLayers}`\n );\n lines.push(\"\");\n\n lines.push(ansis.bold(\"Top Element Types:\"));\n for (const layer of stats.layers.slice(0, 5)) {\n if (layer.totalElements > 0) {\n const types = Object.entries(layer.elementsByType)\n .sort(([, a], [, b]) => b - a)\n .slice(0, 3)\n .map(([type, count]) => `${count} ${type}`)\n .join(\", \");\n lines.push(` ${layer.name}: ${types}`);\n }\n }\n}\n\n/**\n * Format relationships section for text output\n */\nfunction formatRelationshipsSection(lines: string[], report: ReportData): void {\n const relationships = report.relationships;\n\n lines.push(ansis.bold(\"Relationships:\"));\n lines.push(\n ` ${ansis.gray(\"Cross-Layer:\")} ${relationships.crossLayerCount}`\n );\n lines.push(\n ` ${ansis.gray(\"Intra-Layer:\")} ${relationships.intraLayerCount}`\n );\n lines.push(\"\");\n\n lines.push(ansis.bold(\"By Category:\"));\n const categoryEntries = Object.entries(relationships.byCategory)\n .sort(([, a], [, b]) => b - a)\n .slice(0, 5);\n\n for (const [category, count] of categoryEntries) {\n const percentage = relationships.totalRelationships > 0 ? (count / relationships.totalRelationships) * 100 : 0;\n lines.push(` ${category.padEnd(20)} ${String(count).padEnd(3)} (${percentage.toFixed(0)}%)`);\n }\n\n if (relationships.circularDependencies.length > 0) {\n lines.push(\"\");\n lines.push(ansis.bold(ansis.red(\"\u26A0\uFE0F Circular Dependencies:\")));\n for (const circular of relationships.circularDependencies.slice(0, 5)) {\n lines.push(` ${circular.elements.join(\" \u2192 \")} \u2192 ${circular.elements[0]}`);\n }\n }\n}\n\n/**\n * Format data model section for text output\n */\nfunction formatDataModelSection(lines: string[], report: ReportData): void {\n const dataModel = report.dataModel;\n\n lines.push(ansis.bold(\"Data Model (Layer 7):\"));\n lines.push(\n ` ${ansis.gray(\"Total Entities:\")} ${dataModel.entityCount}`\n );\n lines.push(\n ` ${ansis.gray(\"Total Attributes:\")} ${dataModel.attributeCount}`\n );\n lines.push(\n ` ${ansis.gray(\"Entity Relationships:\")} ${dataModel.relationshipCount}`\n );\n lines.push(\n ` ${ansis.gray(\"Referenced Entities:\")} ${dataModel.referencedEntities}`\n );\n lines.push(\"\");\n\n if (dataModel.orphanedEntities.length > 0) {\n lines.push(ansis.bold(ansis.yellow(\"\u26A0\uFE0F Orphaned Entities:\")));\n for (const entity of dataModel.orphanedEntities.slice(0, 5)) {\n lines.push(` - ${entity}`);\n }\n }\n}\n\n/**\n * Format quality section for markdown\n */\nfunction formatQualityMarkdown(lines: string[], quality: QualityMetrics): void {\n lines.push(\"## Quality Metrics\");\n lines.push(\"\");\n lines.push(\"### Coverage\");\n lines.push(\"| Metric | Value |\");\n lines.push(\"|--------|-------|\");\n lines.push(`| Element Coverage | ${quality.elementCoverage.toFixed(0)}% |`);\n lines.push(`| Relationship Coverage | ${quality.relationshipCoverage.toFixed(0)}% |`);\n lines.push(`| Documentation Coverage | ${quality.documentationCoverage.toFixed(0)}% |`);\n lines.push(`| Layer Coverage | ${quality.layerCoverage.toFixed(0)}% |`);\n lines.push(\"\");\n\n lines.push(\"### Compliance\");\n lines.push(\"| Metric | Score |\");\n lines.push(\"|--------|-------|\");\n lines.push(`| ArchiMate Compliance | ${quality.archimateCompliance.toFixed(0)}% |`);\n lines.push(`| Spec Compliance | ${quality.specCompliance.toFixed(0)}% |`);\n lines.push(`| Semantic Consistency | ${quality.semanticConsistency.toFixed(0)}% |`);\n lines.push(\"\");\n\n lines.push(\"### Issues\");\n lines.push(`- Orphaned Elements: ${quality.orphanedElements}`);\n lines.push(`- Circular Dependencies: ${quality.circularDependencies}`);\n lines.push(\"\");\n}\n\n/**\n * Format statistics section for markdown\n */\nfunction formatStatisticsMarkdown(lines: string[], report: ReportData): void {\n const stats = report.statistics;\n\n lines.push(\"## Statistics\");\n lines.push(\"\");\n lines.push(\"### Overview\");\n lines.push(\"| Metric | Value |\");\n lines.push(\"|--------|-------|\");\n lines.push(`| Total Elements | ${stats.statistics.totalElements} |`);\n lines.push(`| Total Relationships | ${stats.statistics.totalRelationships} |`);\n lines.push(`| Populated Layers | ${stats.statistics.populatedLayers}/${stats.statistics.totalLayers} |`);\n lines.push(\"\");\n\n lines.push(\"### Elements by Layer\");\n lines.push(\"| Layer | Count | Types |\");\n lines.push(\"|-------|-------|-------|\");\n for (const layer of stats.layers) {\n if (layer.totalElements > 0) {\n const types = Object.keys(layer.elementsByType).join(\", \");\n lines.push(`| ${layer.name} | ${layer.totalElements} | ${types} |`);\n }\n }\n lines.push(\"\");\n}\n\n/**\n * Format relationships section for markdown\n */\nfunction formatRelationshipsMarkdown(lines: string[], report: ReportData): void {\n const relationships = report.relationships;\n\n lines.push(\"## Relationships\");\n lines.push(\"\");\n lines.push(\"### Overview\");\n lines.push(\"| Type | Count |\");\n lines.push(\"|------|-------|\");\n lines.push(`| Total | ${relationships.totalRelationships} |`);\n lines.push(`| Cross-Layer | ${relationships.crossLayerCount} |`);\n lines.push(`| Intra-Layer | ${relationships.intraLayerCount} |`);\n lines.push(\"\");\n\n lines.push(\"### By Category\");\n lines.push(\"| Category | Count | Percentage |\");\n lines.push(\"|----------|-------|-----------|\");\n for (const [category, count] of Object.entries(relationships.byCategory)\n .sort(([, a], [, b]) => b - a)) {\n const percentage = ((count / relationships.totalRelationships) * 100).toFixed(1);\n lines.push(`| ${category} | ${count} | ${percentage}% |`);\n }\n lines.push(\"\");\n\n if (relationships.circularDependencies.length > 0) {\n lines.push(\"### Circular Dependencies\");\n for (const circular of relationships.circularDependencies) {\n lines.push(`- ${circular.elements.join(\" \u2192 \")} \u2192 ${circular.elements[0]}`);\n }\n lines.push(\"\");\n }\n}\n\n/**\n * Format data model section for markdown\n */\nfunction formatDataModelMarkdown(lines: string[], report: ReportData): void {\n const dataModel = report.dataModel;\n\n lines.push(\"## Data Model (Layer 7)\");\n lines.push(\"\");\n lines.push(\"### Overview\");\n lines.push(\"| Metric | Value |\");\n lines.push(\"|--------|-------|\");\n lines.push(`| Total Entities | ${dataModel.entityCount} |`);\n lines.push(`| Total Attributes | ${dataModel.attributeCount} |`);\n lines.push(`| Entity Relationships | ${dataModel.relationshipCount} |`);\n lines.push(`| Referenced Entities | ${dataModel.referencedEntities} |`);\n lines.push(\"\");\n\n if (dataModel.orphanedEntities.length > 0) {\n lines.push(\"### Orphaned Entities\");\n for (const entity of dataModel.orphanedEntities) {\n lines.push(`- ${entity}`);\n }\n lines.push(\"\");\n }\n}\n\n/**\n * Create quality progress bar\n */\nfunction qualityBar(percentage: number): string {\n const width = 20;\n const filled = Math.round((percentage / 100) * width);\n const empty = width - filled;\n\n const bar = \"\u2588\".repeat(filled) + \"\u2591\".repeat(empty);\n\n if (percentage >= 80) return ansis.green(bar);\n if (percentage >= 60) return ansis.yellow(bar);\n return ansis.red(bar);\n}\n"],
4
+ "sourcesContent": ["/**\n * Report formatters for comprehensive architecture reports\n * Supports text, JSON, and markdown output formats\n */\n\nimport ansis from \"ansis\";\nimport { ReportData, QualityMetrics } from \"../core/report-data-model.js\";\nimport { formatDate } from \"../utils/date-utils.js\";\n\nexport type ReportFormat = \"text\" | \"json\" | \"markdown\" | \"compact\";\n\nexport interface ReportFormatterOptions {\n format: ReportFormat;\n compact?: boolean;\n verbose?: boolean;\n includeDataModel?: boolean;\n includeQuality?: boolean;\n}\n\n/**\n * Format report for output\n */\nexport function formatReport(report: ReportData, options: ReportFormatterOptions): string {\n switch (options.format) {\n case \"json\":\n return formatJSON(report);\n case \"markdown\":\n return formatMarkdown(report, options);\n case \"compact\":\n return formatCompact(report);\n case \"text\":\n default:\n return formatText(report, options);\n }\n}\n\n/**\n * Format as plain text (default)\n */\nfunction formatText(report: ReportData, options: ReportFormatterOptions): string {\n const lines: string[] = [];\n\n // Header\n lines.push(\"\");\n lines.push(ansis.bold(`\uD83D\uDCCA Architecture Report: ${ansis.cyan(report.statistics.project.name)}`));\n lines.push(ansis.dim(\"=\".repeat(80)));\n lines.push(\"\");\n lines.push(`Generated: ${formatDate(report.timestamp)}`);\n lines.push(`Version: ${report.statistics.project.version}`);\n lines.push(\"\");\n\n // Quality Overview\n if (options.includeQuality) {\n formatQualitySection(lines, report.quality);\n lines.push(\"\");\n }\n\n // Statistics\n formatStatisticsSection(lines, report);\n lines.push(\"\");\n\n // Relationships\n formatRelationshipsSection(lines, report);\n lines.push(\"\");\n\n // Data Model\n if (options.includeDataModel) {\n formatDataModelSection(lines, report);\n lines.push(\"\");\n }\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Format as JSON\n */\nfunction formatJSON(report: ReportData): string {\n return JSON.stringify(report, null, 2) + \"\\n\";\n}\n\n/**\n * Format as Markdown\n */\nfunction formatMarkdown(report: ReportData, options: ReportFormatterOptions): string {\n const lines: string[] = [];\n\n // Header\n lines.push(`# Architecture Report: ${report.statistics.project.name}`);\n lines.push(\"\");\n lines.push(`**Generated:** ${formatDate(report.timestamp)}`);\n lines.push(`**Version:** ${report.statistics.project.version}`);\n lines.push(\"\");\n\n // Table of Contents\n lines.push(\"## Contents\");\n lines.push(\"- [Quality Metrics](#quality-metrics)\");\n lines.push(\"- [Statistics](#statistics)\");\n lines.push(\"- [Relationships](#relationships)\");\n if (options.includeDataModel) {\n lines.push(\"- [Data Model](#data-model)\");\n }\n lines.push(\"\");\n\n // Quality Metrics\n if (options.includeQuality) {\n formatQualityMarkdown(lines, report.quality);\n lines.push(\"\");\n }\n\n // Statistics\n formatStatisticsMarkdown(lines, report);\n lines.push(\"\");\n\n // Relationships\n formatRelationshipsMarkdown(lines, report);\n lines.push(\"\");\n\n // Data Model\n if (options.includeDataModel) {\n formatDataModelMarkdown(lines, report);\n lines.push(\"\");\n }\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Format as compact single line\n */\nfunction formatCompact(report: ReportData): string {\n const stats = report.statistics.statistics;\n const quality = report.quality;\n\n return (\n `${report.statistics.project.name} v${report.statistics.project.version}: ` +\n `${stats.totalElements} elements, ` +\n `${stats.totalRelationships} relationships, ` +\n `${report.relationships.circularDependencies.length} circular deps, ` +\n `${Math.round(quality.elementCoverage)}% coverage`\n );\n}\n\n/**\n * Format quality section for text output\n */\nfunction formatQualitySection(lines: string[], quality: QualityMetrics): void {\n lines.push(ansis.bold(\"Quality Metrics:\"));\n lines.push(\n ` ${ansis.gray(\"Element Coverage:\")} ${qualityBar(quality.elementCoverage)} ${quality.elementCoverage.toFixed(0)}%`\n );\n lines.push(\n ` ${ansis.gray(\"Relationship Coverage:\")} ${qualityBar(quality.relationshipCoverage)} ${quality.relationshipCoverage.toFixed(0)}%`\n );\n lines.push(\n ` ${ansis.gray(\"Documentation Coverage:\")} ${qualityBar(quality.documentationCoverage)} ${quality.documentationCoverage.toFixed(0)}%`\n );\n lines.push(\n ` ${ansis.gray(\"Layer Coverage:\")} ${qualityBar(quality.layerCoverage)} ${quality.layerCoverage.toFixed(0)}%`\n );\n lines.push(\"\");\n lines.push(\n ` ${ansis.gray(\"ArchiMate Compliance:\")} ${quality.archimateCompliance.toFixed(0)}%`\n );\n lines.push(\n ` ${ansis.gray(\"Spec Compliance:\")} ${quality.specCompliance.toFixed(0)}%`\n );\n lines.push(\n ` ${ansis.gray(\"Semantic Consistency:\")} ${quality.semanticConsistency.toFixed(0)}%`\n );\n lines.push(\"\");\n lines.push(\n ` ${ansis.gray(\"Orphaned Elements:\")} ${quality.orphanedElements > 0 ? ansis.yellow(quality.orphanedElements) : ansis.green(\"0\")}`\n );\n lines.push(\n ` ${ansis.gray(\"Circular Dependencies:\")} ${quality.circularDependencies > 0 ? ansis.red(quality.circularDependencies) : ansis.green(\"0\")}`\n );\n}\n\n/**\n * Format statistics section for text output\n */\nfunction formatStatisticsSection(lines: string[], report: ReportData): void {\n const stats = report.statistics;\n\n lines.push(ansis.bold(\"Statistics:\"));\n lines.push(\n ` ${ansis.gray(\"Total Elements:\")} ${stats.statistics.totalElements}`\n );\n lines.push(\n ` ${ansis.gray(\"Total Relationships:\")} ${stats.statistics.totalRelationships}`\n );\n lines.push(\n ` ${ansis.gray(\"Populated Layers:\")} ${stats.statistics.populatedLayers}/${stats.statistics.totalLayers}`\n );\n lines.push(\"\");\n\n lines.push(ansis.bold(\"Top Element Types:\"));\n for (const layer of stats.layers.slice(0, 5)) {\n if (layer.totalElements > 0) {\n const types = Object.entries(layer.elementsByType)\n .sort(([, a], [, b]) => b - a)\n .slice(0, 3)\n .map(([type, count]) => `${count} ${type}`)\n .join(\", \");\n lines.push(` ${layer.name}: ${types}`);\n }\n }\n}\n\n/**\n * Format relationships section for text output\n */\nfunction formatRelationshipsSection(lines: string[], report: ReportData): void {\n const relationships = report.relationships;\n\n lines.push(ansis.bold(\"Relationships:\"));\n lines.push(\n ` ${ansis.gray(\"Cross-Layer:\")} ${relationships.crossLayerCount}`\n );\n lines.push(\n ` ${ansis.gray(\"Intra-Layer:\")} ${relationships.intraLayerCount}`\n );\n lines.push(\"\");\n\n lines.push(ansis.bold(\"By Category:\"));\n const categoryEntries = Object.entries(relationships.byCategory)\n .sort(([, a], [, b]) => b - a)\n .slice(0, 5);\n\n for (const [category, count] of categoryEntries) {\n const percentage = relationships.totalRelationships > 0 ? (count / relationships.totalRelationships) * 100 : 0;\n lines.push(` ${category.padEnd(20)} ${String(count).padEnd(3)} (${percentage.toFixed(0)}%)`);\n }\n\n if (relationships.circularDependencies.length > 0) {\n lines.push(\"\");\n lines.push(ansis.bold(ansis.red(\"\u26A0\uFE0F Circular Dependencies:\")));\n for (const circular of relationships.circularDependencies.slice(0, 5)) {\n lines.push(` ${circular.elements.join(\" \u2192 \")} \u2192 ${circular.elements[0]}`);\n }\n }\n}\n\n/**\n * Format data model section for text output\n */\nfunction formatDataModelSection(lines: string[], report: ReportData): void {\n const dataModel = report.dataModel;\n\n lines.push(ansis.bold(\"Data Model (Layer 8):\"));\n lines.push(\n ` ${ansis.gray(\"Total Entities:\")} ${dataModel.entityCount}`\n );\n lines.push(\n ` ${ansis.gray(\"Total Attributes:\")} ${dataModel.attributeCount}`\n );\n lines.push(\n ` ${ansis.gray(\"Entity Relationships:\")} ${dataModel.relationshipCount}`\n );\n lines.push(\n ` ${ansis.gray(\"Referenced Entities:\")} ${dataModel.referencedEntities}`\n );\n lines.push(\"\");\n\n if (dataModel.orphanedEntities.length > 0) {\n lines.push(ansis.bold(ansis.yellow(\"\u26A0\uFE0F Orphaned Entities:\")));\n for (const entity of dataModel.orphanedEntities.slice(0, 5)) {\n lines.push(` - ${entity}`);\n }\n }\n}\n\n/**\n * Format quality section for markdown\n */\nfunction formatQualityMarkdown(lines: string[], quality: QualityMetrics): void {\n lines.push(\"## Quality Metrics\");\n lines.push(\"\");\n lines.push(\"### Coverage\");\n lines.push(\"| Metric | Value |\");\n lines.push(\"|--------|-------|\");\n lines.push(`| Element Coverage | ${quality.elementCoverage.toFixed(0)}% |`);\n lines.push(`| Relationship Coverage | ${quality.relationshipCoverage.toFixed(0)}% |`);\n lines.push(`| Documentation Coverage | ${quality.documentationCoverage.toFixed(0)}% |`);\n lines.push(`| Layer Coverage | ${quality.layerCoverage.toFixed(0)}% |`);\n lines.push(\"\");\n\n lines.push(\"### Compliance\");\n lines.push(\"| Metric | Score |\");\n lines.push(\"|--------|-------|\");\n lines.push(`| ArchiMate Compliance | ${quality.archimateCompliance.toFixed(0)}% |`);\n lines.push(`| Spec Compliance | ${quality.specCompliance.toFixed(0)}% |`);\n lines.push(`| Semantic Consistency | ${quality.semanticConsistency.toFixed(0)}% |`);\n lines.push(\"\");\n\n lines.push(\"### Issues\");\n lines.push(`- Orphaned Elements: ${quality.orphanedElements}`);\n lines.push(`- Circular Dependencies: ${quality.circularDependencies}`);\n lines.push(\"\");\n}\n\n/**\n * Format statistics section for markdown\n */\nfunction formatStatisticsMarkdown(lines: string[], report: ReportData): void {\n const stats = report.statistics;\n\n lines.push(\"## Statistics\");\n lines.push(\"\");\n lines.push(\"### Overview\");\n lines.push(\"| Metric | Value |\");\n lines.push(\"|--------|-------|\");\n lines.push(`| Total Elements | ${stats.statistics.totalElements} |`);\n lines.push(`| Total Relationships | ${stats.statistics.totalRelationships} |`);\n lines.push(`| Populated Layers | ${stats.statistics.populatedLayers}/${stats.statistics.totalLayers} |`);\n lines.push(\"\");\n\n lines.push(\"### Elements by Layer\");\n lines.push(\"| Layer | Count | Types |\");\n lines.push(\"|-------|-------|-------|\");\n for (const layer of stats.layers) {\n if (layer.totalElements > 0) {\n const types = Object.keys(layer.elementsByType).join(\", \");\n lines.push(`| ${layer.name} | ${layer.totalElements} | ${types} |`);\n }\n }\n lines.push(\"\");\n}\n\n/**\n * Format relationships section for markdown\n */\nfunction formatRelationshipsMarkdown(lines: string[], report: ReportData): void {\n const relationships = report.relationships;\n\n lines.push(\"## Relationships\");\n lines.push(\"\");\n lines.push(\"### Overview\");\n lines.push(\"| Type | Count |\");\n lines.push(\"|------|-------|\");\n lines.push(`| Total | ${relationships.totalRelationships} |`);\n lines.push(`| Cross-Layer | ${relationships.crossLayerCount} |`);\n lines.push(`| Intra-Layer | ${relationships.intraLayerCount} |`);\n lines.push(\"\");\n\n lines.push(\"### By Category\");\n lines.push(\"| Category | Count | Percentage |\");\n lines.push(\"|----------|-------|-----------|\");\n for (const [category, count] of Object.entries(relationships.byCategory)\n .sort(([, a], [, b]) => b - a)) {\n const percentage = ((count / relationships.totalRelationships) * 100).toFixed(1);\n lines.push(`| ${category} | ${count} | ${percentage}% |`);\n }\n lines.push(\"\");\n\n if (relationships.circularDependencies.length > 0) {\n lines.push(\"### Circular Dependencies\");\n for (const circular of relationships.circularDependencies) {\n lines.push(`- ${circular.elements.join(\" \u2192 \")} \u2192 ${circular.elements[0]}`);\n }\n lines.push(\"\");\n }\n}\n\n/**\n * Format data model section for markdown\n */\nfunction formatDataModelMarkdown(lines: string[], report: ReportData): void {\n const dataModel = report.dataModel;\n\n lines.push(\"## Data Model (Layer 8)\");\n lines.push(\"\");\n lines.push(\"### Overview\");\n lines.push(\"| Metric | Value |\");\n lines.push(\"|--------|-------|\");\n lines.push(`| Total Entities | ${dataModel.entityCount} |`);\n lines.push(`| Total Attributes | ${dataModel.attributeCount} |`);\n lines.push(`| Entity Relationships | ${dataModel.relationshipCount} |`);\n lines.push(`| Referenced Entities | ${dataModel.referencedEntities} |`);\n lines.push(\"\");\n\n if (dataModel.orphanedEntities.length > 0) {\n lines.push(\"### Orphaned Entities\");\n for (const entity of dataModel.orphanedEntities) {\n lines.push(`- ${entity}`);\n }\n lines.push(\"\");\n }\n}\n\n/**\n * Create quality progress bar\n */\nfunction qualityBar(percentage: number): string {\n const width = 20;\n const filled = Math.round((percentage / 100) * width);\n const empty = width - filled;\n\n const bar = \"\u2588\".repeat(filled) + \"\u2591\".repeat(empty);\n\n if (percentage >= 80) return ansis.green(bar);\n if (percentage >= 60) return ansis.yellow(bar);\n return ansis.red(bar);\n}\n"],
5
5
  "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -2,6 +2,7 @@ import { getAllLayerIds } from "../generated/layer-registry.js";
2
2
  const LAYER_COLORS = {
3
3
  motivation: "FFE4E1",
4
4
  business: "E6F3FF",
5
+ product: "E6FFD9",
5
6
  security: "FFE6E6",
6
7
  application: "E6FFE6",
7
8
  technology: "FFFFE6",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/export/types.ts"],
4
- "sourcesContent": ["import type { Model } from \"../core/model.js\";\nimport { getAllLayerIds } from \"../generated/layer-registry.js\";\n\n/**\n * Options for export operations\n */\nexport interface ExportOptions {\n layers?: string[];\n outputPath?: string;\n format?: string;\n includeSources?: boolean; // For PlantUML: include source file paths as notes\n}\n\n/**\n * Interface for format-specific exporters\n */\nexport interface Exporter {\n /** Display name of the exporter */\n name: string;\n\n /** Layers this exporter supports */\n supportedLayers: string[];\n\n /**\n * Export model or subset to the format\n */\n export(model: Model, options: ExportOptions): Promise<string>;\n}\n\n/**\n * Metadata about a registered export format\n */\nexport interface ExportFormatInfo {\n format: string;\n name: string;\n description: string;\n supportedLayers: string[];\n mimeType: string;\n}\n\n/**\n * Shared layer colors for consistent visualization across exporters\n * Note: Color values do NOT include '#' prefix - exporters add it as needed\n */\nexport const LAYER_COLORS: Record<string, string> = {\n motivation: \"FFE4E1\",\n business: \"E6F3FF\",\n security: \"FFE6E6\",\n application: \"E6FFE6\",\n technology: \"FFFFE6\",\n api: \"F0E6FF\",\n \"data-model\": \"E6F0FF\",\n \"data-store\": \"FFE6F0\",\n ux: \"FFCCCC\",\n navigation: \"CCFFCC\",\n apm: \"CCFFFF\",\n testing: \"FFCCFF\",\n};\n\n/**\n * All 12 supported layers (from generated registry)\n */\nexport const ALL_LAYERS: string[] = getAllLayerIds();\n\n/**\n * Escape XML special characters\n */\nexport function escapeXml(str: string): string {\n return str\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&apos;\");\n}\n"],
5
- "mappings": "AACA,SAAS,sBAAsB;AA2CxB,MAAM,eAAuC;EAClD,YAAY;EACZ,UAAU;EACV,UAAU;EACV,aAAa;EACb,YAAY;EACZ,KAAK;EACL,cAAc;EACd,cAAc;EACd,IAAI;EACJ,YAAY;EACZ,KAAK;EACL,SAAS;GAME,aAAuB,eAAc;AAK5C,SAAU,UAAU,KAAW;AACnC,SAAO,IACJ,QAAQ,MAAM,OAAO,EACrB,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,QAAQ,EACtB,QAAQ,MAAM,QAAQ;AAC3B;",
4
+ "sourcesContent": ["import type { Model } from \"../core/model.js\";\nimport { getAllLayerIds } from \"../generated/layer-registry.js\";\n\n/**\n * Options for export operations\n */\nexport interface ExportOptions {\n layers?: string[];\n outputPath?: string;\n format?: string;\n includeSources?: boolean; // For PlantUML: include source file paths as notes\n}\n\n/**\n * Interface for format-specific exporters\n */\nexport interface Exporter {\n /** Display name of the exporter */\n name: string;\n\n /** Layers this exporter supports */\n supportedLayers: string[];\n\n /**\n * Export model or subset to the format\n */\n export(model: Model, options: ExportOptions): Promise<string>;\n}\n\n/**\n * Metadata about a registered export format\n */\nexport interface ExportFormatInfo {\n format: string;\n name: string;\n description: string;\n supportedLayers: string[];\n mimeType: string;\n}\n\n/**\n * Shared layer colors for consistent visualization across exporters\n * Note: Color values do NOT include '#' prefix - exporters add it as needed\n */\nexport const LAYER_COLORS: Record<string, string> = {\n motivation: \"FFE4E1\",\n business: \"E6F3FF\",\n product: \"E6FFD9\",\n security: \"FFE6E6\",\n application: \"E6FFE6\",\n technology: \"FFFFE6\",\n api: \"F0E6FF\",\n \"data-model\": \"E6F0FF\",\n \"data-store\": \"FFE6F0\",\n ux: \"FFCCCC\",\n navigation: \"CCFFCC\",\n apm: \"CCFFFF\",\n testing: \"FFCCFF\",\n};\n\n/**\n * All 13 supported layers (from generated registry)\n */\nexport const ALL_LAYERS: string[] = getAllLayerIds();\n\n/**\n * Escape XML special characters\n */\nexport function escapeXml(str: string): string {\n return str\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&apos;\");\n}\n"],
5
+ "mappings": "AACA,SAAS,sBAAsB;AA2CxB,MAAM,eAAuC;EAClD,YAAY;EACZ,UAAU;EACV,SAAS;EACT,UAAU;EACV,aAAa;EACb,YAAY;EACZ,KAAK;EACL,cAAc;EACd,cAAc;EACd,IAAI;EACJ,YAAY;EACZ,KAAK;EACL,SAAS;GAME,aAAuB,eAAc;AAK5C,SAAU,UAAU,KAAW;AACnC,SAAO,IACJ,QAAQ,MAAM,OAAO,EACrB,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,QAAQ,EACtB,QAAQ,MAAM,QAAQ;AAC3B;",
6
6
  "names": []
7
7
  }
@@ -20,11 +20,22 @@ const LAYER_METADATA_MOTIVATION = {
20
20
  version: "3.2",
21
21
  url: "https://pubs.opengroup.org/architecture/archimate32-doc/"
22
22
  }
23
+ }, LAYER_METADATA_PRODUCT = {
24
+ id: "product",
25
+ number: 3,
26
+ name: "Product Layer",
27
+ description: "Layer 3: Product Layer",
28
+ nodeTypes: ["product.capability", "product.feature", "product.milestone", "product.persona", "product.userworkflow"],
29
+ inspiredBy: {
30
+ standard: "ArchiMate 3.2 Strategy Extension + Product Management Practice",
31
+ version: "3.2",
32
+ url: "https://pubs.opengroup.org/architecture/archimate32-doc/"
33
+ }
23
34
  }, LAYER_METADATA_SECURITY = {
24
35
  id: "security",
25
- number: 3,
36
+ number: 4,
26
37
  name: "Security Layer",
27
- description: "Layer 3: Security Layer",
38
+ description: "Layer 4: Security Layer",
28
39
  nodeTypes: ["security.accesscondition", "security.accountabilityrequirement", "security.actor", "security.auditconfig", "security.authenticationconfig", "security.bindingofduty", "security.condition", "security.countermeasure", "security.dataclassification", "security.delegation", "security.evidence", "security.fieldaccesscontrol", "security.informationentity", "security.informationright", "security.needtoknow", "security.passwordpolicy", "security.permission", "security.policyaction", "security.policyrule", "security.resourceoperation", "security.retentionpolicy", "security.role", "security.secureresource", "security.securityconstraints", "security.securitymodel", "security.securitypolicy", "security.separationofduty", "security.threat", "security.validationrule"],
29
40
  inspiredBy: {
30
41
  standard: "NIST SP 800-53",
@@ -33,9 +44,9 @@ const LAYER_METADATA_MOTIVATION = {
33
44
  }
34
45
  }, LAYER_METADATA_APPLICATION = {
35
46
  id: "application",
36
- number: 4,
47
+ number: 5,
37
48
  name: "Application Layer",
38
- description: "Layer 4: Application Layer",
49
+ description: "Layer 5: Application Layer",
39
50
  nodeTypes: ["application.applicationcollaboration", "application.applicationcomponent", "application.applicationevent", "application.applicationfunction", "application.applicationinteraction", "application.applicationinterface", "application.applicationprocess", "application.applicationservice", "application.dataobject"],
40
51
  inspiredBy: {
41
52
  standard: "ArchiMate 3.2",
@@ -44,9 +55,9 @@ const LAYER_METADATA_MOTIVATION = {
44
55
  }
45
56
  }, LAYER_METADATA_TECHNOLOGY = {
46
57
  id: "technology",
47
- number: 5,
58
+ number: 6,
48
59
  name: "Technology Layer",
49
- description: "Layer 5: Technology Layer",
60
+ description: "Layer 6: Technology Layer",
50
61
  nodeTypes: ["technology.artifact", "technology.communicationnetwork", "technology.device", "technology.node", "technology.path", "technology.systemsoftware", "technology.technologycollaboration", "technology.technologyevent", "technology.technologyfunction", "technology.technologyinteraction", "technology.technologyinterface", "technology.technologyprocess", "technology.technologyservice"],
51
62
  inspiredBy: {
52
63
  standard: "ArchiMate 3.2",
@@ -55,9 +66,9 @@ const LAYER_METADATA_MOTIVATION = {
55
66
  }
56
67
  }, LAYER_METADATA_API = {
57
68
  id: "api",
58
- number: 6,
69
+ number: 7,
59
70
  name: "API Layer",
60
- description: "Layer 6: API Layer",
71
+ description: "Layer 7: API Layer",
61
72
  nodeTypes: ["api.callback", "api.components", "api.contact", "api.encoding", "api.example", "api.externaldocumentation", "api.header", "api.info", "api.license", "api.link", "api.mediatype", "api.oauthflow", "api.oauthflows", "api.openapidocument", "api.operation", "api.parameter", "api.pathitem", "api.ratelimit", "api.paths", "api.requestbody", "api.response", "api.responses", "api.schema", "api.securityscheme", "api.server", "api.servervariable", "api.tag"],
62
73
  inspiredBy: {
63
74
  standard: "OpenAPI 3.0",
@@ -66,9 +77,9 @@ const LAYER_METADATA_MOTIVATION = {
66
77
  }
67
78
  }, LAYER_METADATA_DATA_MODEL = {
68
79
  id: "data-model",
69
- number: 7,
80
+ number: 8,
70
81
  name: "Data Model Layer",
71
- description: "Layer 7: Data Model Layer",
82
+ description: "Layer 8: Data Model Layer",
72
83
  nodeTypes: [],
73
84
  inspiredBy: {
74
85
  standard: "JSON Schema Draft 7",
@@ -77,9 +88,9 @@ const LAYER_METADATA_MOTIVATION = {
77
88
  }
78
89
  }, LAYER_METADATA_DATA_STORE = {
79
90
  id: "data-store",
80
- number: 8,
91
+ number: 9,
81
92
  name: "Data Store Layer",
82
- description: "Layer 8: Data Store Layer",
93
+ description: "Layer 9: Data Store Layer",
83
94
  nodeTypes: ["data-store.accesspattern", "data-store.collection", "data-store.database", "data-store.eventhandler", "data-store.field", "data-store.index", "data-store.namespace", "data-store.retentionpolicy", "data-store.storedlogic", "data-store.validationrule", "data-store.view"],
84
95
  inspiredBy: {
85
96
  standard: "ISO/IEC 9075 (SQL) + Paradigm Extensions",
@@ -88,9 +99,9 @@ const LAYER_METADATA_MOTIVATION = {
88
99
  }
89
100
  }, LAYER_METADATA_UX = {
90
101
  id: "ux",
91
- number: 9,
102
+ number: 10,
92
103
  name: "UX Layer",
93
- description: "Layer 9: UX Layer",
104
+ description: "Layer 10: UX Layer",
94
105
  nodeTypes: ["ux.actioncomponent", "ux.actionpattern", "ux.chartseries", "ux.componentinstance", "ux.componentreference", "ux.dataconfig", "ux.errorconfig", "ux.experiencestate", "ux.layoutconfig", "ux.librarycomponent", "ux.librarysubview", "ux.stateaction", "ux.stateactiontemplate", "ux.statepattern", "ux.statetransition", "ux.subview", "ux.tablecolumn", "ux.transitiontemplate", "ux.uxapplication", "ux.uxlibrary", "ux.uxspec", "ux.view"],
95
106
  inspiredBy: {
96
107
  standard: "HTML 5.3",
@@ -99,9 +110,9 @@ const LAYER_METADATA_MOTIVATION = {
99
110
  }
100
111
  }, LAYER_METADATA_NAVIGATION = {
101
112
  id: "navigation",
102
- number: 10,
113
+ number: 11,
103
114
  name: "Navigation Layer",
104
- description: "Layer 10: Navigation Layer",
115
+ description: "Layer 11: Navigation Layer",
105
116
  nodeTypes: ["navigation.breadcrumbconfig", "navigation.contextvariable", "navigation.flowstep", "navigation.guardaction", "navigation.guardcondition", "navigation.navigationflow", "navigation.navigationgraph", "navigation.navigationguard", "navigation.navigationtransition", "navigation.route", "navigation.routemeta"],
106
117
  inspiredBy: {
107
118
  standard: "SPA Navigation Patterns",
@@ -110,9 +121,9 @@ const LAYER_METADATA_MOTIVATION = {
110
121
  }
111
122
  }, LAYER_METADATA_APM = {
112
123
  id: "apm",
113
- number: 11,
124
+ number: 12,
114
125
  name: "APM Observability Layer",
115
- description: "Layer 11: APM Observability Layer",
126
+ description: "Layer 12: APM Observability Layer",
116
127
  nodeTypes: ["apm.alert", "apm.dashboard", "apm.exporterconfig", "apm.instrumentationconfig", "apm.instrumentationscope", "apm.logconfiguration", "apm.logprocessor", "apm.logrecord", "apm.metricconfiguration", "apm.metricinstrument", "apm.resource", "apm.span", "apm.spanevent", "apm.spanlink", "apm.traceconfiguration"],
117
128
  inspiredBy: {
118
129
  standard: "OpenTelemetry",
@@ -121,9 +132,9 @@ const LAYER_METADATA_MOTIVATION = {
121
132
  }
122
133
  }, LAYER_METADATA_TESTING = {
123
134
  id: "testing",
124
- number: 12,
135
+ number: 13,
125
136
  name: "Testing Layer",
126
- description: "Layer 12: Testing Layer",
137
+ description: "Layer 13: Testing Layer",
127
138
  nodeTypes: ["testing.contextvariation", "testing.coverageexclusion", "testing.coveragegap", "testing.coveragerequirement", "testing.coveragesummary", "testing.environmentfactor", "testing.inputpartitionselection", "testing.inputselection", "testing.inputspacepartition", "testing.outcomecategory", "testing.partitiondependency", "testing.partitionvalue", "testing.targetcoveragesummary", "testing.targetinputfield", "testing.testcasesketch", "testing.testcoveragemodel", "testing.testcoveragetarget"],
128
139
  inspiredBy: {
129
140
  standard: "IEEE 829-2008",
@@ -133,6 +144,7 @@ const LAYER_METADATA_MOTIVATION = {
133
144
  }, LAYERS = /* @__PURE__ */ new Map([
134
145
  ["motivation", LAYER_METADATA_MOTIVATION],
135
146
  ["business", LAYER_METADATA_BUSINESS],
147
+ ["product", LAYER_METADATA_PRODUCT],
136
148
  ["security", LAYER_METADATA_SECURITY],
137
149
  ["application", LAYER_METADATA_APPLICATION],
138
150
  ["technology", LAYER_METADATA_TECHNOLOGY],
@@ -146,17 +158,18 @@ const LAYER_METADATA_MOTIVATION = {
146
158
  ]), LAYERS_BY_NUMBER = /* @__PURE__ */ new Map([
147
159
  [1, LAYER_METADATA_MOTIVATION],
148
160
  [2, LAYER_METADATA_BUSINESS],
149
- [3, LAYER_METADATA_SECURITY],
150
- [4, LAYER_METADATA_APPLICATION],
151
- [5, LAYER_METADATA_TECHNOLOGY],
152
- [6, LAYER_METADATA_API],
153
- [7, LAYER_METADATA_DATA_MODEL],
154
- [8, LAYER_METADATA_DATA_STORE],
155
- [9, LAYER_METADATA_UX],
156
- [10, LAYER_METADATA_NAVIGATION],
157
- [11, LAYER_METADATA_APM],
158
- [12, LAYER_METADATA_TESTING]
159
- ]), LAYER_HIERARCHY = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
161
+ [3, LAYER_METADATA_PRODUCT],
162
+ [4, LAYER_METADATA_SECURITY],
163
+ [5, LAYER_METADATA_APPLICATION],
164
+ [6, LAYER_METADATA_TECHNOLOGY],
165
+ [7, LAYER_METADATA_API],
166
+ [8, LAYER_METADATA_DATA_MODEL],
167
+ [9, LAYER_METADATA_DATA_STORE],
168
+ [10, LAYER_METADATA_UX],
169
+ [11, LAYER_METADATA_NAVIGATION],
170
+ [12, LAYER_METADATA_APM],
171
+ [13, LAYER_METADATA_TESTING]
172
+ ]), LAYER_HIERARCHY = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13];
160
173
  function getLayerByNumber(n) {
161
174
  return LAYERS_BY_NUMBER.get(n);
162
175
  }