@documentation-robotics/cli 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (169) hide show
  1. package/PYTHON_CLI_PARITY.md +265 -0
  2. package/PYTHON_CLI_STRUCTURE_UPDATE.md +246 -0
  3. package/README.md +926 -0
  4. package/biome.json +42 -0
  5. package/bunfig.toml +3 -0
  6. package/dist/ai/claude-client.js +71 -0
  7. package/dist/ai/claude-client.js.map +7 -0
  8. package/dist/ai/context-provider.js +129 -0
  9. package/dist/ai/context-provider.js.map +7 -0
  10. package/dist/ai/tools.js +231 -0
  11. package/dist/ai/tools.js.map +7 -0
  12. package/dist/cli.js +224 -0
  13. package/dist/cli.js.map +7 -0
  14. package/dist/commands/add.js +51 -0
  15. package/dist/commands/add.js.map +7 -0
  16. package/dist/commands/changeset.js +174 -0
  17. package/dist/commands/changeset.js.map +7 -0
  18. package/dist/commands/chat.js +111 -0
  19. package/dist/commands/chat.js.map +7 -0
  20. package/dist/commands/conformance.js +132 -0
  21. package/dist/commands/conformance.js.map +7 -0
  22. package/dist/commands/delete.js +31 -0
  23. package/dist/commands/delete.js.map +7 -0
  24. package/dist/commands/element.js +28 -0
  25. package/dist/commands/element.js.map +7 -0
  26. package/dist/commands/export.js +65 -0
  27. package/dist/commands/export.js.map +7 -0
  28. package/dist/commands/info.js +40 -0
  29. package/dist/commands/info.js.map +7 -0
  30. package/dist/commands/init.js +45 -0
  31. package/dist/commands/init.js.map +7 -0
  32. package/dist/commands/list.js +32 -0
  33. package/dist/commands/list.js.map +7 -0
  34. package/dist/commands/migrate.js +36 -0
  35. package/dist/commands/migrate.js.map +7 -0
  36. package/dist/commands/project.js +74 -0
  37. package/dist/commands/project.js.map +7 -0
  38. package/dist/commands/relationship.js +118 -0
  39. package/dist/commands/relationship.js.map +7 -0
  40. package/dist/commands/search.js +48 -0
  41. package/dist/commands/search.js.map +7 -0
  42. package/dist/commands/show.js +38 -0
  43. package/dist/commands/show.js.map +7 -0
  44. package/dist/commands/trace.js +60 -0
  45. package/dist/commands/trace.js.map +7 -0
  46. package/dist/commands/update.js +37 -0
  47. package/dist/commands/update.js.map +7 -0
  48. package/dist/commands/upgrade.js +152 -0
  49. package/dist/commands/upgrade.js.map +7 -0
  50. package/dist/commands/validate.js +71 -0
  51. package/dist/commands/validate.js.map +7 -0
  52. package/dist/commands/version.js +20 -0
  53. package/dist/commands/version.js.map +7 -0
  54. package/dist/commands/visualize.js +51 -0
  55. package/dist/commands/visualize.js.map +7 -0
  56. package/dist/core/active-changeset.js +52 -0
  57. package/dist/core/active-changeset.js.map +7 -0
  58. package/dist/core/changeset.js +244 -0
  59. package/dist/core/changeset.js.map +7 -0
  60. package/dist/core/dependency-tracker.js +322 -0
  61. package/dist/core/dependency-tracker.js.map +7 -0
  62. package/dist/core/element.js +65 -0
  63. package/dist/core/element.js.map +7 -0
  64. package/dist/core/layer.js +75 -0
  65. package/dist/core/layer.js.map +7 -0
  66. package/dist/core/manifest.js +57 -0
  67. package/dist/core/manifest.js.map +7 -0
  68. package/dist/core/migration-registry.js +131 -0
  69. package/dist/core/migration-registry.js.map +7 -0
  70. package/dist/core/model.js +455 -0
  71. package/dist/core/model.js.map +7 -0
  72. package/dist/core/projection-engine.js +288 -0
  73. package/dist/core/projection-engine.js.map +7 -0
  74. package/dist/core/reference-registry.js +188 -0
  75. package/dist/core/reference-registry.js.map +7 -0
  76. package/dist/core/relationship-registry.js +114 -0
  77. package/dist/core/relationship-registry.js.map +7 -0
  78. package/dist/core/relationships.js +78 -0
  79. package/dist/core/relationships.js.map +7 -0
  80. package/dist/export/archimate-exporter.js +111 -0
  81. package/dist/export/archimate-exporter.js.map +7 -0
  82. package/dist/export/export-manager.js +63 -0
  83. package/dist/export/export-manager.js.map +7 -0
  84. package/dist/export/graphml-exporter.js +39 -0
  85. package/dist/export/graphml-exporter.js.map +7 -0
  86. package/dist/export/index.js +17 -0
  87. package/dist/export/index.js.map +7 -0
  88. package/dist/export/json-schema-exporter.js +60 -0
  89. package/dist/export/json-schema-exporter.js.map +7 -0
  90. package/dist/export/markdown-exporter.js +99 -0
  91. package/dist/export/markdown-exporter.js.map +7 -0
  92. package/dist/export/openapi-exporter.js +85 -0
  93. package/dist/export/openapi-exporter.js.map +7 -0
  94. package/dist/export/plantuml-exporter.js +60 -0
  95. package/dist/export/plantuml-exporter.js.map +7 -0
  96. package/dist/export/types.js +36 -0
  97. package/dist/export/types.js.map +7 -0
  98. package/dist/schemas/bundled/01-motivation-layer.schema.json +942 -0
  99. package/dist/schemas/bundled/02-business-layer.schema.json +1293 -0
  100. package/dist/schemas/bundled/03-security-layer.schema.json +2177 -0
  101. package/dist/schemas/bundled/04-application-layer.schema.json +1328 -0
  102. package/dist/schemas/bundled/05-technology-layer.schema.json +1465 -0
  103. package/dist/schemas/bundled/06-api-layer.schema.json +1743 -0
  104. package/dist/schemas/bundled/07-data-model-layer.schema.json +1253 -0
  105. package/dist/schemas/bundled/08-datastore-layer.schema.json +892 -0
  106. package/dist/schemas/bundled/09-ux-layer.schema.json +1506 -0
  107. package/dist/schemas/bundled/10-navigation-layer.schema.json +843 -0
  108. package/dist/schemas/bundled/11-apm-observability-layer.schema.json +1430 -0
  109. package/dist/schemas/bundled/12-testing-layer.schema.json +1091 -0
  110. package/dist/schemas/bundled/common/layer-extensions.schema.json +266 -0
  111. package/dist/schemas/bundled/common/predicates.schema.json +493 -0
  112. package/dist/schemas/bundled/common/relationships.schema.json +791 -0
  113. package/dist/schemas/bundled/common/source-references.schema.json +71 -0
  114. package/dist/schemas/bundled/link-registry.json +1839 -0
  115. package/dist/schemas/bundled/link-registry.schema.json +339 -0
  116. package/dist/schemas/bundled/relationship-catalog.json +1302 -0
  117. package/dist/schemas/bundled/relationship-type.schema.json +221 -0
  118. package/dist/server/server.js +1207 -0
  119. package/dist/server/server.js.map +7 -0
  120. package/dist/server/telemetry-middleware.js +24 -0
  121. package/dist/server/telemetry-middleware.js.map +7 -0
  122. package/dist/telemetry/console-interceptor.js +34 -0
  123. package/dist/telemetry/console-interceptor.js.map +7 -0
  124. package/dist/telemetry/index.js +54 -0
  125. package/dist/telemetry/index.js.map +7 -0
  126. package/dist/telemetry/resilient-exporter.js +41 -0
  127. package/dist/telemetry/resilient-exporter.js.map +7 -0
  128. package/dist/telemetry/resilient-log-exporter.js +41 -0
  129. package/dist/telemetry/resilient-log-exporter.js.map +7 -0
  130. package/dist/telemetry/test-instrumentation.js +32 -0
  131. package/dist/telemetry/test-instrumentation.js.map +7 -0
  132. package/dist/types/index.js +1 -0
  133. package/dist/types/index.js.map +7 -0
  134. package/dist/utils/element-utils.js +11 -0
  135. package/dist/utils/element-utils.js.map +7 -0
  136. package/dist/utils/errors.js +105 -0
  137. package/dist/utils/errors.js.map +7 -0
  138. package/dist/utils/file-io.js +69 -0
  139. package/dist/utils/file-io.js.map +7 -0
  140. package/dist/utils/globals.js +28 -0
  141. package/dist/utils/globals.js.map +7 -0
  142. package/dist/utils/model-path.js +22 -0
  143. package/dist/utils/model-path.js.map +7 -0
  144. package/dist/utils/project-paths.js +45 -0
  145. package/dist/utils/project-paths.js.map +7 -0
  146. package/dist/utils/spec-installer.js +85 -0
  147. package/dist/utils/spec-installer.js.map +7 -0
  148. package/dist/utils/spec-version.js +33 -0
  149. package/dist/utils/spec-version.js.map +7 -0
  150. package/dist/validators/index.js +15 -0
  151. package/dist/validators/index.js.map +7 -0
  152. package/dist/validators/naming-validator.js +82 -0
  153. package/dist/validators/naming-validator.js.map +7 -0
  154. package/dist/validators/reference-validator.js +106 -0
  155. package/dist/validators/reference-validator.js.map +7 -0
  156. package/dist/validators/schema-validator.js +148 -0
  157. package/dist/validators/schema-validator.js.map +7 -0
  158. package/dist/validators/semantic-validator.js +80 -0
  159. package/dist/validators/semantic-validator.js.map +7 -0
  160. package/dist/validators/types.js +48 -0
  161. package/dist/validators/types.js.map +7 -0
  162. package/dist/validators/validator.js +67 -0
  163. package/dist/validators/validator.js.map +7 -0
  164. package/docs/TEST-INSTRUMENTATION.md +405 -0
  165. package/docs/telemetry.md +427 -0
  166. package/package.json +70 -0
  167. package/test-debug.js +33 -0
  168. package/test-special.mjs +46 -0
  169. package/test_runner.ts +7 -0
