@yahoo/uds-create-config 5.41.7 → 5.41.8

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.
@@ -6,7 +6,7 @@ import { applyPathDelta, isPlainObject, namedFields, pathSegments, sectionDelta,
6
6
  import { METADATA_KEYS, declaredField } from "./utils/field-schema.js";
7
7
  import { dataSchema, resolveInputSchema } from "./schemas.js";
8
8
  import { isComposedValue } from "../entities/system/composed-values.js";
9
- import { borrowedSlug, classifyOverlay } from "./source-integrity.js";
9
+ import { borrowedSlug, classifyOverlay, uniteEntries } from "./source-integrity.js";
10
10
  import { kindBorrowable, titleCase } from "./registry.js";
11
11
  import { isGroupBody } from "./utils/group.js";
12
12
  import { authoredBag, pinBodyStyleNumbers, stylePropNumberUnit } from "./projections.js";
@@ -6095,19 +6095,6 @@ function layerOverlay({ onto, patch, theirs, union }) {
6095
6095
  }
6096
6096
  return merged;
6097
6097
  }
6098
- /** A union that keeps the existing order and drops a repeat. Entries are refs and small literals, so
6099
- * identity is what they serialize to rather than reference equality. */
6100
- function uniteEntries(existing, added) {
6101
- const out = Array.isArray(existing) ? [...existing] : [];
6102
- const seen = new Set(out.map((entry) => JSON.stringify(entry)));
6103
- for (const entry of added) {
6104
- const key = JSON.stringify(entry);
6105
- if (seen.has(key)) continue;
6106
- seen.add(key);
6107
- out.push(entry);
6108
- }
6109
- return out;
6110
- }
6111
6098
  function derivedItemChange(kind, path, base, extend = {}) {
6112
6099
  return {
6113
6100
  kind,
@@ -117,6 +117,9 @@ interface MisdeclaredOverlay {
117
117
  declared: 'override' | 'extend';
118
118
  /** The field it was wrong about, addressed from the entity body as segments. */
119
119
  field: readonly string[];
120
+ /** For an `extend` of a list, the entries the list it lays onto already holds. The entries are what
121
+ * the extension is judged on, so a list the source defines is not wrong to extend. */
122
+ entries?: readonly unknown[];
120
123
  }
121
124
  /**
122
125
  * A leaf address: dotted, or spelled as segments where a member key can itself contain a dot (a
@@ -136,6 +139,9 @@ type OverlayVerb = 'override' | 'extend';
136
139
  * nothing local sits there or the two agree. A leaf carried along unchanged is not overlaid: a sub-op
137
140
  * copies the whole record it touched into the delta, so a token given one local condition holds the
138
141
  * source's other conditions beside it.
142
+ *
143
+ * A list is the one leaf with members. One that keeps all of theirs and adds to it is an `extend`,
144
+ * since that is what an `extend` of the added entries reads back as.
139
145
  */
140
146
  declare function leafVerb({
141
147
  ours,
@@ -162,6 +168,10 @@ declare function overlayVerb(overlay: LocalOverlay, field: LeafAddress): Overlay
162
168
  * Judged leaf by leaf, because one entity legitimately carries both — a token overridden under one
163
169
  * modifier and extended under another is one body with two verbs, and a whole-entity comparison would
164
170
  * have to call it one or the other.
171
+ *
172
+ * A list is judged by its entries: an `extend` of one the source defines adds to it, and is wrong only
173
+ * in the entries the list beneath already holds. That is the same moving source one level down — they
174
+ * added a value this config was extending with.
165
175
  */
166
176
  declare function misdeclaredOverlays(config: Config): MisdeclaredOverlay[];
167
177
  /**
@@ -243,17 +243,50 @@ function valueAt(body, field) {
243
243
  function isRuleCondition(address) {
244
244
  return address.length >= 3 && address[0] === "styles" && address[2] === "when";
245
245
  }
246
+ /** A list entry's identity. Entries are refs and small literals, so it is what they serialize to
247
+ * rather than reference equality. */
248
+ const entryKey = (entry) => JSON.stringify(entry);
249
+ /**
250
+ * A union that keeps the existing order and drops a repeat — what an `extend` of a list lays onto the
251
+ * list beneath it.
252
+ */
253
+ function uniteEntries(existing, added) {
254
+ const out = Array.isArray(existing) ? [...existing] : [];
255
+ const seen = new Set(out.map(entryKey));
256
+ for (const entry of added) {
257
+ const key = entryKey(entry);
258
+ if (seen.has(key)) continue;
259
+ seen.add(key);
260
+ out.push(entry);
261
+ }
262
+ return out;
263
+ }
264
+ /**
265
+ * The entries `ours` adds to `theirs`, where uniting them onto `theirs` gives back `ours` exactly —
266
+ * their list whole and in order, with ours after it. `undefined` where it doesn't: a list that drops
267
+ * or reorders one of theirs replaces it, and so does anything that isn't a list on both sides.
268
+ */
269
+ function addedEntries(ours, theirs) {
270
+ if (!Array.isArray(ours) || !Array.isArray(theirs)) return void 0;
271
+ const listed = new Set(theirs.map(entryKey));
272
+ const added = ours.filter((entry) => !listed.has(entryKey(entry)));
273
+ return sameValue(uniteEntries(theirs, added), ours) ? added : void 0;
274
+ }
246
275
  /**
247
276
  * The verb one local leaf is against the source's value at the same address: `extend` where the
248
277
  * source has nothing there, `override` where it has something different, and `undefined` where
249
278
  * nothing local sits there or the two agree. A leaf carried along unchanged is not overlaid: a sub-op
250
279
  * copies the whole record it touched into the delta, so a token given one local condition holds the
251
280
  * source's other conditions beside it.
281
+ *
282
+ * A list is the one leaf with members. One that keeps all of theirs and adds to it is an `extend`,
283
+ * since that is what an `extend` of the added entries reads back as.
252
284
  */
253
285
  function leafVerb({ ours, theirs }) {
254
286
  if (ours === void 0) return void 0;
255
287
  if (theirs === void 0) return "extend";
256
- return sameValue(ours, theirs) ? void 0 : "override";
288
+ if (sameValue(ours, theirs)) return void 0;
289
+ return addedEntries(ours, theirs)?.length ? "extend" : "override";
257
290
  }
258
291
  /**
259
292
  * Which verb this config's value at `field` is, in the pin's vocabulary — `override` where the source
@@ -286,6 +319,10 @@ function sameValue(a, b) {
286
319
  * Judged leaf by leaf, because one entity legitimately carries both — a token overridden under one
287
320
  * modifier and extended under another is one body with two verbs, and a whole-entity comparison would
288
321
  * have to call it one or the other.
322
+ *
323
+ * A list is judged by its entries: an `extend` of one the source defines adds to it, and is wrong only
324
+ * in the entries the list beneath already holds. That is the same moving source one level down — they
325
+ * added a value this config was extending with.
289
326
  */
290
327
  function misdeclaredOverlays(config) {
291
328
  const found = [];
@@ -299,7 +336,29 @@ function misdeclaredOverlays(config) {
299
336
  const theirs = source.resolve(kind, path)?.toJSON();
300
337
  for (const field of leafAddresses(overlay.extend)) {
301
338
  if (isRuleCondition(field)) continue;
302
- if (valueAt(theirs, field) !== void 0) found.push({
339
+ const defined = valueAt(theirs, field);
340
+ if (defined === void 0) continue;
341
+ const added = valueAt(overlay.extend, field);
342
+ if (Array.isArray(added) && Array.isArray(defined)) {
343
+ const replaced = valueAt(overlay.override, field);
344
+ const beneath = Array.isArray(replaced) ? replaced : valueAt(config.copyOf({
345
+ slug,
346
+ kind,
347
+ path
348
+ }), field);
349
+ const listed = new Set((Array.isArray(beneath) ? beneath : defined).map(entryKey));
350
+ const entries = added.filter((entry) => listed.has(entryKey(entry)));
351
+ if (entries.length > 0) found.push({
352
+ slug,
353
+ kind,
354
+ path,
355
+ declared: "extend",
356
+ field,
357
+ entries
358
+ });
359
+ continue;
360
+ }
361
+ found.push({
303
362
  slug,
304
363
  kind,
305
364
  path,
@@ -336,12 +395,16 @@ function classifyOverlay(local, theirs) {
336
395
  for (const [address, value] of leafEntries(local)) {
337
396
  if (address.length === 0) continue;
338
397
  if (isRuleCondition(address)) continue;
398
+ const defined = valueAt(theirs, address);
339
399
  const verb = leafVerb({
340
400
  ours: value,
341
- theirs: valueAt(theirs, address)
401
+ theirs: defined
342
402
  });
343
403
  if (verb === "override") override = setAtPath(override, address, value);
344
- else if (verb === "extend") extend = setAtPath(extend, address, value);
404
+ else if (verb === "extend") {
405
+ const added = addedEntries(value, defined) ?? value;
406
+ extend = setAtPath(extend, address, added);
407
+ }
345
408
  }
346
409
  const rules = local.styles;
347
410
  if (isWalkable(rules)) for (const [key, rule] of Object.entries(rules)) {
@@ -594,4 +657,4 @@ function borrowedSlug(body) {
594
657
  return isRef(body) ? sourceOf(body) : void 0;
595
658
  }
596
659
  //#endregion
597
- export { borrowedSlug, classifyOverlay, danglingDirectives, danglingSourcedRefs, excludedCondition, leafAddresses, leafVerb, misdeclaredOverlays, overlayVerb, redundantQualifiers, sourceSlugs, unadoptedDirectives, unreadableBorrows, unstatableConditions, unstatableOverrides, valueAt };
660
+ export { borrowedSlug, classifyOverlay, danglingDirectives, danglingSourcedRefs, excludedCondition, leafAddresses, leafVerb, misdeclaredOverlays, overlayVerb, redundantQualifiers, sourceSlugs, unadoptedDirectives, uniteEntries, unreadableBorrows, unstatableConditions, unstatableOverrides, valueAt };