@living-architecture/riviere-schema-published-language 0.9.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.
@@ -0,0 +1,662 @@
1
+ // src/published-language/validation.ts
2
+ import Ajv from "ajv";
3
+ import addFormats from "ajv-formats";
4
+
5
+ // riviere.schema.json
6
+ var riviere_schema_default = {
7
+ $schema: "http://json-schema.org/draft-07/schema#",
8
+ $id: "https://riviere.arch/schema/riviere.schema.json",
9
+ title: "Rivi\xE8re Architecture Graph",
10
+ description: "Flow-based architecture graph format for operational visualization",
11
+ type: "object",
12
+ required: ["version", "metadata", "components", "links"],
13
+ properties: {
14
+ version: {
15
+ type: "string",
16
+ description: "Schema version",
17
+ pattern: "^[0-9]+\\.[0-9]+$"
18
+ },
19
+ metadata: {
20
+ type: "object",
21
+ description: "Graph-level metadata",
22
+ required: ["domains"],
23
+ properties: {
24
+ name: {
25
+ type: "string",
26
+ description: "Human-readable name for this architecture graph"
27
+ },
28
+ description: {
29
+ type: "string",
30
+ description: "Description of what this graph represents"
31
+ },
32
+ generated: {
33
+ type: "string",
34
+ format: "date-time",
35
+ description: "Timestamp when this graph was generated"
36
+ },
37
+ sources: {
38
+ type: "array",
39
+ description: "Source repositories this graph was extracted from",
40
+ items: {
41
+ type: "object",
42
+ required: ["repository"],
43
+ properties: {
44
+ repository: {
45
+ type: "string",
46
+ description: "Repository name or identifier",
47
+ minLength: 3
48
+ },
49
+ commit: {
50
+ type: "string",
51
+ description: "Git commit SHA"
52
+ },
53
+ extractedAt: {
54
+ type: "string",
55
+ format: "date-time",
56
+ description: "When this repository was extracted"
57
+ }
58
+ }
59
+ }
60
+ },
61
+ domains: {
62
+ type: "object",
63
+ description: "Domain-level metadata keyed by domain name",
64
+ minProperties: 1,
65
+ additionalProperties: {
66
+ $ref: "#/definitions/domainMetadata"
67
+ }
68
+ },
69
+ customTypes: {
70
+ type: "object",
71
+ description: "User-defined custom component types with their required and optional properties",
72
+ additionalProperties: {
73
+ $ref: "#/definitions/customTypeDefinition"
74
+ }
75
+ },
76
+ relationshipTypes: {
77
+ type: "object",
78
+ description: "Project-defined relationship types keyed by name",
79
+ additionalProperties: {
80
+ $ref: "#/definitions/relationshipTypeDefinition"
81
+ }
82
+ }
83
+ }
84
+ },
85
+ components: {
86
+ type: "array",
87
+ description: "Architectural components in the system",
88
+ items: {
89
+ $ref: "#/definitions/component"
90
+ }
91
+ },
92
+ links: {
93
+ type: "array",
94
+ description: "Operational flows between components",
95
+ items: {
96
+ $ref: "#/definitions/link"
97
+ }
98
+ },
99
+ externalLinks: {
100
+ type: "array",
101
+ description: "Links to external systems outside the graph",
102
+ items: {
103
+ $ref: "#/definitions/externalLink"
104
+ }
105
+ }
106
+ },
107
+ definitions: {
108
+ component: {
109
+ oneOf: [
110
+ { $ref: "#/definitions/uiComponent" },
111
+ { $ref: "#/definitions/apiRestComponent" },
112
+ { $ref: "#/definitions/apiGraphqlComponent" },
113
+ { $ref: "#/definitions/apiOtherComponent" },
114
+ { $ref: "#/definitions/useCaseComponent" },
115
+ { $ref: "#/definitions/domainOpComponent" },
116
+ { $ref: "#/definitions/eventComponent" },
117
+ { $ref: "#/definitions/eventHandlerComponent" },
118
+ { $ref: "#/definitions/customComponent" }
119
+ ]
120
+ },
121
+ baseComponentProperties: {
122
+ type: "object",
123
+ properties: {
124
+ id: {
125
+ type: "string",
126
+ description: "Globally unique identifier following format: {domain}:{module}:{type}:{name}[:{lineNumber}].",
127
+ minLength: 1
128
+ },
129
+ name: {
130
+ type: "string",
131
+ description: "Human-readable name",
132
+ minLength: 1
133
+ },
134
+ domain: {
135
+ type: "string",
136
+ description: "Domain boundary this node belongs to",
137
+ minLength: 1
138
+ },
139
+ module: {
140
+ type: "string",
141
+ description: "Functional module within the domain",
142
+ minLength: 1
143
+ },
144
+ description: {
145
+ type: "string",
146
+ description: "Optional description of what this node does"
147
+ },
148
+ sourceLocation: {
149
+ $ref: "#/definitions/sourceLocation"
150
+ }
151
+ }
152
+ },
153
+ uiComponent: {
154
+ type: "object",
155
+ required: ["id", "type", "name", "domain", "module", "sourceLocation", "route"],
156
+ properties: {
157
+ id: { type: "string", minLength: 1 },
158
+ type: { const: "UI" },
159
+ name: { type: "string", minLength: 1 },
160
+ domain: { type: "string", minLength: 1 },
161
+ module: { type: "string", minLength: 1 },
162
+ description: { type: "string" },
163
+ sourceLocation: { $ref: "#/definitions/sourceLocation" },
164
+ route: {
165
+ type: "string",
166
+ description: "URL route where UI component is rendered",
167
+ minLength: 1
168
+ }
169
+ },
170
+ additionalProperties: false
171
+ },
172
+ apiRestComponent: {
173
+ type: "object",
174
+ required: [
175
+ "id",
176
+ "type",
177
+ "name",
178
+ "domain",
179
+ "module",
180
+ "sourceLocation",
181
+ "apiType",
182
+ "httpMethod",
183
+ "path"
184
+ ],
185
+ properties: {
186
+ id: { type: "string", minLength: 1 },
187
+ type: { const: "API" },
188
+ name: { type: "string", minLength: 1 },
189
+ domain: { type: "string", minLength: 1 },
190
+ module: { type: "string", minLength: 1 },
191
+ description: { type: "string" },
192
+ sourceLocation: { $ref: "#/definitions/sourceLocation" },
193
+ apiType: { const: "REST" },
194
+ httpMethod: {
195
+ type: "string",
196
+ enum: ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"]
197
+ },
198
+ path: { type: "string", description: "API path", minLength: 3 }
199
+ },
200
+ additionalProperties: false
201
+ },
202
+ apiGraphqlComponent: {
203
+ type: "object",
204
+ required: [
205
+ "id",
206
+ "type",
207
+ "name",
208
+ "domain",
209
+ "module",
210
+ "sourceLocation",
211
+ "apiType",
212
+ "operationName"
213
+ ],
214
+ properties: {
215
+ id: { type: "string", minLength: 1 },
216
+ type: { const: "API" },
217
+ name: { type: "string", minLength: 1 },
218
+ domain: { type: "string", minLength: 1 },
219
+ module: { type: "string", minLength: 1 },
220
+ description: { type: "string" },
221
+ sourceLocation: { $ref: "#/definitions/sourceLocation" },
222
+ apiType: { const: "GraphQL" },
223
+ operationName: {
224
+ type: "string",
225
+ description: "GraphQL operation name",
226
+ minLength: 2
227
+ }
228
+ },
229
+ additionalProperties: false
230
+ },
231
+ apiOtherComponent: {
232
+ type: "object",
233
+ required: ["id", "type", "name", "domain", "module", "sourceLocation", "apiType"],
234
+ properties: {
235
+ id: { type: "string", minLength: 1 },
236
+ type: { const: "API" },
237
+ name: { type: "string", minLength: 1 },
238
+ domain: { type: "string", minLength: 1 },
239
+ module: { type: "string", minLength: 1 },
240
+ description: { type: "string" },
241
+ sourceLocation: { $ref: "#/definitions/sourceLocation" },
242
+ apiType: { const: "other" }
243
+ },
244
+ additionalProperties: false
245
+ },
246
+ useCaseComponent: {
247
+ type: "object",
248
+ required: ["id", "type", "name", "domain", "module", "sourceLocation"],
249
+ properties: {
250
+ id: { type: "string", minLength: 1 },
251
+ type: { const: "UseCase" },
252
+ name: { type: "string", minLength: 1 },
253
+ domain: { type: "string", minLength: 1 },
254
+ module: { type: "string", minLength: 1 },
255
+ description: { type: "string" },
256
+ sourceLocation: { $ref: "#/definitions/sourceLocation" }
257
+ },
258
+ additionalProperties: false
259
+ },
260
+ domainOpComponent: {
261
+ type: "object",
262
+ required: ["id", "type", "name", "domain", "module", "sourceLocation", "operationName"],
263
+ properties: {
264
+ id: { type: "string", minLength: 1 },
265
+ type: { const: "DomainOp" },
266
+ name: { type: "string", minLength: 1 },
267
+ domain: { type: "string", minLength: 1 },
268
+ module: { type: "string", minLength: 1 },
269
+ description: { type: "string" },
270
+ sourceLocation: { $ref: "#/definitions/sourceLocation" },
271
+ operationName: { type: "string", description: "Operation name", minLength: 2 },
272
+ entity: { type: "string", description: "Entity name" },
273
+ signature: { $ref: "#/definitions/operationSignature" },
274
+ behavior: { $ref: "#/definitions/operationBehavior" },
275
+ stateChanges: { type: "array", items: { $ref: "#/definitions/stateTransition" } },
276
+ businessRules: { type: "array", items: { type: "string", minLength: 1 } }
277
+ },
278
+ additionalProperties: false
279
+ },
280
+ eventComponent: {
281
+ type: "object",
282
+ required: ["id", "type", "name", "domain", "module", "sourceLocation", "eventName"],
283
+ properties: {
284
+ id: { type: "string", minLength: 1 },
285
+ type: { const: "Event" },
286
+ name: { type: "string", minLength: 1 },
287
+ domain: { type: "string", minLength: 1 },
288
+ module: { type: "string", minLength: 1 },
289
+ description: { type: "string" },
290
+ sourceLocation: { $ref: "#/definitions/sourceLocation" },
291
+ eventName: { type: "string", description: "Event name", minLength: 3 },
292
+ eventSchema: { type: "string", description: "Event schema definition" }
293
+ },
294
+ additionalProperties: false
295
+ },
296
+ eventHandlerComponent: {
297
+ type: "object",
298
+ required: ["id", "type", "name", "domain", "module", "sourceLocation", "subscribedEvents"],
299
+ properties: {
300
+ id: { type: "string", minLength: 1 },
301
+ type: { const: "EventHandler" },
302
+ name: { type: "string", minLength: 1 },
303
+ domain: { type: "string", minLength: 1 },
304
+ module: { type: "string", minLength: 1 },
305
+ description: { type: "string" },
306
+ sourceLocation: { $ref: "#/definitions/sourceLocation" },
307
+ subscribedEvents: {
308
+ type: "array",
309
+ items: { type: "string" },
310
+ description: "Events this handler subscribes to"
311
+ }
312
+ },
313
+ additionalProperties: false
314
+ },
315
+ customComponent: {
316
+ type: "object",
317
+ required: ["id", "type", "name", "domain", "module", "sourceLocation", "customTypeName"],
318
+ properties: {
319
+ id: { type: "string", minLength: 1 },
320
+ type: { const: "Custom" },
321
+ name: { type: "string", minLength: 1 },
322
+ domain: { type: "string", minLength: 1 },
323
+ module: { type: "string", minLength: 1 },
324
+ description: { type: "string" },
325
+ sourceLocation: { $ref: "#/definitions/sourceLocation" },
326
+ customTypeName: {
327
+ type: "string",
328
+ description: "Name of the custom type (must match a key in metadata.customTypes)",
329
+ minLength: 1
330
+ }
331
+ },
332
+ additionalProperties: true
333
+ },
334
+ link: {
335
+ type: "object",
336
+ required: ["source", "target"],
337
+ properties: {
338
+ id: {
339
+ type: "string",
340
+ description: "Optional unique identifier for this link"
341
+ },
342
+ source: {
343
+ type: "string",
344
+ description: "Source component ID",
345
+ minLength: 1
346
+ },
347
+ target: {
348
+ type: "string",
349
+ description: "Target component ID",
350
+ minLength: 1
351
+ },
352
+ type: {
353
+ type: "string",
354
+ enum: ["sync", "async"],
355
+ description: "Link type: sync (request/response) or async (fire-and-forget, events)"
356
+ },
357
+ relationshipType: {
358
+ type: "string",
359
+ description: "Project-defined relationship type name",
360
+ minLength: 1
361
+ },
362
+ condition: {
363
+ type: "string",
364
+ description: "Condition retained exactly as supplied"
365
+ },
366
+ payload: {
367
+ type: "object",
368
+ description: "Data transferred through this flow",
369
+ properties: {
370
+ type: {
371
+ type: "string",
372
+ description: "Payload type name"
373
+ },
374
+ schema: {
375
+ type: "object",
376
+ description: "Schema definition as JSON object"
377
+ }
378
+ }
379
+ },
380
+ sourceLocation: {
381
+ $ref: "#/definitions/sourceLocation"
382
+ }
383
+ },
384
+ additionalProperties: false
385
+ },
386
+ externalLink: {
387
+ type: "object",
388
+ description: "Link from an internal component to an external system",
389
+ required: ["source", "target"],
390
+ properties: {
391
+ id: {
392
+ type: "string",
393
+ description: "Optional unique identifier for this link"
394
+ },
395
+ source: {
396
+ type: "string",
397
+ description: "Source component ID (must exist in graph)",
398
+ minLength: 1
399
+ },
400
+ target: {
401
+ $ref: "#/definitions/externalTarget",
402
+ description: "External system being called"
403
+ },
404
+ type: {
405
+ type: "string",
406
+ enum: ["sync", "async"],
407
+ description: "Link type: sync (request/response) or async (fire-and-forget)"
408
+ },
409
+ description: {
410
+ type: "string",
411
+ description: "Human-readable description of this integration"
412
+ },
413
+ sourceLocation: {
414
+ $ref: "#/definitions/sourceLocation"
415
+ }
416
+ },
417
+ additionalProperties: false
418
+ },
419
+ externalTarget: {
420
+ type: "object",
421
+ description: "Reference to an external system outside the graph",
422
+ required: ["name"],
423
+ properties: {
424
+ name: {
425
+ type: "string",
426
+ description: "Name of the external system",
427
+ minLength: 1
428
+ },
429
+ route: {
430
+ type: "string",
431
+ description: "Remote route/path for the external call",
432
+ minLength: 1
433
+ },
434
+ domain: {
435
+ type: "string",
436
+ description: "Domain name if known"
437
+ },
438
+ repository: {
439
+ type: "string",
440
+ description: "Repository name if known",
441
+ minLength: 3
442
+ },
443
+ url: {
444
+ type: "string",
445
+ format: "uri",
446
+ description: "URL to the external system"
447
+ }
448
+ },
449
+ additionalProperties: { type: "string" }
450
+ },
451
+ sourceLocation: {
452
+ type: "object",
453
+ required: ["repository", "filePath"],
454
+ properties: {
455
+ repository: {
456
+ type: "string",
457
+ description: "Repository name or identifier",
458
+ minLength: 3
459
+ },
460
+ filePath: {
461
+ type: "string",
462
+ description: "Relative file path within repository",
463
+ minLength: 1
464
+ },
465
+ lineNumber: {
466
+ type: "integer",
467
+ description: "Starting line number",
468
+ minimum: 1
469
+ },
470
+ columnNumber: {
471
+ type: "integer",
472
+ description: "Starting column number",
473
+ minimum: 1
474
+ },
475
+ endLineNumber: {
476
+ type: "integer",
477
+ description: "Ending line number",
478
+ minimum: 1
479
+ },
480
+ methodName: {
481
+ type: "string",
482
+ description: "Method or function name"
483
+ },
484
+ url: {
485
+ type: "string",
486
+ format: "uri",
487
+ description: "Direct URL to view this location in source control"
488
+ }
489
+ },
490
+ additionalProperties: false
491
+ },
492
+ domainMetadata: {
493
+ type: "object",
494
+ description: "Domain-level metadata for UI display",
495
+ required: ["description", "systemType"],
496
+ properties: {
497
+ description: {
498
+ type: "string",
499
+ description: "Human-readable description of domain purpose",
500
+ minLength: 3
501
+ },
502
+ systemType: {
503
+ type: "string",
504
+ enum: ["domain", "bff", "ui", "external-service", "other"],
505
+ description: "Classification of domain's role in system"
506
+ }
507
+ },
508
+ additionalProperties: false
509
+ },
510
+ customTypeDefinition: {
511
+ type: "object",
512
+ description: "Definition of a custom component type with required and optional properties",
513
+ properties: {
514
+ description: {
515
+ type: "string",
516
+ description: "Human-readable description of this custom type"
517
+ },
518
+ requiredProperties: {
519
+ type: "object",
520
+ description: "Properties required for components of this custom type (beyond base component properties)",
521
+ additionalProperties: {
522
+ $ref: "#/definitions/customPropertyDefinition"
523
+ }
524
+ },
525
+ optionalProperties: {
526
+ type: "object",
527
+ description: "Optional properties for components of this custom type",
528
+ additionalProperties: {
529
+ $ref: "#/definitions/customPropertyDefinition"
530
+ }
531
+ }
532
+ },
533
+ additionalProperties: false
534
+ },
535
+ relationshipTypeDefinition: {
536
+ type: "object",
537
+ description: "Definition of a project-defined relationship type",
538
+ required: ["description"],
539
+ properties: {
540
+ description: {
541
+ type: "string",
542
+ description: "Human-readable description of this relationship type",
543
+ minLength: 1
544
+ }
545
+ },
546
+ additionalProperties: false
547
+ },
548
+ customPropertyDefinition: {
549
+ type: "object",
550
+ description: "Definition of a property in a custom type",
551
+ required: ["type"],
552
+ properties: {
553
+ type: {
554
+ type: "string",
555
+ description: "JSON Schema type (string, number, boolean, array, object)",
556
+ enum: ["string", "number", "boolean", "array", "object"]
557
+ },
558
+ description: {
559
+ type: "string",
560
+ description: "Human-readable description of this property"
561
+ }
562
+ },
563
+ additionalProperties: false
564
+ },
565
+ operationSignature: {
566
+ type: "object",
567
+ description: "Method signature including parameters and return type",
568
+ properties: {
569
+ parameters: {
570
+ type: "array",
571
+ items: {
572
+ type: "object",
573
+ required: ["name", "type"],
574
+ properties: {
575
+ name: {
576
+ type: "string",
577
+ minLength: 1
578
+ },
579
+ type: {
580
+ type: "string",
581
+ minLength: 1
582
+ },
583
+ description: {
584
+ type: "string"
585
+ }
586
+ },
587
+ additionalProperties: false
588
+ }
589
+ },
590
+ returnType: {
591
+ type: "string",
592
+ minLength: 1
593
+ }
594
+ },
595
+ additionalProperties: false
596
+ },
597
+ operationBehavior: {
598
+ type: "object",
599
+ description: "Behavioral characteristics of the operation",
600
+ properties: {
601
+ reads: {
602
+ type: "array",
603
+ description: "Entity fields or state read by this operation",
604
+ items: { type: "string" }
605
+ },
606
+ validates: {
607
+ type: "array",
608
+ description: "Invariants or preconditions validated",
609
+ items: { type: "string" }
610
+ },
611
+ modifies: {
612
+ type: "array",
613
+ description: "Entity fields or state modified by this operation",
614
+ items: { type: "string" }
615
+ },
616
+ emits: {
617
+ type: "array",
618
+ description: "Events emitted by this operation",
619
+ items: { type: "string" }
620
+ }
621
+ },
622
+ additionalProperties: false
623
+ },
624
+ stateTransition: {
625
+ type: "object",
626
+ description: "A single state transition caused by an operation",
627
+ required: ["from", "to"],
628
+ properties: {
629
+ from: {
630
+ type: "string",
631
+ description: "Source state (use '*' for any state)",
632
+ minLength: 1
633
+ },
634
+ to: {
635
+ type: "string",
636
+ description: "Target state",
637
+ minLength: 1
638
+ }
639
+ },
640
+ additionalProperties: false
641
+ }
642
+ }
643
+ };
644
+
645
+ // src/published-language/validation.ts
646
+ var ajv = new Ajv();
647
+ addFormats(ajv);
648
+ var validate = ajv.compile(riviere_schema_default);
649
+ function parseRiviereGraph(value) {
650
+ if (validate(value)) {
651
+ return { success: true, graph: value };
652
+ }
653
+ return {
654
+ success: false,
655
+ issues: validate.errors?.map(
656
+ (issue) => `${issue.instancePath}: ${issue.message ?? "invalid value"}`
657
+ ) ?? ["validation failed without specific issues"]
658
+ };
659
+ }
660
+ export {
661
+ parseRiviereGraph
662
+ };