@@ -0,0 +1,106 @@
1
+ import { ValidationResult } from "./types.js";
2
+ class ReferenceValidator {
3
+ // Layer hierarchy (lower numbers are "higher" in the architecture)
4
+ LAYER_HIERARCHY = {
5
+ motivation: 1,
6
+ business: 2,
7
+ security: 3,
8
+ application: 4,
9
+ technology: 5,
10
+ api: 6,
11
+ "data-model": 7,
12
+ "data-store": 8,
13
+ ux: 9,
14
+ navigation: 10,
15
+ apm: 11,
16
+ testing: 12
17
+ };
18
+ // Known layer names (including hyphenated ones)
19
+ KNOWN_LAYERS = [
20
+ "motivation",
21
+ "business",
22
+ "security",
23
+ "application",
24
+ "technology",
25
+ "api",
26
+ "data-model",
27
+ "data-store",
28
+ "ux",
29
+ "navigation",
30
+ "apm",
31
+ "testing"
32
+ ];
33
+ /**
34
+ * Validate all references in a model
35
+ */
36
+ validateModel(model) {
37
+ const result = new ValidationResult(), allElementIds = this.collectAllElementIds(model);
38
+ for (const [layerName, layer] of model.layers)
39
+ for (const element of layer.listElements())
40
+ this.validateReferences(element.id, element.references || [], layerName, allElementIds, result);
41
+ return result;
42
+ }
43
+ /**
44
+ * Collect all element IDs across the model
45
+ */
46
+ collectAllElementIds(model) {
47
+ const ids = /* @__PURE__ */ new Set();
48
+ for (const layer of model.layers.values())
49
+ for (const element of layer.listElements())
50
+ ids.add(element.id);
51
+ return ids;
52
+ }
53
+ /**
54
+ * Validate references for an element
55
+ */
56
+ validateReferences(elementId, references, sourceLayerName, validIds, result) {
57
+ for (const ref of references) {
58
+ if (!validIds.has(ref.target)) {
59
+ result.addError({
60
+ layer: sourceLayerName,
61
+ elementId,
62
+ message: `Broken reference: target '${ref.target}' does not exist`,
63
+ fixSuggestion: `Remove reference or create element '${ref.target}'`
64
+ });
65
+ continue;
66
+ }
67
+ const targetLayerName = this.extractLayerFromId(ref.target), sourceLevel = this.LAYER_HIERARCHY[sourceLayerName], targetLevel = this.LAYER_HIERARCHY[targetLayerName];
68
+ if (sourceLevel === void 0) {
69
+ result.addError({
70
+ layer: sourceLayerName,
71
+ elementId,
72
+ message: `Unknown source layer: ${sourceLayerName}`
73
+ });
74
+ continue;
75
+ }
76
+ if (targetLevel === void 0) {
77
+ result.addError({
78
+ layer: sourceLayerName,
79
+ elementId,
80
+ message: `Target element '${ref.target}' has unknown layer: ${targetLayerName}`
81
+ });
82
+ continue;
83
+ }
84
+ sourceLevel > targetLevel && result.addError({
85
+ layer: sourceLayerName,
86
+ elementId,
87
+ message: `Invalid reference direction: ${sourceLayerName} (level ${sourceLevel}) cannot reference ${targetLayerName} (level ${targetLevel})`,
88
+ fixSuggestion: "References must go from higher layers to lower layers (motivation \u2192 testing)"
89
+ });
90
+ }
91
+ }
92
+ /**
93
+ * Extract layer name from element ID, handling hyphenated layer names
94
+ */
95
+ extractLayerFromId(elementId) {
96
+ const sortedLayers = [...this.KNOWN_LAYERS].sort((a, b) => b.length - a.length);
97
+ for (const layer of sortedLayers)
98
+ if (elementId.startsWith(layer + "-"))
99
+ return layer;
100
+ return elementId.split("-")[0] || "";
101
+ }
102
+ }
103
+ export {
104
+ ReferenceValidator
105
+ };
106
+ //# sourceMappingURL=reference-validator.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/validators/reference-validator.ts"],
4
+ "sourcesContent": ["/**\n * Reference validation for cross-layer integrity\n */\n\nimport { ValidationResult } from './types.js';\nimport type { Model } from '../core/model.js';\n\n/**\n * Validator for cross-layer references\n */\nexport class ReferenceValidator {\n // Layer hierarchy (lower numbers are \"higher\" in the architecture)\n private readonly LAYER_HIERARCHY: Record<string, number> = {\n motivation: 1,\n business: 2,\n security: 3,\n application: 4,\n technology: 5,\n api: 6,\n 'data-model': 7,\n 'data-store': 8,\n ux: 9,\n navigation: 10,\n apm: 11,\n testing: 12,\n };\n\n // Known layer names (including hyphenated ones)\n private readonly KNOWN_LAYERS = [\n 'motivation',\n 'business',\n 'security',\n 'application',\n 'technology',\n 'api',\n 'data-model',\n 'data-store',\n 'ux',\n 'navigation',\n 'apm',\n 'testing',\n ];\n\n /**\n * Validate all references in a model\n */\n validateModel(model: Model): ValidationResult {\n const result = new ValidationResult();\n const allElementIds = this.collectAllElementIds(model);\n\n for (const [layerName, layer] of model.layers) {\n for (const element of layer.listElements()) {\n this.validateReferences(\n element.id,\n element.references || [],\n layerName,\n allElementIds,\n result\n );\n }\n }\n\n return result;\n }\n\n /**\n * Collect all element IDs across the model\n */\n private collectAllElementIds(model: Model): Set<string> {\n const ids = new Set<string>();\n\n for (const layer of model.layers.values()) {\n for (const element of layer.listElements()) {\n ids.add(element.id);\n }\n }\n\n return ids;\n }\n\n /**\n * Validate references for an element\n */\n private validateReferences(\n elementId: string,\n references: Array<{ target: string; type?: string }>,\n sourceLayerName: string,\n validIds: Set<string>,\n result: ValidationResult\n ): void {\n for (const ref of references) {\n // Check target exists\n if (!validIds.has(ref.target)) {\n result.addError({\n layer: sourceLayerName,\n elementId,\n message: `Broken reference: target '${ref.target}' does not exist`,\n fixSuggestion: `Remove reference or create element '${ref.target}'`,\n });\n continue;\n }\n\n // Check directional constraint (higher \u2192 lower only)\n const targetLayerName = this.extractLayerFromId(ref.target);\n const sourceLevel = this.LAYER_HIERARCHY[sourceLayerName];\n const targetLevel = this.LAYER_HIERARCHY[targetLayerName];\n\n if (sourceLevel === undefined) {\n result.addError({\n layer: sourceLayerName,\n elementId,\n message: `Unknown source layer: ${sourceLayerName}`,\n });\n continue;\n }\n\n if (targetLevel === undefined) {\n result.addError({\n layer: sourceLayerName,\n elementId,\n message: `Target element '${ref.target}' has unknown layer: ${targetLayerName}`,\n });\n continue;\n }\n\n // References must go from higher layers (lower numbers) to lower layers (higher numbers)\n // or within the same layer\n if (sourceLevel > targetLevel) {\n result.addError({\n layer: sourceLayerName,\n elementId,\n message: `Invalid reference direction: ${sourceLayerName} (level ${sourceLevel}) cannot reference ${targetLayerName} (level ${targetLevel})`,\n fixSuggestion:\n 'References must go from higher layers to lower layers (motivation \u2192 testing)',\n });\n }\n }\n }\n\n /**\n * Extract layer name from element ID, handling hyphenated layer names\n */\n private extractLayerFromId(elementId: string): string {\n // Try to match known layers in order of specificity (longest first)\n const sortedLayers = [...this.KNOWN_LAYERS].sort((a, b) => b.length - a.length);\n\n for (const layer of sortedLayers) {\n if (elementId.startsWith(layer + '-')) {\n return layer;\n }\n }\n\n // Fallback: return first segment (shouldn't reach here with valid element IDs)\n return elementId.split('-')[0] || '';\n }\n}\n"],
5
+ "mappings": "AAIA,SAAS,wBAAwB;AAM3B,MAAO,mBAAkB;;EAEZ,kBAA0C;IACzD,YAAY;IACZ,UAAU;IACV,UAAU;IACV,aAAa;IACb,YAAY;IACZ,KAAK;IACL,cAAc;IACd,cAAc;IACd,IAAI;IACJ,YAAY;IACZ,KAAK;IACL,SAAS;;;EAIM,eAAe;IAC9B;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;;;;;EAMF,cAAc,OAAY;AACxB,UAAM,SAAS,IAAI,iBAAgB,GAC7B,gBAAgB,KAAK,qBAAqB,KAAK;AAErD,eAAW,CAAC,WAAW,KAAK,KAAK,MAAM;AACrC,iBAAW,WAAW,MAAM,aAAY;AACtC,aAAK,mBACH,QAAQ,IACR,QAAQ,cAAc,CAAA,GACtB,WACA,eACA,MAAM;AAKZ,WAAO;EACT;;;;EAKQ,qBAAqB,OAAY;AACvC,UAAM,MAAM,oBAAI,IAAG;AAEnB,eAAW,SAAS,MAAM,OAAO,OAAM;AACrC,iBAAW,WAAW,MAAM,aAAY;AACtC,YAAI,IAAI,QAAQ,EAAE;AAItB,WAAO;EACT;;;;EAKQ,mBACN,WACA,YACA,iBACA,UACA,QAAwB;AAExB,eAAW,OAAO,YAAY;AAE5B,UAAI,CAAC,SAAS,IAAI,IAAI,MAAM,GAAG;AAC7B,eAAO,SAAS;UACd,OAAO;UACP;UACA,SAAS,6BAA6B,IAAI,MAAM;UAChD,eAAe,uCAAuC,IAAI,MAAM;SACjE;AACD;MACF;AAGA,YAAM,kBAAkB,KAAK,mBAAmB,IAAI,MAAM,GACpD,cAAc,KAAK,gBAAgB,eAAe,GAClD,cAAc,KAAK,gBAAgB,eAAe;AAExD,UAAI,gBAAgB,QAAW;AAC7B,eAAO,SAAS;UACd,OAAO;UACP;UACA,SAAS,yBAAyB,eAAe;SAClD;AACD;MACF;AAEA,UAAI,gBAAgB,QAAW;AAC7B,eAAO,SAAS;UACd,OAAO;UACP;UACA,SAAS,mBAAmB,IAAI,MAAM,wBAAwB,eAAe;SAC9E;AACD;MACF;AAIA,MAAI,cAAc,eAChB,OAAO,SAAS;QACd,OAAO;QACP;QACA,SAAS,gCAAgC,eAAe,WAAW,WAAW,sBAAsB,eAAe,WAAW,WAAW;QACzI,eACE;OACH;IAEL;EACF;;;;EAKQ,mBAAmB,WAAiB;AAE1C,UAAM,eAAe,CAAC,GAAG,KAAK,YAAY,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,SAAS,EAAE,MAAM;AAE9E,eAAW,SAAS;AAClB,UAAI,UAAU,WAAW,QAAQ,GAAG;AAClC,eAAO;AAKX,WAAO,UAAU,MAAM,GAAG,EAAE,CAAC,KAAK;EACpC;;",
6
+ "names": []
7
+ }
@@ -0,0 +1,148 @@
1
+ import Ajv from "ajv";
2
+ import addFormats from "ajv-formats";
3
+ import { ValidationResult } from "./types.js";
4
+ import { fileURLToPath } from "url";
5
+ import path from "path";
6
+ import { readFile } from "../utils/file-io.js";
7
+ import { startSpan, endSpan } from "../telemetry/index.js";
8
+ const isTelemetryEnabled = !1;
9
+ class SchemaValidator {
10
+ ajv;
11
+ compiledSchemas = /* @__PURE__ */ new Map();
12
+ schemasLoaded = !1;
13
+ constructor() {
14
+ this.ajv = new Ajv({
15
+ allErrors: !0,
16
+ strict: !1,
17
+ validateFormats: !0
18
+ }), addFormats(this.ajv);
19
+ }
20
+ /**
21
+ * Ensure schemas are precompiled before validation
22
+ */
23
+ async ensureSchemasLoaded() {
24
+ this.schemasLoaded || (await this.precompileSchemas(), this.schemasLoaded = !0);
25
+ }
26
+ /**
27
+ * Precompile all layer schemas for efficient validation
28
+ */
29
+ async precompileSchemas() {
30
+ const layerMappings = {
31
+ motivation: "01-motivation-layer.schema.json",
32
+ business: "02-business-layer.schema.json",
33
+ security: "03-security-layer.schema.json",
34
+ application: "04-application-layer.schema.json",
35
+ technology: "05-technology-layer.schema.json",
36
+ api: "06-api-layer.schema.json",
37
+ "data-model": "07-data-model-layer.schema.json",
38
+ "data-store": "08-datastore-layer.schema.json",
39
+ ux: "09-ux-layer.schema.json",
40
+ navigation: "10-navigation-layer.schema.json",
41
+ apm: "11-apm-observability-layer.schema.json",
42
+ testing: "12-testing-layer.schema.json"
43
+ }, __dirname = path.dirname(fileURLToPath(import.meta.url)), schemasDir = path.join(__dirname, "..", "schemas", "bundled"), commonSchemas = [
44
+ "common/source-references.schema.json",
45
+ "common/predicates.schema.json",
46
+ "common/relationships.schema.json",
47
+ "common/layer-extensions.schema.json"
48
+ ];
49
+ for (const commonSchemaFile of commonSchemas)
50
+ try {
51
+ const schemaPath = path.join(schemasDir, commonSchemaFile), schemaContent = await readFile(schemaPath), schema = JSON.parse(schemaContent);
52
+ this.ajv.addSchema(schema);
53
+ } catch (error) {
54
+ console.warn(`Warning: Failed to load common schema ${commonSchemaFile}:`, error);
55
+ }
56
+ for (const [layerName, schemaFileName] of Object.entries(layerMappings))
57
+ try {
58
+ let schemaPath = path.join(schemasDir, schemaFileName), schemaContent;
59
+ try {
60
+ schemaContent = await readFile(schemaPath);
61
+ } catch {
62
+ schemaPath = path.join(__dirname, "schemas", "bundled", schemaFileName), schemaContent = await readFile(schemaPath);
63
+ }
64
+ const schema = JSON.parse(schemaContent), validate = this.ajv.compile(schema);
65
+ this.compiledSchemas.set(layerName, validate);
66
+ } catch (error) {
67
+ console.warn(`Failed to load schema for layer ${layerName}:`, error);
68
+ }
69
+ }
70
+ /**
71
+ * Validate a layer against its schema
72
+ */
73
+ async validateLayer(layer) {
74
+ const span = isTelemetryEnabled ? startSpan("schema.validate", {
75
+ "schema.layer": layer.name
76
+ }) : null;
77
+ try {
78
+ const result = new ValidationResult();
79
+ await this.ensureSchemasLoaded();
80
+ const validate = this.compiledSchemas.get(layer.name);
81
+ if (!validate)
82
+ return isTelemetryEnabled && span && (span.setAttribute("schema.valid", !0), span.setAttribute("schema.skipped", !0)), result;
83
+ const layerData = layer.toJSON(), valid = validate(layerData);
84
+ if (!valid && validate.errors)
85
+ for (const error of validate.errors)
86
+ result.addError({
87
+ layer: layer.name,
88
+ message: `Schema validation failed: ${this.formatAjvError(error)}`,
89
+ location: error.instancePath || "/",
90
+ fixSuggestion: this.generateFixSuggestion(error)
91
+ });
92
+ return isTelemetryEnabled && span && (span.setAttribute("schema.valid", valid), span.setAttribute("schema.error_count", validate.errors?.length || 0)), result;
93
+ } finally {
94
+ endSpan(span);
95
+ }
96
+ }
97
+ /**
98
+ * Format AJV error message
99
+ */
100
+ formatAjvError(error) {
101
+ const keyword = error.keyword, dataPath = error.instancePath || "/";
102
+ switch (keyword) {
103
+ case "type":
104
+ return `At ${dataPath}: expected ${error.params?.type}, got ${typeof error.data}`;
105
+ case "required":
106
+ return `At ${dataPath}: missing required property '${error.params?.missingProperty}'`;
107
+ case "enum":
108
+ return `At ${dataPath}: value must be one of [${error.params?.allowedValues?.join(", ")}]`;
109
+ case "pattern":
110
+ return `At ${dataPath}: value must match pattern ${error.params?.pattern}`;
111
+ case "minLength":
112
+ return `At ${dataPath}: string must be at least ${error.params?.limit} characters`;
113
+ case "maxLength":
114
+ return `At ${dataPath}: string must be at most ${error.params?.limit} characters`;
115
+ case "minimum":
116
+ return `At ${dataPath}: value must be >= ${error.params?.limit}`;
117
+ case "maximum":
118
+ return `At ${dataPath}: value must be <= ${error.params?.limit}`;
119
+ case "additionalProperties":
120
+ return `At ${dataPath}: unexpected property '${error.params?.additionalProperty}'`;
121
+ default:
122
+ return error.message || "Validation failed";
123
+ }
124
+ }
125
+ /**
126
+ * Generate a fix suggestion based on the error
127
+ */
128
+ generateFixSuggestion(error) {
129
+ switch (error.keyword) {
130
+ case "required":
131
+ return `Add required field: ${error.params?.missingProperty}`;
132
+ case "type":
133
+ return `Expected type ${error.params?.type}`;
134
+ case "enum":
135
+ return `Use one of: ${error.params?.allowedValues?.join(", ")}`;
136
+ case "pattern":
137
+ return `Value must match pattern: ${error.params?.pattern}`;
138
+ case "additionalProperties":
139
+ return `Remove unexpected property: ${error.params?.additionalProperty}`;
140
+ default:
141
+ return;
142
+ }
143
+ }
144
+ }
145
+ export {
146
+ SchemaValidator
147
+ };
148
+ //# sourceMappingURL=schema-validator.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/validators/schema-validator.ts"],
4
+ "sourcesContent": ["/**\n * Schema validation using AJV\n */\n\nimport Ajv, { ValidateFunction, ErrorObject } from 'ajv';\nimport addFormats from 'ajv-formats';\nimport { ValidationResult } from './types.js';\nimport type { Layer } from '../core/layer.js';\nimport { fileURLToPath } from 'url';\nimport path from 'path';\nimport { readFile } from '../utils/file-io.js';\nimport { startSpan, endSpan } from '../telemetry/index.js';\n\n// Fallback for runtime environments where TELEMETRY_ENABLED is not defined by esbuild\ndeclare const TELEMETRY_ENABLED: boolean | undefined;\nconst isTelemetryEnabled = typeof TELEMETRY_ENABLED !== 'undefined' ? TELEMETRY_ENABLED : false;\n\n/**\n * Validator for JSON Schema compliance\n */\nexport class SchemaValidator {\n private ajv: Ajv;\n private compiledSchemas: Map<string, ValidateFunction> = new Map();\n private schemasLoaded: boolean = false;\n\n constructor() {\n this.ajv = new Ajv({\n allErrors: true,\n strict: false,\n validateFormats: true,\n });\n addFormats(this.ajv);\n // Note: schemas are loaded lazily on first validation\n }\n\n /**\n * Ensure schemas are precompiled before validation\n */\n private async ensureSchemasLoaded(): Promise<void> {\n if (this.schemasLoaded) {\n return;\n }\n\n await this.precompileSchemas();\n this.schemasLoaded = true;\n }\n\n /**\n * Precompile all layer schemas for efficient validation\n */\n private async precompileSchemas(): Promise<void> {\n const layerMappings = {\n motivation: '01-motivation-layer.schema.json',\n business: '02-business-layer.schema.json',\n security: '03-security-layer.schema.json',\n application: '04-application-layer.schema.json',\n technology: '05-technology-layer.schema.json',\n api: '06-api-layer.schema.json',\n 'data-model': '07-data-model-layer.schema.json',\n 'data-store': '08-datastore-layer.schema.json',\n ux: '09-ux-layer.schema.json',\n navigation: '10-navigation-layer.schema.json',\n apm: '11-apm-observability-layer.schema.json',\n testing: '12-testing-layer.schema.json',\n };\n\n const __dirname = path.dirname(fileURLToPath(import.meta.url));\n const schemasDir = path.join(__dirname, '..', 'schemas', 'bundled');\n\n // First, register all common schemas that other schemas reference\n const commonSchemas = [\n 'common/source-references.schema.json',\n 'common/predicates.schema.json',\n 'common/relationships.schema.json',\n 'common/layer-extensions.schema.json',\n ];\n\n for (const commonSchemaFile of commonSchemas) {\n try {\n const schemaPath = path.join(schemasDir, commonSchemaFile);\n const schemaContent = await readFile(schemaPath);\n const schema = JSON.parse(schemaContent);\n this.ajv.addSchema(schema);\n } catch (error) {\n // Common schemas not all layers may reference - warn but continue\n console.warn(\n `Warning: Failed to load common schema ${commonSchemaFile}:`,\n error\n );\n }\n }\n\n for (const [layerName, schemaFileName] of Object.entries(layerMappings)) {\n try {\n // Try primary schema path first (development)\n let schemaPath = path.join(schemasDir, schemaFileName);\n\n let schemaContent: string;\n try {\n schemaContent = await readFile(schemaPath);\n } catch {\n // Fallback to alternative path for bundled deployments\n schemaPath = path.join(\n __dirname,\n 'schemas',\n 'bundled',\n schemaFileName\n );\n schemaContent = await readFile(schemaPath);\n }\n\n const schema = JSON.parse(schemaContent);\n const validate = this.ajv.compile(schema);\n this.compiledSchemas.set(layerName, validate);\n } catch (error) {\n console.warn(`Failed to load schema for layer ${layerName}:`, error);\n }\n }\n }\n\n /**\n * Validate a layer against its schema\n */\n async validateLayer(layer: Layer): Promise<ValidationResult> {\n const span = isTelemetryEnabled ? startSpan('schema.validate', {\n 'schema.layer': layer.name,\n }) : null;\n\n try {\n const result = new ValidationResult();\n\n // Ensure schemas are loaded\n await this.ensureSchemasLoaded();\n\n const validate = this.compiledSchemas.get(layer.name);\n\n if (!validate) {\n // Schema not found - skip validation silently (matching Python CLI behavior)\n // Some layers may not have schemas yet, which is acceptable\n // Don't add warning - just return success\n if (isTelemetryEnabled && span) {\n span.setAttribute('schema.valid', true);\n span.setAttribute('schema.skipped', true);\n }\n\n return result;\n }\n\n const layerData = layer.toJSON();\n const valid = validate(layerData);\n\n if (!valid && validate.errors) {\n for (const error of validate.errors) {\n result.addError({\n layer: layer.name,\n message: `Schema validation failed: ${this.formatAjvError(error)}`,\n location: error.instancePath || '/',\n fixSuggestion: this.generateFixSuggestion(error),\n });\n }\n }\n\n if (isTelemetryEnabled && span) {\n span.setAttribute('schema.valid', valid);\n span.setAttribute('schema.error_count', validate.errors?.length || 0);\n }\n\n return result;\n } finally {\n endSpan(span);\n }\n }\n\n /**\n * Format AJV error message\n */\n private formatAjvError(error: ErrorObject): string {\n const keyword = error.keyword;\n const dataPath = error.instancePath || '/';\n\n switch (keyword) {\n case 'type':\n return `At ${dataPath}: expected ${error.params?.type}, got ${typeof error.data}`;\n case 'required':\n return `At ${dataPath}: missing required property '${error.params?.missingProperty}'`;\n case 'enum':\n return `At ${dataPath}: value must be one of [${error.params?.allowedValues?.join(', ')}]`;\n case 'pattern':\n return `At ${dataPath}: value must match pattern ${error.params?.pattern}`;\n case 'minLength':\n return `At ${dataPath}: string must be at least ${error.params?.limit} characters`;\n case 'maxLength':\n return `At ${dataPath}: string must be at most ${error.params?.limit} characters`;\n case 'minimum':\n return `At ${dataPath}: value must be >= ${error.params?.limit}`;\n case 'maximum':\n return `At ${dataPath}: value must be <= ${error.params?.limit}`;\n case 'additionalProperties':\n return `At ${dataPath}: unexpected property '${error.params?.additionalProperty}'`;\n default:\n return error.message || `Validation failed`;\n }\n }\n\n /**\n * Generate a fix suggestion based on the error\n */\n private generateFixSuggestion(error: ErrorObject): string | undefined {\n const keyword = error.keyword;\n\n switch (keyword) {\n case 'required':\n return `Add required field: ${error.params?.missingProperty}`;\n case 'type':\n return `Expected type ${error.params?.type}`;\n case 'enum':\n return `Use one of: ${error.params?.allowedValues?.join(', ')}`;\n case 'pattern':\n return `Value must match pattern: ${error.params?.pattern}`;\n case 'additionalProperties':\n return `Remove unexpected property: ${error.params?.additionalProperty}`;\n default:\n return undefined;\n }\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,80 @@
1
+ import { ValidationResult } from "./types.js";
2
+ import { fileURLToPath } from "url";
3
+ import path from "path";
4
+ class SemanticValidator {
5
+ relationshipCatalog = null;
6
+ catalogLoaded = !1;
7
+ constructor() {
8
+ }
9
+ /**
10
+ * Ensure relationship catalog is loaded
11
+ */
12
+ async ensureCatalogLoaded() {
13
+ this.catalogLoaded || (await this.loadRelationshipCatalog(), this.catalogLoaded = !0);
14
+ }
15
+ /**
16
+ * Load the relationship catalog for predicate validation
17
+ */
18
+ async loadRelationshipCatalog() {
19
+ try {
20
+ const __dirname = path.dirname(fileURLToPath(import.meta.url)), catalogPath = path.join(__dirname, "..", "schemas", "bundled", "relationship-catalog.json");
21
+ this.relationshipCatalog = await import(catalogPath, { assert: { type: "json" } }).then((m) => m.default);
22
+ } catch {
23
+ this.relationshipCatalog = null;
24
+ }
25
+ }
26
+ /**
27
+ * Validate semantic constraints of a model
28
+ */
29
+ async validateModel(model) {
30
+ const result = new ValidationResult();
31
+ return await this.ensureCatalogLoaded(), this.validateUniqueIds(model, result), this.validateRelationshipPredicates(model, result), result;
32
+ }
33
+ /**
34
+ * Validate that all element IDs are unique across layers
35
+ */
36
+ validateUniqueIds(model, result) {
37
+ const seenIds = /* @__PURE__ */ new Map();
38
+ for (const [layerName, layer] of model.layers)
39
+ for (const element of layer.listElements())
40
+ seenIds.has(element.id) ? result.addError({
41
+ layer: layerName,
42
+ elementId: element.id,
43
+ message: `Duplicate element ID: '${element.id}' already exists in layer '${seenIds.get(element.id)}'`,
44
+ fixSuggestion: "Element IDs must be unique across all layers"
45
+ }) : seenIds.set(element.id, layerName);
46
+ }
47
+ /**
48
+ * Validate relationship predicates against the catalog
49
+ */
50
+ validateRelationshipPredicates(model, result) {
51
+ if (this.relationshipCatalog)
52
+ for (const [layerName, layer] of model.layers) {
53
+ const allowedPredicates = this.getAllowedPredicates(layerName);
54
+ for (const element of layer.listElements())
55
+ for (const rel of element.relationships || [])
56
+ allowedPredicates.includes(rel.predicate) || result.addWarning({
57
+ layer: layerName,
58
+ elementId: element.id,
59
+ message: `Unknown relationship predicate '${rel.predicate}' for layer ${layerName}`,
60
+ fixSuggestion: allowedPredicates.length > 0 ? `Use one of: ${allowedPredicates.join(", ")}` : "Check relationship catalog for valid predicates"
61
+ });
62
+ }
63
+ }
64
+ /**
65
+ * Get allowed predicates for a layer from the catalog
66
+ */
67
+ getAllowedPredicates(layerName) {
68
+ if (!this.relationshipCatalog)
69
+ return [];
70
+ const layerCatalog = this.relationshipCatalog.layers?.[layerName];
71
+ if (!layerCatalog)
72
+ return [];
73
+ const predicates = layerCatalog.predicates || layerCatalog.relationships || [];
74
+ return Array.isArray(predicates) ? predicates : Object.keys(predicates || {});
75
+ }
76
+ }
77
+ export {
78
+ SemanticValidator
79
+ };
80
+ //# sourceMappingURL=semantic-validator.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/validators/semantic-validator.ts"],
4
+ "sourcesContent": ["/**\n * Semantic validation for business rules\n */\n\nimport { ValidationResult } from './types.js';\nimport type { Model } from '../core/model.js';\nimport { fileURLToPath } from 'url';\nimport path from 'path';\n\n/**\n * Validator for semantic/business rule validation\n */\nexport class SemanticValidator {\n private relationshipCatalog: Record<string, any> | null = null;\n private catalogLoaded: boolean = false;\n\n constructor() {\n // Load catalog asynchronously on first use\n }\n\n /**\n * Ensure relationship catalog is loaded\n */\n private async ensureCatalogLoaded(): Promise<void> {\n if (this.catalogLoaded) {\n return;\n }\n\n await this.loadRelationshipCatalog();\n this.catalogLoaded = true;\n }\n\n /**\n * Load the relationship catalog for predicate validation\n */\n private async loadRelationshipCatalog(): Promise<void> {\n try {\n const __dirname = path.dirname(fileURLToPath(import.meta.url));\n const catalogPath = path.join(__dirname, '..', 'schemas', 'bundled', 'relationship-catalog.json');\n this.relationshipCatalog = await import(catalogPath, { assert: { type: 'json' } }).then(\n (m) => m.default\n );\n } catch {\n // Catalog load failure is gracefully handled - validation continues without predicate checking\n this.relationshipCatalog = null;\n }\n }\n\n /**\n * Validate semantic constraints of a model\n */\n async validateModel(model: Model): Promise<ValidationResult> {\n const result = new ValidationResult();\n\n await this.ensureCatalogLoaded();\n\n this.validateUniqueIds(model, result);\n this.validateRelationshipPredicates(model, result);\n\n return result;\n }\n\n /**\n * Validate that all element IDs are unique across layers\n */\n private validateUniqueIds(model: Model, result: ValidationResult): void {\n const seenIds = new Map<string, string>(); // id -> layer name\n\n for (const [layerName, layer] of model.layers) {\n for (const element of layer.listElements()) {\n if (seenIds.has(element.id)) {\n result.addError({\n layer: layerName,\n elementId: element.id,\n message: `Duplicate element ID: '${element.id}' already exists in layer '${seenIds.get(element.id)}'`,\n fixSuggestion: 'Element IDs must be unique across all layers',\n });\n } else {\n seenIds.set(element.id, layerName);\n }\n }\n }\n }\n\n /**\n * Validate relationship predicates against the catalog\n */\n private validateRelationshipPredicates(model: Model, result: ValidationResult): void {\n if (!this.relationshipCatalog) {\n // If we can't load the catalog, we can't validate predicates\n return;\n }\n\n for (const [layerName, layer] of model.layers) {\n const allowedPredicates = this.getAllowedPredicates(layerName);\n\n for (const element of layer.listElements()) {\n for (const rel of element.relationships || []) {\n if (!allowedPredicates.includes(rel.predicate)) {\n result.addWarning({\n layer: layerName,\n elementId: element.id,\n message: `Unknown relationship predicate '${rel.predicate}' for layer ${layerName}`,\n fixSuggestion:\n allowedPredicates.length > 0\n ? `Use one of: ${allowedPredicates.join(', ')}`\n : 'Check relationship catalog for valid predicates',\n });\n }\n }\n }\n }\n }\n\n /**\n * Get allowed predicates for a layer from the catalog\n */\n private getAllowedPredicates(layerName: string): string[] {\n if (!this.relationshipCatalog) {\n return [];\n }\n\n const layerCatalog = this.relationshipCatalog.layers?.[layerName];\n if (!layerCatalog) {\n return [];\n }\n\n const predicates = layerCatalog.predicates || layerCatalog.relationships || [];\n return Array.isArray(predicates) ? predicates : Object.keys(predicates || {});\n }\n}\n"],
5
+ "mappings": "AAIA,SAAS,wBAAwB;AAEjC,SAAS,qBAAqB;AAC9B,OAAO,UAAU;AAKX,MAAO,kBAAiB;EACpB,sBAAkD;EAClD,gBAAyB;EAEjC,cAAA;EAEA;;;;EAKQ,MAAM,sBAAmB;AAC/B,IAAI,KAAK,kBAIT,MAAM,KAAK,wBAAuB,GAClC,KAAK,gBAAgB;EACvB;;;;EAKQ,MAAM,0BAAuB;AACnC,QAAI;AACF,YAAM,YAAY,KAAK,QAAQ,cAAc,YAAY,GAAG,CAAC,GACvD,cAAc,KAAK,KAAK,WAAW,MAAM,WAAW,WAAW,2BAA2B;AAChG,WAAK,sBAAsB,MAAM,OAAO,aAAa,EAAE,QAAQ,EAAE,MAAM,OAAM,EAAE,GAAI,KACjF,CAAC,MAAM,EAAE,OAAO;IAEpB,QAAQ;AAEN,WAAK,sBAAsB;IAC7B;EACF;;;;EAKA,MAAM,cAAc,OAAY;AAC9B,UAAM,SAAS,IAAI,iBAAgB;AAEnC,iBAAM,KAAK,oBAAmB,GAE9B,KAAK,kBAAkB,OAAO,MAAM,GACpC,KAAK,+BAA+B,OAAO,MAAM,GAE1C;EACT;;;;EAKQ,kBAAkB,OAAc,QAAwB;AAC9D,UAAM,UAAU,oBAAI,IAAG;AAEvB,eAAW,CAAC,WAAW,KAAK,KAAK,MAAM;AACrC,iBAAW,WAAW,MAAM,aAAY;AACtC,QAAI,QAAQ,IAAI,QAAQ,EAAE,IACxB,OAAO,SAAS;UACd,OAAO;UACP,WAAW,QAAQ;UACnB,SAAS,0BAA0B,QAAQ,EAAE,8BAA8B,QAAQ,IAAI,QAAQ,EAAE,CAAC;UAClG,eAAe;SAChB,IAED,QAAQ,IAAI,QAAQ,IAAI,SAAS;EAIzC;;;;EAKQ,+BAA+B,OAAc,QAAwB;AAC3E,QAAK,KAAK;AAKV,iBAAW,CAAC,WAAW,KAAK,KAAK,MAAM,QAAQ;AAC7C,cAAM,oBAAoB,KAAK,qBAAqB,SAAS;AAE7D,mBAAW,WAAW,MAAM,aAAY;AACtC,qBAAW,OAAO,QAAQ,iBAAiB,CAAA;AACzC,YAAK,kBAAkB,SAAS,IAAI,SAAS,KAC3C,OAAO,WAAW;cAChB,OAAO;cACP,WAAW,QAAQ;cACnB,SAAS,mCAAmC,IAAI,SAAS,eAAe,SAAS;cACjF,eACE,kBAAkB,SAAS,IACvB,eAAe,kBAAkB,KAAK,IAAI,CAAC,KAC3C;aACP;MAIT;EACF;;;;EAKQ,qBAAqB,WAAiB;AAC5C,QAAI,CAAC,KAAK;AACR,aAAO,CAAA;AAGT,UAAM,eAAe,KAAK,oBAAoB,SAAS,SAAS;AAChE,QAAI,CAAC;AACH,aAAO,CAAA;AAGT,UAAM,aAAa,aAAa,cAAc,aAAa,iBAAiB,CAAA;AAC5E,WAAO,MAAM,QAAQ,UAAU,IAAI,aAAa,OAAO,KAAK,cAAc,CAAA,CAAE;EAC9E;;",
6
+ "names": []
7
+ }
@@ -0,0 +1,48 @@
1
+ class ValidationResult {
2
+ errors = [];
3
+ warnings = [];
4
+ /**
5
+ * Check if validation passed (no errors)
6
+ */
7
+ isValid() {
8
+ return this.errors.length === 0;
9
+ }
10
+ /**
11
+ * Add an error to the result
12
+ */
13
+ addError(issue) {
14
+ this.errors.push({ ...issue, severity: "error" });
15
+ }
16
+ /**
17
+ * Add a warning to the result
18
+ */
19
+ addWarning(issue) {
20
+ this.warnings.push({ ...issue, severity: "warning" });
21
+ }
22
+ /**
23
+ * Merge another validation result into this one
24
+ */
25
+ merge(other, prefix) {
26
+ const addPrefix = (issue) => ({
27
+ ...issue,
28
+ message: prefix ? `${prefix}: ${issue.message}` : issue.message
29
+ });
30
+ this.errors.push(...other.errors.map(addPrefix)), this.warnings.push(...other.warnings.map(addPrefix));
31
+ }
32
+ /**
33
+ * Convert to dictionary representation
34
+ */
35
+ toDict() {
36
+ return {
37
+ valid: this.isValid(),
38
+ errors: this.errors,
39
+ warnings: this.warnings,
40
+ errorCount: this.errors.length,
41
+ warningCount: this.warnings.length
42
+ };
43
+ }
44
+ }
45
+ export {
46
+ ValidationResult
47
+ };
48
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/validators/types.ts"],
4
+ "sourcesContent": ["/**\n * Validation result types and classes\n */\n\n/**\n * A single validation issue\n */\nexport interface ValidationIssue {\n layer: string;\n elementId?: string;\n message: string;\n severity: 'error' | 'warning';\n location?: string;\n fixSuggestion?: string;\n}\n\n/**\n * Result of a validation operation\n */\nexport class ValidationResult {\n errors: ValidationIssue[] = [];\n warnings: ValidationIssue[] = [];\n\n /**\n * Check if validation passed (no errors)\n */\n isValid(): boolean {\n return this.errors.length === 0;\n }\n\n /**\n * Add an error to the result\n */\n addError(issue: Omit<ValidationIssue, 'severity'>): void {\n this.errors.push({ ...issue, severity: 'error' });\n }\n\n /**\n * Add a warning to the result\n */\n addWarning(issue: Omit<ValidationIssue, 'severity'>): void {\n this.warnings.push({ ...issue, severity: 'warning' });\n }\n\n /**\n * Merge another validation result into this one\n */\n merge(other: ValidationResult, prefix?: string): void {\n const addPrefix = (issue: ValidationIssue): ValidationIssue => ({\n ...issue,\n message: prefix ? `${prefix}: ${issue.message}` : issue.message,\n });\n\n this.errors.push(...other.errors.map(addPrefix));\n this.warnings.push(...other.warnings.map(addPrefix));\n }\n\n /**\n * Convert to dictionary representation\n */\n toDict(): Record<string, unknown> {\n return {\n valid: this.isValid(),\n errors: this.errors,\n warnings: this.warnings,\n errorCount: this.errors.length,\n warningCount: this.warnings.length,\n };\n }\n}\n"],
5
+ "mappings": "AAmBM,MAAO,iBAAgB;EAC3B,SAA4B,CAAA;EAC5B,WAA8B,CAAA;;;;EAK9B,UAAO;AACL,WAAO,KAAK,OAAO,WAAW;EAChC;;;;EAKA,SAAS,OAAwC;AAC/C,SAAK,OAAO,KAAK,EAAE,GAAG,OAAO,UAAU,QAAO,CAAE;EAClD;;;;EAKA,WAAW,OAAwC;AACjD,SAAK,SAAS,KAAK,EAAE,GAAG,OAAO,UAAU,UAAS,CAAE;EACtD;;;;EAKA,MAAM,OAAyB,QAAe;AAC5C,UAAM,YAAY,CAAC,WAA6C;MAC9D,GAAG;MACH,SAAS,SAAS,GAAG,MAAM,KAAK,MAAM,OAAO,KAAK,MAAM;;AAG1D,SAAK,OAAO,KAAK,GAAG,MAAM,OAAO,IAAI,SAAS,CAAC,GAC/C,KAAK,SAAS,KAAK,GAAG,MAAM,SAAS,IAAI,SAAS,CAAC;EACrD;;;;EAKA,SAAM;AACJ,WAAO;MACL,OAAO,KAAK,QAAO;MACnB,QAAQ,KAAK;MACb,UAAU,KAAK;MACf,YAAY,KAAK,OAAO;MACxB,cAAc,KAAK,SAAS;;EAEhC;;",
6
+ "names": []
7
+ }
@@ -0,0 +1,67 @@
1
+ import { ValidationResult } from "./types.js";
2
+ import { SchemaValidator } from "./schema-validator.js";
3
+ import { NamingValidator } from "./naming-validator.js";
4
+ import { ReferenceValidator } from "./reference-validator.js";
5
+ import { SemanticValidator } from "./semantic-validator.js";
6
+ import { startSpan, endSpan } from "../telemetry/index.js";
7
+ const isTelemetryEnabled = !1;
8
+ class Validator {
9
+ schemaValidator;
10
+ namingValidator;
11
+ referenceValidator;
12
+ semanticValidator;
13
+ constructor() {
14
+ this.schemaValidator = new SchemaValidator(), this.namingValidator = new NamingValidator(), this.referenceValidator = new ReferenceValidator(), this.semanticValidator = new SemanticValidator();
15
+ }
16
+ /**
17
+ * Validate a complete model through all 4 stages
18
+ */
19
+ async validateModel(model) {
20
+ const rootSpan = isTelemetryEnabled ? startSpan("model.validate", {
21
+ "model.path": model.rootPath
22
+ }) : null, result = new ValidationResult();
23
+ try {
24
+ const schemaStageSpan = isTelemetryEnabled ? startSpan("validation.stage.schema") : null;
25
+ try {
26
+ for (const layer of model.layers.values()) {
27
+ const schemaResult = await this.schemaValidator.validateLayer(layer);
28
+ result.merge(schemaResult, `[Schema/${layer.name}]`);
29
+ }
30
+ isTelemetryEnabled && schemaStageSpan && schemaStageSpan.setAttribute("validation.error_count", result.errors.length);
31
+ } finally {
32
+ endSpan(schemaStageSpan);
33
+ }
34
+ const namingStageSpan = isTelemetryEnabled ? startSpan("validation.stage.naming") : null;
35
+ try {
36
+ for (const layer of model.layers.values()) {
37
+ const namingResult = this.namingValidator.validateLayer(layer);
38
+ result.merge(namingResult, `[Naming/${layer.name}]`);
39
+ }
40
+ isTelemetryEnabled && namingStageSpan && namingStageSpan.setAttribute("validation.error_count", result.errors.length);
41
+ } finally {
42
+ endSpan(namingStageSpan);
43
+ }
44
+ const refStageSpan = isTelemetryEnabled ? startSpan("validation.stage.reference") : null;
45
+ try {
46
+ const referenceResult = this.referenceValidator.validateModel(model);
47
+ result.merge(referenceResult, "[References]"), isTelemetryEnabled && refStageSpan && refStageSpan.setAttribute("validation.error_count", result.errors.length);
48
+ } finally {
49
+ endSpan(refStageSpan);
50
+ }
51
+ const semanticStageSpan = isTelemetryEnabled ? startSpan("validation.stage.semantic") : null;
52
+ try {
53
+ const semanticResult = await this.semanticValidator.validateModel(model);
54
+ result.merge(semanticResult, "[Semantic]"), isTelemetryEnabled && semanticStageSpan && semanticStageSpan.setAttribute("validation.error_count", result.errors.length);
55
+ } finally {
56
+ endSpan(semanticStageSpan);
57
+ }
58
+ return isTelemetryEnabled && rootSpan && (rootSpan.setAttribute("validation.valid", result.isValid()), rootSpan.setAttribute("validation.error_count", result.errors.length)), result;
59
+ } finally {
60
+ endSpan(rootSpan);
61
+ }
62
+ }
63
+ }
64
+ export {
65
+ Validator
66
+ };
67
+ //# sourceMappingURL=validator.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/validators/validator.ts"],
4
+ "sourcesContent": ["/**\n * Unified validator orchestrating the 4-stage validation pipeline\n */\n\nimport { ValidationResult } from './types.js';\nimport { SchemaValidator } from './schema-validator.js';\nimport { NamingValidator } from './naming-validator.js';\nimport { ReferenceValidator } from './reference-validator.js';\nimport { SemanticValidator } from './semantic-validator.js';\nimport type { Model } from '../core/model.js';\nimport { startSpan, endSpan } from '../telemetry/index.js';\n\n// Fallback for runtime environments where TELEMETRY_ENABLED is not defined by esbuild\ndeclare const TELEMETRY_ENABLED: boolean | undefined;\nconst isTelemetryEnabled = typeof TELEMETRY_ENABLED !== 'undefined' ? TELEMETRY_ENABLED : false;\n\n/**\n * Unified validator implementing the 4-stage validation pipeline:\n * 1. Schema validation (AJV)\n * 2. Naming validation (element ID format)\n * 3. Reference validation (cross-layer integrity)\n * 4. Semantic validation (business rules)\n */\nexport class Validator {\n private schemaValidator: SchemaValidator;\n private namingValidator: NamingValidator;\n private referenceValidator: ReferenceValidator;\n private semanticValidator: SemanticValidator;\n\n constructor() {\n this.schemaValidator = new SchemaValidator();\n this.namingValidator = new NamingValidator();\n this.referenceValidator = new ReferenceValidator();\n this.semanticValidator = new SemanticValidator();\n }\n\n /**\n * Validate a complete model through all 4 stages\n */\n async validateModel(model: Model): Promise<ValidationResult> {\n const rootSpan = isTelemetryEnabled ? startSpan('model.validate', {\n 'model.path': model.rootPath,\n }) : null;\n\n const result = new ValidationResult();\n\n try {\n // Stage 1: Schema validation\n const schemaStageSpan = isTelemetryEnabled ? startSpan('validation.stage.schema') : null;\n try {\n for (const layer of model.layers.values()) {\n const schemaResult = await this.schemaValidator.validateLayer(layer);\n result.merge(schemaResult, `[Schema/${layer.name}]`);\n }\n\n if (isTelemetryEnabled && schemaStageSpan) {\n schemaStageSpan.setAttribute('validation.error_count', result.errors.length);\n }\n } finally {\n endSpan(schemaStageSpan);\n }\n\n // Stage 2: Naming validation\n const namingStageSpan = isTelemetryEnabled ? startSpan('validation.stage.naming') : null;\n try {\n for (const layer of model.layers.values()) {\n const namingResult = this.namingValidator.validateLayer(layer);\n result.merge(namingResult, `[Naming/${layer.name}]`);\n }\n\n if (isTelemetryEnabled && namingStageSpan) {\n namingStageSpan.setAttribute('validation.error_count', result.errors.length);\n }\n } finally {\n endSpan(namingStageSpan);\n }\n\n // Stage 3: Reference validation\n const refStageSpan = isTelemetryEnabled ? startSpan('validation.stage.reference') : null;\n try {\n const referenceResult = this.referenceValidator.validateModel(model);\n result.merge(referenceResult, '[References]');\n\n if (isTelemetryEnabled && refStageSpan) {\n refStageSpan.setAttribute('validation.error_count', result.errors.length);\n }\n } finally {\n endSpan(refStageSpan);\n }\n\n // Stage 4: Semantic validation\n const semanticStageSpan = isTelemetryEnabled ? startSpan('validation.stage.semantic') : null;\n try {\n const semanticResult = await this.semanticValidator.validateModel(model);\n result.merge(semanticResult, '[Semantic]');\n\n if (isTelemetryEnabled && semanticStageSpan) {\n semanticStageSpan.setAttribute('validation.error_count', result.errors.length);\n }\n } finally {\n endSpan(semanticStageSpan);\n }\n\n if (isTelemetryEnabled && rootSpan) {\n rootSpan.setAttribute('validation.valid', result.isValid());\n rootSpan.setAttribute('validation.error_count', result.errors.length);\n }\n\n return result;\n } finally {\n endSpan(rootSpan);\n }\n }\n}\n"],
5
+ "mappings": "AAIA,SAAS,wBAAwB;AACjC,SAAS,uBAAuB;AAChC,SAAS,uBAAuB;AAChC,SAAS,0BAA0B;AACnC,SAAS,yBAAyB;AAElC,SAAS,WAAW,eAAe;AAInC,MAAM,qBAAgE;AAShE,MAAO,UAAS;EACZ;EACA;EACA;EACA;EAER,cAAA;AACE,SAAK,kBAAkB,IAAI,gBAAe,GAC1C,KAAK,kBAAkB,IAAI,gBAAe,GAC1C,KAAK,qBAAqB,IAAI,mBAAkB,GAChD,KAAK,oBAAoB,IAAI,kBAAiB;EAChD;;;;EAKA,MAAM,cAAc,OAAY;AAC9B,UAAM,WAAW,qBAAqB,UAAU,kBAAkB;MAChE,cAAc,MAAM;KACrB,IAAI,MAEC,SAAS,IAAI,iBAAgB;AAEnC,QAAI;AAEF,YAAM,kBAAkB,qBAAqB,UAAU,yBAAyB,IAAI;AACpF,UAAI;AACF,mBAAW,SAAS,MAAM,OAAO,OAAM,GAAI;AACzC,gBAAM,eAAe,MAAM,KAAK,gBAAgB,cAAc,KAAK;AACnE,iBAAO,MAAM,cAAc,WAAW,MAAM,IAAI,GAAG;QACrD;AAEA,QAAI,sBAAsB,mBACxB,gBAAgB,aAAa,0BAA0B,OAAO,OAAO,MAAM;MAE/E;AACE,gBAAQ,eAAe;MACzB;AAGA,YAAM,kBAAkB,qBAAqB,UAAU,yBAAyB,IAAI;AACpF,UAAI;AACF,mBAAW,SAAS,MAAM,OAAO,OAAM,GAAI;AACzC,gBAAM,eAAe,KAAK,gBAAgB,cAAc,KAAK;AAC7D,iBAAO,MAAM,cAAc,WAAW,MAAM,IAAI,GAAG;QACrD;AAEA,QAAI,sBAAsB,mBACxB,gBAAgB,aAAa,0BAA0B,OAAO,OAAO,MAAM;MAE/E;AACE,gBAAQ,eAAe;MACzB;AAGA,YAAM,eAAe,qBAAqB,UAAU,4BAA4B,IAAI;AACpF,UAAI;AACF,cAAM,kBAAkB,KAAK,mBAAmB,cAAc,KAAK;AACnE,eAAO,MAAM,iBAAiB,cAAc,GAExC,sBAAsB,gBACxB,aAAa,aAAa,0BAA0B,OAAO,OAAO,MAAM;MAE5E;AACE,gBAAQ,YAAY;MACtB;AAGA,YAAM,oBAAoB,qBAAqB,UAAU,2BAA2B,IAAI;AACxF,UAAI;AACF,cAAM,iBAAiB,MAAM,KAAK,kBAAkB,cAAc,KAAK;AACvE,eAAO,MAAM,gBAAgB,YAAY,GAErC,sBAAsB,qBACxB,kBAAkB,aAAa,0BAA0B,OAAO,OAAO,MAAM;MAEjF;AACE,gBAAQ,iBAAiB;MAC3B;AAEA,aAAI,sBAAsB,aACxB,SAAS,aAAa,oBAAoB,OAAO,QAAO,CAAE,GAC1D,SAAS,aAAa,0BAA0B,OAAO,OAAO,MAAM,IAG/D;IACT;AACE,cAAQ,QAAQ;IAClB;EACF;;",
6
+ "names": []
7
+ }