yarramate 1.21.0 → 1.22.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.
@@ -110,15 +110,28 @@ export declare function nestingTree(edges: readonly FoldEdge[], nesting: readonl
110
110
  /**
111
111
  * The containment tree: what a view nests, plus what a pattern owns.
112
112
  *
113
- * A slot member joins the tree only when all three hold, and each condition is
114
- * a different way of getting the answer wrong:
113
+ * A slot member joins the tree only when all of these hold, and each condition
114
+ * is a different way of getting the answer wrong:
115
115
  *
116
- * - **Exclusive.** A subject bound into two instances has two owners, and a
117
- * single-parent tree would silently pick one. Shared subjects stay outside.
118
- * - **`owned` or `unwired`, never `context`.** A context slot names something
119
- * the instance USES and does not contain the upstream API it calls, the
120
- * plane it runs on. Folding those would swallow half the landscape into
121
- * whichever box happened to reference it.
116
+ * - **Held inside one box.** A member's HOLDERS are every instance whose slots
117
+ * name it. One holder puts the member in that holder. Several put it in their
118
+ * lowest common ancestor, which is the level at which the holders diverge and
119
+ * therefore the innermost box that contains all of them. Holders with no
120
+ * common ancestor leave the member outside, because there is no one box it
121
+ * sits within and a single-parent tree would have to pick.
122
+ *
123
+ * This AMENDS ADR 0143's "Exclusive" rule, which kept every shared subject
124
+ * outside (#473 phase 3, ADR 0145, Nabeel's decision of 2026-09-05). The
125
+ * original reasoning was that two owners force a silent choice; it is only
126
+ * true when the owners sit in different boxes. Where both already sit under
127
+ * one box there is nothing to choose, and the old rule left 14 of the
128
+ * reference Landscape's 30 data objects outside the single application whose
129
+ * own parts were the things binding them.
130
+ * - **`owned` or `unwired`, never `context` alone.** A context slot names
131
+ * something the instance USES and does not contain — the upstream API it
132
+ * calls, the plane it runs on. Folding those would swallow half the landscape
133
+ * into whichever box happened to reference it. At least one binding must be
134
+ * `owned` or `unwired` for the member to fold at all.
122
135
  * - **Not a ruling.** See {@link RULING_CORE_KINDS}.
123
136
  *
124
137
  * A view's own nesting wins where both apply: the view is the more specific
package/dist/fold-tree.js CHANGED
@@ -127,6 +127,18 @@ export function nestingTree(edges, nesting, coreKindOf) {
127
127
  * a straight-line ancestor of a cycle is still validly nested under its own
128
128
  * non-cyclic parent. Mutates `parentOf` and returns what it removed.
129
129
  */
130
+ /** Whether `id` sits anywhere inside `ancestor` in the tree built so far. */
131
+ const isDescendantOf = (id, ancestor, parentOf) => {
132
+ const seen = new Set([id]);
133
+ let current = parentOf.get(id);
134
+ while (current !== undefined && !seen.has(current)) {
135
+ if (current === ancestor)
136
+ return true;
137
+ seen.add(current);
138
+ current = parentOf.get(current);
139
+ }
140
+ return false;
141
+ };
130
142
  function unnestCycles(parentOf) {
131
143
  const cycleMembers = new Set();
132
144
  for (const start of parentOf.keys()) {
@@ -149,18 +161,59 @@ function unnestCycles(parentOf) {
149
161
  parentOf.delete(id);
150
162
  return [...cycleMembers];
151
163
  }
164
+ /**
165
+ * The lowest node that contains every one of `ids`, counting each id as an
166
+ * ancestor of itself, or `undefined` when they do not share one.
167
+ *
168
+ * "Counting each id as an ancestor of itself" is the part that matters: where
169
+ * one holder already sits inside another, the answer is the outer holder rather
170
+ * than something above them both.
171
+ */
172
+ const lowestCommonAncestor = (ids, parentOf) => {
173
+ const chainOf = (id) => {
174
+ const chain = [];
175
+ const seen = new Set();
176
+ let current = id;
177
+ while (current !== undefined && !seen.has(current)) {
178
+ seen.add(current);
179
+ chain.push(current);
180
+ current = parentOf.get(current);
181
+ }
182
+ return chain;
183
+ };
184
+ const [first, ...rest] = ids;
185
+ if (first === undefined)
186
+ return undefined;
187
+ const others = rest.map((id) => new Set(chainOf(id)));
188
+ // Walking the first chain from the node OUTWARDS makes the first hit the
189
+ // lowest by construction.
190
+ return chainOf(first).find((candidate) => others.every((chain) => chain.has(candidate)));
191
+ };
152
192
  /**
153
193
  * The containment tree: what a view nests, plus what a pattern owns.
154
194
  *
155
- * A slot member joins the tree only when all three hold, and each condition is
156
- * a different way of getting the answer wrong:
195
+ * A slot member joins the tree only when all of these hold, and each condition
196
+ * is a different way of getting the answer wrong:
157
197
  *
158
- * - **Exclusive.** A subject bound into two instances has two owners, and a
159
- * single-parent tree would silently pick one. Shared subjects stay outside.
160
- * - **`owned` or `unwired`, never `context`.** A context slot names something
161
- * the instance USES and does not contain the upstream API it calls, the
162
- * plane it runs on. Folding those would swallow half the landscape into
163
- * whichever box happened to reference it.
198
+ * - **Held inside one box.** A member's HOLDERS are every instance whose slots
199
+ * name it. One holder puts the member in that holder. Several put it in their
200
+ * lowest common ancestor, which is the level at which the holders diverge and
201
+ * therefore the innermost box that contains all of them. Holders with no
202
+ * common ancestor leave the member outside, because there is no one box it
203
+ * sits within and a single-parent tree would have to pick.
204
+ *
205
+ * This AMENDS ADR 0143's "Exclusive" rule, which kept every shared subject
206
+ * outside (#473 phase 3, ADR 0145, Nabeel's decision of 2026-09-05). The
207
+ * original reasoning was that two owners force a silent choice; it is only
208
+ * true when the owners sit in different boxes. Where both already sit under
209
+ * one box there is nothing to choose, and the old rule left 14 of the
210
+ * reference Landscape's 30 data objects outside the single application whose
211
+ * own parts were the things binding them.
212
+ * - **`owned` or `unwired`, never `context` alone.** A context slot names
213
+ * something the instance USES and does not contain — the upstream API it
214
+ * calls, the plane it runs on. Folding those would swallow half the landscape
215
+ * into whichever box happened to reference it. At least one binding must be
216
+ * `owned` or `unwired` for the member to fold at all.
164
217
  * - **Not a ruling.** See {@link RULING_CORE_KINDS}.
165
218
  *
166
219
  * A view's own nesting wins where both apply: the view is the more specific
@@ -178,22 +231,64 @@ export function foldTree(input) {
178
231
  else
179
232
  instances.add(membership.instance);
180
233
  }
181
- const parentOf = new Map(fromNesting.parentOf);
234
+ // Whether ANY of a member's bindings is one the instance holds it out by. A
235
+ // member bound only through context slots never folds, however many hold it.
236
+ const heldOutSomewhere = new Set();
182
237
  for (const membership of input.memberships) {
183
- if (parentOf.has(membership.member))
184
- continue;
185
- if ((instancesOf.get(membership.member)?.size ?? 0) !== 1)
186
- continue;
187
- if (membership.wiring === 'context')
188
- continue;
189
- if (RULING_CORE_KINDS.has(coreKindOf(membership.member)))
190
- continue;
191
- // A node the input does not carry cannot be drawn inside anything.
192
- if (!coreKindById.has(membership.member))
193
- continue;
194
- if (membership.member === membership.instance)
195
- continue;
196
- parentOf.set(membership.member, membership.instance);
238
+ if (membership.wiring !== 'context')
239
+ heldOutSomewhere.add(membership.member);
240
+ }
241
+ const parentOf = new Map(fromNesting.parentOf);
242
+ const candidates = [
243
+ ...new Set(input.memberships
244
+ .map(({ member }) => member)
245
+ .filter((member) =>
246
+ // A view's own nesting already placed it, and the view wins.
247
+ !parentOf.has(member) &&
248
+ heldOutSomewhere.has(member) &&
249
+ !RULING_CORE_KINDS.has(coreKindOf(member)) &&
250
+ // A node the input does not carry cannot be drawn inside anything.
251
+ coreKindById.has(member) &&
252
+ // Something that holds itself is not held by anything.
253
+ instancesOf.get(member)?.has(member) !== true)),
254
+ ];
255
+ // Resolved in ROUNDS rather than one pass, because a member's holders may
256
+ // themselves be members whose own parents are decided here. Placing a member
257
+ // before its holders are settled would measure the lowest common ancestor
258
+ // against a tree that is still missing the levels that separate them, and the
259
+ // reference has five-deep chains (spec, mapping, call, client, application),
260
+ // so this is exercised rather than theoretical.
261
+ //
262
+ // A member is settled once it is placed or once it is known to stay outside.
263
+ // Whatever a round cannot decide it hands to the next; when a round decides
264
+ // nothing, what is left is a mutual dependency and stays outside, which is the
265
+ // same answer the cycle guard below would reach for it anyway.
266
+ let pending = candidates;
267
+ while (pending.length > 0) {
268
+ const deferred = [];
269
+ let decided = false;
270
+ for (const member of pending) {
271
+ const holders = [...(instancesOf.get(member) ?? [])];
272
+ if (holders.some((holder) => pending.includes(holder) && holder !== member)) {
273
+ deferred.push(member);
274
+ continue;
275
+ }
276
+ decided = true;
277
+ const parent = holders.length === 1
278
+ ? holders[0]
279
+ : lowestCommonAncestor(holders, parentOf);
280
+ if (parent === undefined || parent === member)
281
+ continue;
282
+ // A member that already contains one of its holders cannot also sit
283
+ // inside it. The cycle guard below is the backstop, not the rule.
284
+ if (holders.some((holder) => isDescendantOf(holder, member, parentOf))) {
285
+ continue;
286
+ }
287
+ parentOf.set(member, parent);
288
+ }
289
+ if (!decided)
290
+ break;
291
+ pending = deferred;
197
292
  }
198
293
  // Slot membership can close a loop the view's nesting alone did not, so the
199
294
  // guard runs again over the combined tree rather than trusting the first.
@@ -78,6 +78,17 @@ export interface ProjectionDefinition {
78
78
  readonly showLifecycle?: boolean;
79
79
  readonly showEvidence?: boolean;
80
80
  readonly showOwnership?: boolean;
81
+ /**
82
+ * Whether a bound RULING draws as a row inside its holder rather than as a
83
+ * node of its own (#473 phase 3, ADR 0145).
84
+ *
85
+ * On the reference this takes the whole model from 173 boxes to 91, because
86
+ * 82 of its rulings are bound into slots and every one of them was drawing
87
+ * as a box with a single association edge. Presentation only: the model,
88
+ * the query and the selected set do not move, and turning it off restores
89
+ * the boxes.
90
+ */
91
+ readonly showConstraints?: boolean;
81
92
  /**
82
93
  * The folder this view files itself under in an editor's rail: a label the
83
94
  * author declares, nested with `/`, never the directory the projection
@@ -66,6 +66,7 @@ export function canonicalProjection(projection) {
66
66
  ...(presentation.showLifecycle === undefined ? {} : { showLifecycle: presentation.showLifecycle }),
67
67
  ...(presentation.showEvidence === undefined ? {} : { showEvidence: presentation.showEvidence }),
68
68
  ...(presentation.showOwnership === undefined ? {} : { showOwnership: presentation.showOwnership }),
69
+ ...(presentation.showConstraints === undefined ? {} : { showConstraints: presentation.showConstraints }),
69
70
  ...(presentation.notation === undefined ? {} : { notation: presentation.notation }),
70
71
  },
71
72
  }),
@@ -631,6 +632,9 @@ export function evaluateProjection(graph, projection, profileContext, membership
631
632
  ...(projection.presentation.showOwnership === undefined
632
633
  ? {}
633
634
  : { showOwnership: projection.presentation.showOwnership }),
635
+ ...(projection.presentation.showConstraints === undefined
636
+ ? {}
637
+ : { showConstraints: projection.presentation.showConstraints }),
634
638
  ...(projection.presentation.notation === undefined
635
639
  ? {}
636
640
  : { notation: projection.presentation.notation }),
@@ -9,7 +9,7 @@
9
9
  // file and not a runtime one; the two pure helpers imported below are
10
10
  // all the runtime still takes from ajv.
11
11
  //
12
- // schema/ sha256: 71358391c82518d840a0bc538999ea67063aa97e7093f7ca099155f57c44abba
12
+ // schema/ sha256: cc9263e2df972b9fbeb51dd1e2572396c633aaa2b7eb74f0a70e82f7063ce0d4
13
13
  import ajvRuntime0Module from 'ajv/dist/runtime/ucs2length.js';
14
14
  const ajvRuntime0 = ajvRuntime0Module.default ?? ajvRuntime0Module;
15
15
  import ajvRuntime1Module from 'ajv/dist/runtime/equal.js';
@@ -4476,7 +4476,7 @@ else {
4476
4476
  } validate61.errors = vErrors; return errors === 0; }
4477
4477
  validate61.evaluated = { "props": true, "dynamicProps": false, "dynamicItems": false };
4478
4478
  export const validateProjection = validate62;
4479
- const schema113 = { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://yarramate.org/schema/projection/v1", "title": "YarraMate semantic projection", "type": "object", "additionalProperties": false, "required": ["format", "id", "version", "query"], "properties": { "format": { "const": "yarramate/projection/v1" }, "id": { "$ref": "#/$defs/id" }, "version": { "type": "string", "pattern": "^[0-9]+\\.[0-9]+$" }, "query": { "$ref": "#/$defs/query" }, "presentation": { "$ref": "#/$defs/presentation" } }, "$defs": { "query": { "type": "object", "additionalProperties": false, "properties": { "subjects": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "$ref": "#/$defs/subjectIdentity" } }, "instances": { "description": "Pattern instances whose CONTENTS this query selects (#473, ADR 0144). Each id names an instance, and the facet selects that instance together with everything the fold tree would draw inside it: the same closure `presentation.fold: \"instances\"` collapses into one box, read through this view's own `nesting`. This is the one facet that ADDS rather than narrows. `subjects` and `instances` are a single identity facet spelled two ways and their values combine with OR, while every other field still ANDs over the union. Naming the instance rather than hand-listing its members is what keeps a view from going stale the next time the pattern binds a slot. An id that names nothing is refused (YM921); one that names a subject which is not a pattern instance is refused separately (YM922), because a typo and a category error send an author to different places.", "type": "array", "minItems": 1, "uniqueItems": true, "items": { "$ref": "#/$defs/subjectIdentity" } }, "exclude": { "description": "Subjects this query would otherwise select and the author has taken out: the exception a rule cannot state (#267, ADR 0122). Applied after every other facet and after relationship expansion, so an excluded subject is out whichever way it would have come back in. Naming a subject no facet selects is allowed and inert until the model grows into the rule.", "type": "array", "minItems": 1, "uniqueItems": true, "items": { "$ref": "#/$defs/subjectIdentity" } }, "documents": { "type": "array", "uniqueItems": true, "items": { "$ref": "#/$defs/id" } }, "kinds": { "type": "array", "uniqueItems": true, "items": { "$ref": "#/$defs/qualifiedKind" } }, "layers": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "$ref": "#/$defs/layer" } }, "statuses": { "type": "array", "uniqueItems": true, "items": { "enum": ["planned", "current", "retired"] } }, "excludeStatuses": { "description": "Drop concepts carrying one of these lifecycle statuses while keeping concepts that declare no status at all - 'everything except retired' for viewpoint projections, where a bare statuses filter would wrongly drop unstatused actors and motivation elements.", "type": "array", "uniqueItems": true, "items": { "enum": ["planned", "current", "retired"] } }, "states": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "$ref": "#/$defs/subjectIdentity" } }, "owners": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "$ref": "#/$defs/subjectIdentity" } }, "constraints": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "$ref": "#/$defs/subjectIdentity" } }, "relationshipKinds": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "$ref": "#/$defs/qualifiedKind" } }, "kindMatching": { "enum": ["exact", "descendants"] }, "relationships": { "enum": ["between", "connected", "none"] }, "isolatedConcepts": { "enum": ["include", "exclude"] } } }, "presentation": { "type": "object", "additionalProperties": false, "properties": { "title": { "$ref": "#/$defs/nonEmptyText" }, "description": { "$ref": "#/$defs/nonEmptyText" }, "layout": { "enum": ["layered"] }, "direction": { "enum": ["top-down", "left-right"] }, "nesting": { "type": "array", "uniqueItems": true, "items": { "enum": ["composition", "assignment"] } }, "fold": { "description": "Whether this view draws pattern instances FOLDED by default (#473). \"instances\" collapses every instance to a single node carrying its members, with the edges into and out of them lifted onto the box; \"none\", the default, draws everything. A reader opens what they want, so this says where to START rather than what may be seen. Folding reads the same containment tree nesting does, so a view declaring fold without \"assignment\" in nesting collapses less than its author probably expects; the editor says so rather than the loader refusing it, because a diagnostic has no warning severity and this is not an error.", "enum": ["instances", "none"] }, "showLifecycle": { "type": "boolean" }, "showEvidence": { "type": "boolean" }, "showOwnership": { "type": "boolean" }, "notation": { "enum": ["archimate"] }, "folder": { "type": "string", "description": "The folder this view files itself under in an editor's rail. A LABEL the author declares, never the directory the projection sits in: nest with '/' separators, and the filesystem is never consulted (ADR 0104).", "pattern": "^[^/]+(?:/[^/]+)*$", "minLength": 1 } } }, "id": { "type": "string", "pattern": "^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$" }, "qualifiedKind": { "type": "string", "pattern": "^[a-z][a-z0-9-]*(?:/[a-z][a-z0-9-]*)+@[0-9]+\\.[0-9]+#[a-z][A-Za-z0-9-]*$" }, "subjectIdentity": { "type": "string", "pattern": "^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$" }, "nonEmptyText": { "type": "string", "minLength": 1 }, "layer": { "enum": ["motivation", "strategy", "business", "application", "technology", "physical", "implementation", "composite"] } } };
4479
+ const schema113 = { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://yarramate.org/schema/projection/v1", "title": "YarraMate semantic projection", "type": "object", "additionalProperties": false, "required": ["format", "id", "version", "query"], "properties": { "format": { "const": "yarramate/projection/v1" }, "id": { "$ref": "#/$defs/id" }, "version": { "type": "string", "pattern": "^[0-9]+\\.[0-9]+$" }, "query": { "$ref": "#/$defs/query" }, "presentation": { "$ref": "#/$defs/presentation" } }, "$defs": { "query": { "type": "object", "additionalProperties": false, "properties": { "subjects": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "$ref": "#/$defs/subjectIdentity" } }, "instances": { "description": "Pattern instances whose CONTENTS this query selects (#473, ADR 0144). Each id names an instance, and the facet selects that instance together with everything the fold tree would draw inside it: the same closure `presentation.fold: \"instances\"` collapses into one box, read through this view's own `nesting`. This is the one facet that ADDS rather than narrows. `subjects` and `instances` are a single identity facet spelled two ways and their values combine with OR, while every other field still ANDs over the union. Naming the instance rather than hand-listing its members is what keeps a view from going stale the next time the pattern binds a slot. An id that names nothing is refused (YM921); one that names a subject which is not a pattern instance is refused separately (YM922), because a typo and a category error send an author to different places.", "type": "array", "minItems": 1, "uniqueItems": true, "items": { "$ref": "#/$defs/subjectIdentity" } }, "exclude": { "description": "Subjects this query would otherwise select and the author has taken out: the exception a rule cannot state (#267, ADR 0122). Applied after every other facet and after relationship expansion, so an excluded subject is out whichever way it would have come back in. Naming a subject no facet selects is allowed and inert until the model grows into the rule.", "type": "array", "minItems": 1, "uniqueItems": true, "items": { "$ref": "#/$defs/subjectIdentity" } }, "documents": { "type": "array", "uniqueItems": true, "items": { "$ref": "#/$defs/id" } }, "kinds": { "type": "array", "uniqueItems": true, "items": { "$ref": "#/$defs/qualifiedKind" } }, "layers": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "$ref": "#/$defs/layer" } }, "statuses": { "type": "array", "uniqueItems": true, "items": { "enum": ["planned", "current", "retired"] } }, "excludeStatuses": { "description": "Drop concepts carrying one of these lifecycle statuses while keeping concepts that declare no status at all - 'everything except retired' for viewpoint projections, where a bare statuses filter would wrongly drop unstatused actors and motivation elements.", "type": "array", "uniqueItems": true, "items": { "enum": ["planned", "current", "retired"] } }, "states": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "$ref": "#/$defs/subjectIdentity" } }, "owners": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "$ref": "#/$defs/subjectIdentity" } }, "constraints": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "$ref": "#/$defs/subjectIdentity" } }, "relationshipKinds": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "$ref": "#/$defs/qualifiedKind" } }, "kindMatching": { "enum": ["exact", "descendants"] }, "relationships": { "enum": ["between", "connected", "none"] }, "isolatedConcepts": { "enum": ["include", "exclude"] } } }, "presentation": { "type": "object", "additionalProperties": false, "properties": { "title": { "$ref": "#/$defs/nonEmptyText" }, "description": { "$ref": "#/$defs/nonEmptyText" }, "layout": { "enum": ["layered"] }, "direction": { "enum": ["top-down", "left-right"] }, "nesting": { "type": "array", "uniqueItems": true, "items": { "enum": ["composition", "assignment"] } }, "fold": { "description": "Whether this view draws pattern instances FOLDED by default (#473). \"instances\" collapses every instance to a single node carrying its members, with the edges into and out of them lifted onto the box; \"none\", the default, draws everything. A reader opens what they want, so this says where to START rather than what may be seen. Folding reads the same containment tree nesting does, so a view declaring fold without \"assignment\" in nesting collapses less than its author probably expects; the editor says so rather than the loader refusing it, because a diagnostic has no warning severity and this is not an error.", "enum": ["instances", "none"] }, "showLifecycle": { "type": "boolean" }, "showEvidence": { "type": "boolean" }, "showOwnership": { "type": "boolean" }, "showConstraints": { "description": "Whether this view draws a bound RULING as a row inside the instance that holds it rather than as a node of its own (#473 phase 3, ADR 0145). A constraint filling an unwired slot of a visible instance becomes a line in that instance's label block, carrying its slot, its name and its RULER, and its association edge to the owner is hidden with it. Constraints nothing binds stay nodes: a requirement with no holder has no box to sit in. Presentation only, exactly like the three toggles above it: the model, the query and the selected set are identical either way, and a reader turns it off to get the boxes back.", "type": "boolean" }, "notation": { "enum": ["archimate"] }, "folder": { "type": "string", "description": "The folder this view files itself under in an editor's rail. A LABEL the author declares, never the directory the projection sits in: nest with '/' separators, and the filesystem is never consulted (ADR 0104).", "pattern": "^[^/]+(?:/[^/]+)*$", "minLength": 1 } } }, "id": { "type": "string", "pattern": "^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$" }, "qualifiedKind": { "type": "string", "pattern": "^[a-z][a-z0-9-]*(?:/[a-z][a-z0-9-]*)+@[0-9]+\\.[0-9]+#[a-z][A-Za-z0-9-]*$" }, "subjectIdentity": { "type": "string", "pattern": "^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$" }, "nonEmptyText": { "type": "string", "minLength": 1 }, "layer": { "enum": ["motivation", "strategy", "business", "application", "technology", "physical", "implementation", "composite"] } } };
4480
4480
  const schema114 = { "type": "string", "pattern": "^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$" };
4481
4481
  const schema115 = { "type": "object", "additionalProperties": false, "properties": { "subjects": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "$ref": "#/$defs/subjectIdentity" } }, "instances": { "description": "Pattern instances whose CONTENTS this query selects (#473, ADR 0144). Each id names an instance, and the facet selects that instance together with everything the fold tree would draw inside it: the same closure `presentation.fold: \"instances\"` collapses into one box, read through this view's own `nesting`. This is the one facet that ADDS rather than narrows. `subjects` and `instances` are a single identity facet spelled two ways and their values combine with OR, while every other field still ANDs over the union. Naming the instance rather than hand-listing its members is what keeps a view from going stale the next time the pattern binds a slot. An id that names nothing is refused (YM921); one that names a subject which is not a pattern instance is refused separately (YM922), because a typo and a category error send an author to different places.", "type": "array", "minItems": 1, "uniqueItems": true, "items": { "$ref": "#/$defs/subjectIdentity" } }, "exclude": { "description": "Subjects this query would otherwise select and the author has taken out: the exception a rule cannot state (#267, ADR 0122). Applied after every other facet and after relationship expansion, so an excluded subject is out whichever way it would have come back in. Naming a subject no facet selects is allowed and inert until the model grows into the rule.", "type": "array", "minItems": 1, "uniqueItems": true, "items": { "$ref": "#/$defs/subjectIdentity" } }, "documents": { "type": "array", "uniqueItems": true, "items": { "$ref": "#/$defs/id" } }, "kinds": { "type": "array", "uniqueItems": true, "items": { "$ref": "#/$defs/qualifiedKind" } }, "layers": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "$ref": "#/$defs/layer" } }, "statuses": { "type": "array", "uniqueItems": true, "items": { "enum": ["planned", "current", "retired"] } }, "excludeStatuses": { "description": "Drop concepts carrying one of these lifecycle statuses while keeping concepts that declare no status at all - 'everything except retired' for viewpoint projections, where a bare statuses filter would wrongly drop unstatused actors and motivation elements.", "type": "array", "uniqueItems": true, "items": { "enum": ["planned", "current", "retired"] } }, "states": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "$ref": "#/$defs/subjectIdentity" } }, "owners": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "$ref": "#/$defs/subjectIdentity" } }, "constraints": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "$ref": "#/$defs/subjectIdentity" } }, "relationshipKinds": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "$ref": "#/$defs/qualifiedKind" } }, "kindMatching": { "enum": ["exact", "descendants"] }, "relationships": { "enum": ["between", "connected", "none"] }, "isolatedConcepts": { "enum": ["include", "exclude"] } } };
4482
4482
  const schema116 = { "type": "string", "pattern": "^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$" };
@@ -5314,7 +5314,7 @@ else {
5314
5314
  errors++;
5315
5315
  } validate63.errors = vErrors; return errors === 0; }
5316
5316
  validate63.evaluated = { "props": true, "dynamicProps": false, "dynamicItems": false };
5317
- const schema126 = { "type": "object", "additionalProperties": false, "properties": { "title": { "$ref": "#/$defs/nonEmptyText" }, "description": { "$ref": "#/$defs/nonEmptyText" }, "layout": { "enum": ["layered"] }, "direction": { "enum": ["top-down", "left-right"] }, "nesting": { "type": "array", "uniqueItems": true, "items": { "enum": ["composition", "assignment"] } }, "fold": { "description": "Whether this view draws pattern instances FOLDED by default (#473). \"instances\" collapses every instance to a single node carrying its members, with the edges into and out of them lifted onto the box; \"none\", the default, draws everything. A reader opens what they want, so this says where to START rather than what may be seen. Folding reads the same containment tree nesting does, so a view declaring fold without \"assignment\" in nesting collapses less than its author probably expects; the editor says so rather than the loader refusing it, because a diagnostic has no warning severity and this is not an error.", "enum": ["instances", "none"] }, "showLifecycle": { "type": "boolean" }, "showEvidence": { "type": "boolean" }, "showOwnership": { "type": "boolean" }, "notation": { "enum": ["archimate"] }, "folder": { "type": "string", "description": "The folder this view files itself under in an editor's rail. A LABEL the author declares, never the directory the projection sits in: nest with '/' separators, and the filesystem is never consulted (ADR 0104).", "pattern": "^[^/]+(?:/[^/]+)*$", "minLength": 1 } } };
5317
+ const schema126 = { "type": "object", "additionalProperties": false, "properties": { "title": { "$ref": "#/$defs/nonEmptyText" }, "description": { "$ref": "#/$defs/nonEmptyText" }, "layout": { "enum": ["layered"] }, "direction": { "enum": ["top-down", "left-right"] }, "nesting": { "type": "array", "uniqueItems": true, "items": { "enum": ["composition", "assignment"] } }, "fold": { "description": "Whether this view draws pattern instances FOLDED by default (#473). \"instances\" collapses every instance to a single node carrying its members, with the edges into and out of them lifted onto the box; \"none\", the default, draws everything. A reader opens what they want, so this says where to START rather than what may be seen. Folding reads the same containment tree nesting does, so a view declaring fold without \"assignment\" in nesting collapses less than its author probably expects; the editor says so rather than the loader refusing it, because a diagnostic has no warning severity and this is not an error.", "enum": ["instances", "none"] }, "showLifecycle": { "type": "boolean" }, "showEvidence": { "type": "boolean" }, "showOwnership": { "type": "boolean" }, "showConstraints": { "description": "Whether this view draws a bound RULING as a row inside the instance that holds it rather than as a node of its own (#473 phase 3, ADR 0145). A constraint filling an unwired slot of a visible instance becomes a line in that instance's label block, carrying its slot, its name and its RULER, and its association edge to the owner is hidden with it. Constraints nothing binds stay nodes: a requirement with no holder has no box to sit in. Presentation only, exactly like the three toggles above it: the model, the query and the selected set are identical either way, and a reader turns it off to get the boxes back.", "type": "boolean" }, "notation": { "enum": ["archimate"] }, "folder": { "type": "string", "description": "The folder this view files itself under in an editor's rail. A LABEL the author declares, never the directory the projection sits in: nest with '/' separators, and the filesystem is never consulted (ADR 0104).", "pattern": "^[^/]+(?:/[^/]+)*$", "minLength": 1 } } };
5318
5318
  const schema127 = { "type": "string", "minLength": 1 };
5319
5319
  function validate65(data, { instancePath = "", parentData, parentDataProperty, rootData = data, dynamicAnchors = {} } = {}) { let vErrors = null; let errors = 0; const evaluated0 = validate65.evaluated; if (evaluated0.dynamicProps) {
5320
5320
  evaluated0.props = undefined;
@@ -5505,9 +5505,9 @@ function validate65(data, { instancePath = "", parentData, parentDataProperty, r
5505
5505
  errors++;
5506
5506
  }
5507
5507
  }
5508
- if (data.notation !== undefined) {
5509
- if (!(data.notation === "archimate")) {
5510
- const err14 = { instancePath: instancePath + "/notation", schemaPath: "#/properties/notation/enum", keyword: "enum", params: { allowedValues: schema126.properties.notation.enum }, message: "must be equal to one of the allowed values" };
5508
+ if (data.showConstraints !== undefined) {
5509
+ if (typeof data.showConstraints !== "boolean") {
5510
+ const err14 = { instancePath: instancePath + "/showConstraints", schemaPath: "#/properties/showConstraints/type", keyword: "type", params: { type: "boolean" }, message: "must be boolean" };
5511
5511
  if (vErrors === null) {
5512
5512
  vErrors = [err14];
5513
5513
  }
@@ -5517,49 +5517,61 @@ function validate65(data, { instancePath = "", parentData, parentDataProperty, r
5517
5517
  errors++;
5518
5518
  }
5519
5519
  }
5520
+ if (data.notation !== undefined) {
5521
+ if (!(data.notation === "archimate")) {
5522
+ const err15 = { instancePath: instancePath + "/notation", schemaPath: "#/properties/notation/enum", keyword: "enum", params: { allowedValues: schema126.properties.notation.enum }, message: "must be equal to one of the allowed values" };
5523
+ if (vErrors === null) {
5524
+ vErrors = [err15];
5525
+ }
5526
+ else {
5527
+ vErrors.push(err15);
5528
+ }
5529
+ errors++;
5530
+ }
5531
+ }
5520
5532
  if (data.folder !== undefined) {
5521
- let data11 = data.folder;
5522
- if (typeof data11 === "string") {
5523
- if (func2(data11) < 1) {
5524
- const err15 = { instancePath: instancePath + "/folder", schemaPath: "#/properties/folder/minLength", keyword: "minLength", params: { limit: 1 }, message: "must NOT have fewer than 1 characters" };
5533
+ let data12 = data.folder;
5534
+ if (typeof data12 === "string") {
5535
+ if (func2(data12) < 1) {
5536
+ const err16 = { instancePath: instancePath + "/folder", schemaPath: "#/properties/folder/minLength", keyword: "minLength", params: { limit: 1 }, message: "must NOT have fewer than 1 characters" };
5525
5537
  if (vErrors === null) {
5526
- vErrors = [err15];
5538
+ vErrors = [err16];
5527
5539
  }
5528
5540
  else {
5529
- vErrors.push(err15);
5541
+ vErrors.push(err16);
5530
5542
  }
5531
5543
  errors++;
5532
5544
  }
5533
- if (!pattern15.test(data11)) {
5534
- const err16 = { instancePath: instancePath + "/folder", schemaPath: "#/properties/folder/pattern", keyword: "pattern", params: { pattern: "^[^/]+(?:/[^/]+)*$" }, message: "must match pattern \"" + "^[^/]+(?:/[^/]+)*$" + "\"" };
5545
+ if (!pattern15.test(data12)) {
5546
+ const err17 = { instancePath: instancePath + "/folder", schemaPath: "#/properties/folder/pattern", keyword: "pattern", params: { pattern: "^[^/]+(?:/[^/]+)*$" }, message: "must match pattern \"" + "^[^/]+(?:/[^/]+)*$" + "\"" };
5535
5547
  if (vErrors === null) {
5536
- vErrors = [err16];
5548
+ vErrors = [err17];
5537
5549
  }
5538
5550
  else {
5539
- vErrors.push(err16);
5551
+ vErrors.push(err17);
5540
5552
  }
5541
5553
  errors++;
5542
5554
  }
5543
5555
  }
5544
5556
  else {
5545
- const err17 = { instancePath: instancePath + "/folder", schemaPath: "#/properties/folder/type", keyword: "type", params: { type: "string" }, message: "must be string" };
5557
+ const err18 = { instancePath: instancePath + "/folder", schemaPath: "#/properties/folder/type", keyword: "type", params: { type: "string" }, message: "must be string" };
5546
5558
  if (vErrors === null) {
5547
- vErrors = [err17];
5559
+ vErrors = [err18];
5548
5560
  }
5549
5561
  else {
5550
- vErrors.push(err17);
5562
+ vErrors.push(err18);
5551
5563
  }
5552
5564
  errors++;
5553
5565
  }
5554
5566
  }
5555
5567
  }
5556
5568
  else {
5557
- const err18 = { instancePath, schemaPath: "#/type", keyword: "type", params: { type: "object" }, message: "must be object" };
5569
+ const err19 = { instancePath, schemaPath: "#/type", keyword: "type", params: { type: "object" }, message: "must be object" };
5558
5570
  if (vErrors === null) {
5559
- vErrors = [err18];
5571
+ vErrors = [err19];
5560
5572
  }
5561
5573
  else {
5562
- vErrors.push(err18);
5574
+ vErrors.push(err19);
5563
5575
  }
5564
5576
  errors++;
5565
5577
  } validate65.errors = vErrors; return errors === 0; }