@graph-ir/core 0.2.0 → 0.2.1

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 (40) hide show
  1. package/README.md +15 -2
  2. package/dist/canonical-types.d.ts +207 -0
  3. package/dist/canonical-types.d.ts.map +1 -0
  4. package/dist/canonical-types.js +3 -0
  5. package/dist/canonical-types.js.map +1 -0
  6. package/dist/generation/id-generator.d.ts.map +1 -1
  7. package/dist/generation/id-generator.js +16 -10
  8. package/dist/generation/id-generator.js.map +1 -1
  9. package/dist/index.d.ts +2 -1
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +1 -0
  12. package/dist/index.js.map +1 -1
  13. package/dist/output/types.d.ts.map +1 -1
  14. package/dist/schemas/graph-ir.schema.json +327 -271
  15. package/dist/skills/diff.d.ts +4 -0
  16. package/dist/skills/diff.d.ts.map +1 -1
  17. package/dist/skills/diff.js +93 -11
  18. package/dist/skills/diff.js.map +1 -1
  19. package/dist/skills/migrate.d.ts +13 -18
  20. package/dist/skills/migrate.d.ts.map +1 -1
  21. package/dist/skills/migrate.js +224 -247
  22. package/dist/skills/migrate.js.map +1 -1
  23. package/dist/skills/visualize.d.ts.map +1 -1
  24. package/dist/skills/visualize.js +29 -5
  25. package/dist/skills/visualize.js.map +1 -1
  26. package/dist/testing/diff.d.ts +1 -1
  27. package/dist/testing/diff.d.ts.map +1 -1
  28. package/dist/testing/diff.js +23 -19
  29. package/dist/testing/diff.js.map +1 -1
  30. package/dist/types.d.ts +12 -214
  31. package/dist/types.d.ts.map +1 -1
  32. package/dist/types.js +3 -2
  33. package/dist/types.js.map +1 -1
  34. package/dist/validation/ir-validator.d.ts +27 -44
  35. package/dist/validation/ir-validator.d.ts.map +1 -1
  36. package/dist/validation/ir-validator.js +481 -294
  37. package/dist/validation/ir-validator.js.map +1 -1
  38. package/dist/validation/validator.d.ts.map +1 -1
  39. package/package.json +9 -4
  40. package/specification.json +9 -0
@@ -1,359 +1,415 @@
1
1
  {
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
- "$id": "https://graph-ir.dev/schemas/graph-ir.schema.json",
4
- "title": "Graph-IR",
5
- "description": "Graph Intermediate Representation schema",
3
+ "$id": "https://graph-ir.dev/schemas/2.0/graph-ir.schema.json",
4
+ "title": "GraphIR authored graph",
5
+ "description": "Canonical authored GraphIR schema 2.0.0",
6
6
  "type": "object",
7
+ "additionalProperties": false,
7
8
  "required": ["version", "id", "nodes", "edges"],
8
9
  "properties": {
9
- "version": {
10
- "type": "string",
11
- "description": "Schema version for migration support",
12
- "pattern": "^\\d+\\.\\d+\\.\\d+$"
13
- },
14
- "id": {
15
- "type": "string",
16
- "description": "Unique identifier for this graph",
17
- "minLength": 1
18
- },
19
- "name": {
20
- "type": "string",
21
- "description": "Human-readable name"
22
- },
23
- "nodes": {
10
+ "version": { "const": "2.0.0" },
11
+ "id": { "$ref": "#/$defs/Identifier" },
12
+ "name": { "type": "string" },
13
+ "nodes": { "type": "array", "items": { "$ref": "#/$defs/GraphNode" } },
14
+ "edges": { "type": "array", "items": { "$ref": "#/$defs/GraphEdge" } },
15
+ "constraints": {
24
16
  "type": "array",
25
- "description": "Top-level nodes",
26
- "items": { "$ref": "#/$defs/GraphNode" }
27
- },
28
- "edges": {
29
- "type": "array",
30
- "description": "Connections between nodes",
31
- "items": { "$ref": "#/$defs/GraphEdge" }
17
+ "items": { "$ref": "#/$defs/SpatialConstraint" }
32
18
  },
33
19
  "metadata": { "$ref": "#/$defs/GraphMetadata" },
34
20
  "layoutOptions": { "$ref": "#/$defs/LayoutOptions" }
35
21
  },
36
22
  "$defs": {
37
- "GraphNode": {
23
+ "Identifier": { "type": "string", "minLength": 1 },
24
+ "Position": {
38
25
  "type": "object",
39
- "required": ["id", "type"],
26
+ "additionalProperties": false,
27
+ "required": ["x", "y"],
28
+ "properties": { "x": { "type": "number" }, "y": { "type": "number" } }
29
+ },
30
+ "Dimensions": {
31
+ "type": "object",
32
+ "additionalProperties": false,
33
+ "required": ["width", "height"],
40
34
  "properties": {
41
- "id": {
42
- "type": "string",
43
- "description": "Unique identifier within the graph",
44
- "minLength": 1
45
- },
46
- "type": {
47
- "type": "string",
48
- "description": "Node type (e.g., 'service', 'database')",
49
- "minLength": 1
50
- },
51
- "label": {
52
- "type": "string",
53
- "description": "Display label"
54
- },
55
- "description": {
56
- "type": "string",
57
- "description": "Optional description"
58
- },
59
- "symbol": {
60
- "type": "string",
61
- "description": "Symbol registry key used for visual representation"
62
- },
63
- "variant": {
64
- "type": "string",
65
- "description": "Optional variant of the selected symbol"
66
- },
67
- "properties": {
68
- "type": "object",
69
- "description": "Custom properties",
70
- "additionalProperties": true
71
- },
72
- "children": {
73
- "type": "array",
74
- "description": "Child nodes for compound graphs",
75
- "items": { "$ref": "#/$defs/GraphNode" }
76
- },
77
- "parent": {
78
- "type": "string",
79
- "description": "Parent node ID"
80
- },
81
- "ports": {
82
- "type": "array",
83
- "description": "Connection points",
84
- "items": { "$ref": "#/$defs/Port" }
85
- },
86
- "dimensions": { "$ref": "#/$defs/Dimensions" },
87
- "position": { "$ref": "#/$defs/Position" },
88
- "pinned": {
89
- "type": "boolean",
90
- "description": "Preserve position during layout"
91
- },
92
- "layoutOptions": { "$ref": "#/$defs/NodeLayoutOptions" },
93
- "sourceInfo": { "$ref": "#/$defs/SourceInfo" }
35
+ "width": { "type": "number", "minimum": 0 },
36
+ "height": { "type": "number", "minimum": 0 }
94
37
  }
95
38
  },
39
+ "PlacementSide": {
40
+ "type": "string",
41
+ "enum": ["above", "below", "left", "right", "center"]
42
+ },
43
+ "NodeLabelPlacement": {
44
+ "type": "object",
45
+ "additionalProperties": false,
46
+ "required": ["side"],
47
+ "properties": {
48
+ "side": { "$ref": "#/$defs/PlacementSide" },
49
+ "offset": { "type": "number", "minimum": 0, "default": 0 }
50
+ },
51
+ "allOf": [
52
+ {
53
+ "if": { "properties": { "side": { "const": "center" } }, "required": ["side"] },
54
+ "then": { "properties": { "offset": { "const": 0 } } }
55
+ }
56
+ ]
57
+ },
58
+ "EdgeLabelPlacement": {
59
+ "type": "object",
60
+ "additionalProperties": false,
61
+ "required": ["side"],
62
+ "properties": {
63
+ "side": { "$ref": "#/$defs/PlacementSide" },
64
+ "at": { "type": "number", "minimum": 0, "maximum": 1, "default": 0.5 },
65
+ "offset": { "type": "number", "minimum": 0, "default": 0 }
66
+ },
67
+ "allOf": [
68
+ {
69
+ "if": { "properties": { "side": { "const": "center" } }, "required": ["side"] },
70
+ "then": { "properties": { "offset": { "const": 0 } } }
71
+ }
72
+ ]
73
+ },
96
74
  "Port": {
97
75
  "type": "object",
76
+ "additionalProperties": false,
98
77
  "required": ["id", "side"],
99
78
  "properties": {
100
- "id": {
101
- "type": "string",
102
- "description": "Unique identifier within parent node",
103
- "minLength": 1
104
- },
105
- "side": {
106
- "type": "string",
107
- "enum": ["NORTH", "SOUTH", "EAST", "WEST"],
108
- "description": "Which side of the node"
109
- },
110
- "label": {
111
- "type": "string",
112
- "description": "Optional label"
113
- },
114
- "position": {
115
- "type": "number",
116
- "minimum": 0,
117
- "maximum": 1,
118
- "description": "Position along the side (0.0 to 1.0)"
119
- },
120
- "properties": {
121
- "type": "object",
122
- "additionalProperties": true
123
- }
79
+ "id": { "$ref": "#/$defs/Identifier" },
80
+ "side": { "type": "string", "enum": ["NORTH", "SOUTH", "EAST", "WEST"] },
81
+ "label": { "type": "string" },
82
+ "position": { "type": "number", "minimum": 0, "maximum": 1 },
83
+ "properties": { "type": "object", "additionalProperties": true }
124
84
  }
125
85
  },
126
- "GraphEdge": {
86
+ "Padding": {
127
87
  "type": "object",
128
- "required": ["id", "source", "target"],
88
+ "additionalProperties": false,
129
89
  "properties": {
130
- "id": {
131
- "type": "string",
132
- "description": "Unique identifier within the graph",
133
- "minLength": 1
134
- },
135
- "source": {
136
- "type": "string",
137
- "description": "Source node ID",
138
- "minLength": 1
139
- },
140
- "target": {
141
- "type": "string",
142
- "description": "Target node ID",
143
- "minLength": 1
144
- },
145
- "sourcePort": {
146
- "type": "string",
147
- "description": "Source port ID"
148
- },
149
- "targetPort": {
150
- "type": "string",
151
- "description": "Target port ID"
152
- },
153
- "type": {
154
- "type": "string",
155
- "description": "Edge type"
156
- },
157
- "label": {
158
- "type": "string",
159
- "description": "Display label"
160
- },
161
- "properties": {
162
- "type": "object",
163
- "additionalProperties": true
164
- },
165
- "routingPoints": {
166
- "type": "array",
167
- "items": { "$ref": "#/$defs/Position" }
168
- },
169
- "style": { "$ref": "#/$defs/EdgeStyle" },
170
- "sourceInfo": { "$ref": "#/$defs/SourceInfo" }
90
+ "top": { "type": "number", "minimum": 0, "default": 0 },
91
+ "right": { "type": "number", "minimum": 0, "default": 0 },
92
+ "bottom": { "type": "number", "minimum": 0, "default": 0 },
93
+ "left": { "type": "number", "minimum": 0, "default": 0 }
171
94
  }
172
95
  },
173
- "EdgeStyle": {
96
+ "SpacingOptions": {
174
97
  "type": "object",
98
+ "additionalProperties": false,
175
99
  "properties": {
176
- "lineStyle": {
177
- "type": "string",
178
- "enum": ["solid", "dashed", "dotted"]
179
- },
180
- "targetArrow": {
181
- "type": "string",
182
- "enum": ["arrow", "diamond", "circle", "none"]
183
- },
184
- "sourceArrow": {
185
- "type": "string",
186
- "enum": ["arrow", "diamond", "circle", "none"]
187
- },
188
- "routing": {
189
- "type": "string",
190
- "enum": ["orthogonal", "polyline", "spline"]
191
- }
100
+ "nodeNode": { "type": "number", "minimum": 0 },
101
+ "nodeEdge": { "type": "number", "minimum": 0 },
102
+ "edgeEdge": { "type": "number", "minimum": 0 },
103
+ "layerSpacing": { "type": "number", "minimum": 0 }
192
104
  }
193
105
  },
194
- "Dimensions": {
106
+ "LayoutOptions": {
195
107
  "type": "object",
196
- "required": ["width", "height"],
108
+ "additionalProperties": false,
197
109
  "properties": {
198
- "width": { "type": "number", "minimum": 0 },
199
- "height": { "type": "number", "minimum": 0 }
110
+ "algorithm": { "type": "string", "enum": ["layered", "force", "radial", "tree", "fixed"] },
111
+ "direction": { "type": "string", "enum": ["DOWN", "UP", "LEFT", "RIGHT"] },
112
+ "spacing": { "$ref": "#/$defs/SpacingOptions" },
113
+ "edgeRouting": { "type": "string", "enum": ["orthogonal", "polyline", "spline"] },
114
+ "hierarchyHandling": { "type": "string", "enum": ["INCLUDE_CHILDREN", "SEPARATE_CHILDREN"] }
200
115
  }
201
116
  },
202
- "Position": {
117
+ "NodeLayoutOptions": {
203
118
  "type": "object",
204
- "required": ["x", "y"],
119
+ "additionalProperties": false,
205
120
  "properties": {
206
- "x": { "type": "number" },
207
- "y": { "type": "number" }
121
+ "portConstraints": { "type": "string", "enum": ["FREE", "FIXED_SIDE", "FIXED_ORDER", "FIXED_POS"] },
122
+ "portAlignment": { "type": "string", "enum": ["BEGIN", "CENTER", "END", "JUSTIFIED"] },
123
+ "sizeConstraints": {
124
+ "type": "array",
125
+ "items": { "type": "string", "enum": ["MINIMUM_SIZE", "NODE_LABELS", "PORTS"] },
126
+ "uniqueItems": true
127
+ },
128
+ "minimumSize": { "$ref": "#/$defs/Dimensions" },
129
+ "padding": { "$ref": "#/$defs/Padding" }
208
130
  }
209
131
  },
210
- "LayoutOptions": {
132
+ "GraphNode": {
211
133
  "type": "object",
134
+ "additionalProperties": false,
135
+ "required": ["id", "type"],
212
136
  "properties": {
213
- "algorithm": {
214
- "type": "string",
215
- "enum": ["layered", "force", "radial", "tree", "fixed"]
137
+ "id": { "$ref": "#/$defs/Identifier" },
138
+ "type": { "$ref": "#/$defs/Identifier" },
139
+ "label": { "type": "string" },
140
+ "description": { "type": "string" },
141
+ "symbol": { "type": "string" },
142
+ "variant": { "type": "string" },
143
+ "properties": { "type": "object", "additionalProperties": true },
144
+ "children": { "type": "array", "items": { "$ref": "#/$defs/GraphNode" } },
145
+ "parent": { "$ref": "#/$defs/Identifier" },
146
+ "ports": { "type": "array", "items": { "$ref": "#/$defs/Port" } },
147
+ "dimensions": { "$ref": "#/$defs/Dimensions" },
148
+ "position": { "$ref": "#/$defs/Position" },
149
+ "pinned": { "type": "boolean" },
150
+ "labelPlacement": { "$ref": "#/$defs/NodeLabelPlacement" },
151
+ "layoutOptions": { "$ref": "#/$defs/NodeLayoutOptions" },
152
+ "sourceInfo": { "$ref": "#/$defs/SourceInfo" }
153
+ },
154
+ "allOf": [
155
+ {
156
+ "if": { "properties": { "pinned": { "const": true } }, "required": ["pinned"] },
157
+ "then": { "required": ["position"] }
158
+ }
159
+ ]
160
+ },
161
+ "EdgeStyle": {
162
+ "type": "object",
163
+ "additionalProperties": false,
164
+ "properties": {
165
+ "lineStyle": { "type": "string", "enum": ["solid", "dashed", "dotted"] },
166
+ "targetArrow": { "type": "string", "enum": ["arrow", "diamond", "circle", "none"] },
167
+ "sourceArrow": { "type": "string", "enum": ["arrow", "diamond", "circle", "none"] },
168
+ "routing": { "type": "string", "enum": ["orthogonal", "polyline", "spline"] }
169
+ }
170
+ },
171
+ "RouteAnchor": {
172
+ "oneOf": [
173
+ {
174
+ "type": "object",
175
+ "additionalProperties": false,
176
+ "required": ["kind"],
177
+ "properties": { "kind": { "const": "source" } }
216
178
  },
217
- "direction": {
218
- "type": "string",
219
- "enum": ["DOWN", "UP", "LEFT", "RIGHT"]
179
+ {
180
+ "type": "object",
181
+ "additionalProperties": false,
182
+ "required": ["kind"],
183
+ "properties": { "kind": { "const": "target" } }
220
184
  },
221
- "spacing": { "$ref": "#/$defs/SpacingOptions" },
222
- "edgeRouting": {
223
- "type": "string",
224
- "enum": ["orthogonal", "polyline", "spline"]
185
+ {
186
+ "type": "object",
187
+ "additionalProperties": false,
188
+ "required": ["kind", "nodeId"],
189
+ "properties": { "kind": { "const": "node" }, "nodeId": { "$ref": "#/$defs/Identifier" } }
225
190
  },
226
- "hierarchyHandling": {
227
- "type": "string",
228
- "enum": ["INCLUDE_CHILDREN", "SEPARATE_CHILDREN"]
191
+ {
192
+ "type": "object",
193
+ "additionalProperties": false,
194
+ "required": ["kind", "nodeId", "portId"],
195
+ "properties": {
196
+ "kind": { "const": "port" },
197
+ "nodeId": { "$ref": "#/$defs/Identifier" },
198
+ "portId": { "$ref": "#/$defs/Identifier" }
199
+ }
200
+ }
201
+ ]
202
+ },
203
+ "WaypointPlacement": {
204
+ "oneOf": [
205
+ {
206
+ "type": "object",
207
+ "additionalProperties": false,
208
+ "required": ["kind", "position"],
209
+ "properties": {
210
+ "kind": { "const": "absolute" },
211
+ "position": { "$ref": "#/$defs/Position" }
212
+ }
229
213
  },
230
- "algorithmOptions": {
214
+ {
231
215
  "type": "object",
232
- "additionalProperties": {
233
- "oneOf": [
234
- { "type": "string" },
235
- { "type": "number" },
236
- { "type": "boolean" }
237
- ]
216
+ "additionalProperties": false,
217
+ "required": ["kind", "anchor", "offset"],
218
+ "properties": {
219
+ "kind": { "const": "relative" },
220
+ "anchor": { "$ref": "#/$defs/RouteAnchor" },
221
+ "offset": { "$ref": "#/$defs/Position" }
238
222
  }
239
223
  }
240
- }
224
+ ]
241
225
  },
242
- "SpacingOptions": {
226
+ "RouteWaypoint": {
243
227
  "type": "object",
228
+ "additionalProperties": false,
229
+ "required": ["id", "placement"],
244
230
  "properties": {
245
- "nodeNode": { "type": "number", "minimum": 0 },
246
- "nodeEdge": { "type": "number", "minimum": 0 },
247
- "edgeEdge": { "type": "number", "minimum": 0 },
248
- "layerSpacing": { "type": "number", "minimum": 0 }
231
+ "id": { "$ref": "#/$defs/Identifier" },
232
+ "placement": { "$ref": "#/$defs/WaypointPlacement" }
249
233
  }
250
234
  },
251
- "NodeLayoutOptions": {
235
+ "RouteIntent": {
252
236
  "type": "object",
237
+ "additionalProperties": false,
238
+ "required": ["waypoints"],
253
239
  "properties": {
254
- "portConstraints": {
255
- "type": "string",
256
- "enum": ["FREE", "FIXED_SIDE", "FIXED_ORDER", "FIXED_POS"]
257
- },
258
- "portAlignment": {
259
- "type": "string",
260
- "enum": ["BEGIN", "CENTER", "END", "JUSTIFIED"]
261
- },
262
- "sizeConstraints": {
240
+ "waypoints": {
263
241
  "type": "array",
264
- "items": {
265
- "type": "string",
266
- "enum": ["MINIMUM_SIZE", "NODE_LABELS", "PORTS"]
267
- }
242
+ "minItems": 1,
243
+ "items": { "$ref": "#/$defs/RouteWaypoint" }
244
+ }
245
+ }
246
+ },
247
+ "GraphEdge": {
248
+ "type": "object",
249
+ "additionalProperties": false,
250
+ "required": ["id", "source", "target"],
251
+ "properties": {
252
+ "id": { "$ref": "#/$defs/Identifier" },
253
+ "source": { "$ref": "#/$defs/Identifier" },
254
+ "target": { "$ref": "#/$defs/Identifier" },
255
+ "sourcePort": { "$ref": "#/$defs/Identifier" },
256
+ "targetPort": { "$ref": "#/$defs/Identifier" },
257
+ "type": { "type": "string" },
258
+ "label": { "type": "string" },
259
+ "description": { "type": "string" },
260
+ "labelPlacement": { "$ref": "#/$defs/EdgeLabelPlacement" },
261
+ "routeIntent": { "$ref": "#/$defs/RouteIntent" },
262
+ "properties": { "type": "object", "additionalProperties": true },
263
+ "style": { "$ref": "#/$defs/EdgeStyle" },
264
+ "sourceInfo": { "$ref": "#/$defs/SourceInfo" }
265
+ }
266
+ },
267
+ "ConstraintNodeReference": {
268
+ "type": "object",
269
+ "additionalProperties": false,
270
+ "required": ["kind", "nodeId"],
271
+ "properties": {
272
+ "kind": { "const": "node" },
273
+ "nodeId": { "$ref": "#/$defs/Identifier" }
274
+ }
275
+ },
276
+ "BoundaryScope": {
277
+ "oneOf": [
278
+ {
279
+ "type": "object",
280
+ "additionalProperties": false,
281
+ "required": ["kind"],
282
+ "properties": { "kind": { "const": "graph" } }
268
283
  },
269
- "minimumSize": { "$ref": "#/$defs/Dimensions" },
270
- "padding": {
284
+ {
271
285
  "type": "object",
272
- "properties": {
273
- "top": { "type": "number", "minimum": 0 },
274
- "right": { "type": "number", "minimum": 0 },
275
- "bottom": { "type": "number", "minimum": 0 },
276
- "left": { "type": "number", "minimum": 0 }
277
- }
286
+ "additionalProperties": false,
287
+ "required": ["kind", "nodeId"],
288
+ "properties": { "kind": { "const": "node" }, "nodeId": { "$ref": "#/$defs/Identifier" } }
278
289
  }
290
+ ]
291
+ },
292
+ "ConstraintBaseProperties": {
293
+ "type": "object",
294
+ "properties": {
295
+ "id": { "$ref": "#/$defs/Identifier" },
296
+ "strength": { "type": "string", "enum": ["required", "preferred"], "default": "required" },
297
+ "sourceInfo": { "$ref": "#/$defs/SourceInfo" }
279
298
  }
280
299
  },
281
- "SourceInfo": {
300
+ "RelativeConstraint": {
282
301
  "type": "object",
283
- "required": ["range"],
302
+ "additionalProperties": false,
303
+ "required": ["id", "kind", "subject", "relation", "target"],
284
304
  "properties": {
285
- "range": { "$ref": "#/$defs/SourceRange" },
286
- "leadingComments": {
305
+ "id": { "$ref": "#/$defs/Identifier" },
306
+ "kind": { "const": "relative" },
307
+ "strength": { "type": "string", "enum": ["required", "preferred"], "default": "required" },
308
+ "sourceInfo": { "$ref": "#/$defs/SourceInfo" },
309
+ "subject": { "$ref": "#/$defs/ConstraintNodeReference" },
310
+ "relation": { "type": "string", "enum": ["above", "below", "left-of", "right-of"] },
311
+ "target": { "$ref": "#/$defs/ConstraintNodeReference" },
312
+ "gap": { "type": "number", "minimum": 0, "default": 0 },
313
+ "alignment": { "type": "string", "enum": ["start", "center", "end"], "default": "center" }
314
+ }
315
+ },
316
+ "BoundaryConstraint": {
317
+ "type": "object",
318
+ "additionalProperties": false,
319
+ "required": ["id", "kind", "subject", "side", "scope"],
320
+ "properties": {
321
+ "id": { "$ref": "#/$defs/Identifier" },
322
+ "kind": { "const": "boundary" },
323
+ "strength": { "type": "string", "enum": ["required", "preferred"], "default": "required" },
324
+ "sourceInfo": { "$ref": "#/$defs/SourceInfo" },
325
+ "subject": { "$ref": "#/$defs/ConstraintNodeReference" },
326
+ "side": { "type": "string", "enum": ["top", "bottom", "left", "right"] },
327
+ "scope": { "$ref": "#/$defs/BoundaryScope" },
328
+ "inset": { "type": "number", "minimum": 0, "default": 0 }
329
+ }
330
+ },
331
+ "ArrangementConstraint": {
332
+ "type": "object",
333
+ "additionalProperties": false,
334
+ "required": ["id", "kind", "subjects", "axis"],
335
+ "properties": {
336
+ "id": { "$ref": "#/$defs/Identifier" },
337
+ "kind": { "const": "arrangement" },
338
+ "strength": { "type": "string", "enum": ["required", "preferred"], "default": "required" },
339
+ "sourceInfo": { "$ref": "#/$defs/SourceInfo" },
340
+ "subjects": {
287
341
  "type": "array",
288
- "items": { "$ref": "#/$defs/Comment" }
289
- },
290
- "trailingComment": { "$ref": "#/$defs/Comment" },
291
- "leadingWhitespace": { "type": "string" },
292
- "modified": { "type": "boolean" },
293
- "originalText": { "type": "string" }
342
+ "minItems": 2,
343
+ "uniqueItems": true,
344
+ "items": { "$ref": "#/$defs/ConstraintNodeReference" }
345
+ },
346
+ "axis": { "type": "string", "enum": ["row", "column"] },
347
+ "direction": { "type": "string", "enum": ["forward", "reverse"], "default": "forward" },
348
+ "gap": { "type": "number", "minimum": 0, "default": 0 },
349
+ "alignment": { "type": "string", "enum": ["start", "center", "end"], "default": "center" }
350
+ }
351
+ },
352
+ "SpatialConstraint": {
353
+ "oneOf": [
354
+ { "$ref": "#/$defs/RelativeConstraint" },
355
+ { "$ref": "#/$defs/BoundaryConstraint" },
356
+ { "$ref": "#/$defs/ArrangementConstraint" }
357
+ ]
358
+ },
359
+ "SourcePosition": {
360
+ "type": "object",
361
+ "additionalProperties": false,
362
+ "required": ["line", "column"],
363
+ "properties": {
364
+ "line": { "type": "integer", "minimum": 0 },
365
+ "column": { "type": "integer", "minimum": 0 }
294
366
  }
295
367
  },
296
368
  "SourceRange": {
297
369
  "type": "object",
370
+ "additionalProperties": false,
298
371
  "required": ["start", "end"],
299
372
  "properties": {
300
373
  "start": { "type": "integer", "minimum": 0 },
301
374
  "end": { "type": "integer", "minimum": 0 },
302
- "startPosition": {
303
- "type": "object",
304
- "required": ["line", "column"],
305
- "properties": {
306
- "line": { "type": "integer", "minimum": 0 },
307
- "column": { "type": "integer", "minimum": 0 }
308
- }
309
- },
310
- "endPosition": {
311
- "type": "object",
312
- "required": ["line", "column"],
313
- "properties": {
314
- "line": { "type": "integer", "minimum": 0 },
315
- "column": { "type": "integer", "minimum": 0 }
316
- }
317
- }
375
+ "startPosition": { "$ref": "#/$defs/SourcePosition" },
376
+ "endPosition": { "$ref": "#/$defs/SourcePosition" }
318
377
  }
319
378
  },
320
379
  "Comment": {
321
380
  "type": "object",
381
+ "additionalProperties": false,
322
382
  "required": ["text", "style"],
323
383
  "properties": {
324
384
  "text": { "type": "string" },
325
- "style": {
326
- "type": "string",
327
- "enum": ["line", "block"]
328
- },
385
+ "style": { "type": "string", "enum": ["line", "block"] },
329
386
  "range": { "$ref": "#/$defs/SourceRange" }
330
387
  }
331
388
  },
389
+ "SourceInfo": {
390
+ "type": "object",
391
+ "additionalProperties": false,
392
+ "required": ["range"],
393
+ "properties": {
394
+ "range": { "$ref": "#/$defs/SourceRange" },
395
+ "leadingComments": { "type": "array", "items": { "$ref": "#/$defs/Comment" } },
396
+ "trailingComment": { "$ref": "#/$defs/Comment" },
397
+ "leadingWhitespace": { "type": "string" },
398
+ "modified": { "type": "boolean" },
399
+ "originalText": { "type": "string" }
400
+ }
401
+ },
332
402
  "GraphMetadata": {
333
403
  "type": "object",
404
+ "additionalProperties": false,
334
405
  "properties": {
335
406
  "author": { "type": "string" },
336
- "created": {
337
- "type": "string",
338
- "format": "date-time"
339
- },
340
- "modified": {
341
- "type": "string",
342
- "format": "date-time"
343
- },
407
+ "created": { "type": "string", "format": "date-time" },
408
+ "modified": { "type": "string", "format": "date-time" },
344
409
  "description": { "type": "string" },
345
- "tags": {
346
- "type": "array",
347
- "items": { "type": "string" }
348
- },
349
- "notation": {
350
- "type": "string",
351
- "description": "Notation used by the graph, such as flowchart or ERD"
352
- },
353
- "custom": {
354
- "type": "object",
355
- "additionalProperties": true
356
- }
410
+ "tags": { "type": "array", "items": { "type": "string" } },
411
+ "notation": { "type": "string" },
412
+ "custom": { "type": "object", "additionalProperties": true }
357
413
  }
358
414
  }
359
415
  }