@smallpen/local-package 0.1.0-alpha.5 → 0.1.0-alpha.9

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.
package/src/workspace.mjs CHANGED
@@ -2,7 +2,9 @@ import { realpath } from "node:fs/promises";
2
2
  import { dirname, isAbsolute, posix, resolve, win32 } from "node:path";
3
3
 
4
4
  import {
5
+ closestComponentVariant,
5
6
  combineContextAxes,
7
+ findComponentVariant,
6
8
  listEffectiveTokens,
7
9
  projectScenario,
8
10
  projectScreen,
@@ -294,13 +296,17 @@ const DEPENDENCY_PROJECTION_CODES = new Set([
294
296
  ]);
295
297
 
296
298
  function validateWorkspaceProjections(product, foundation, libraries = []) {
299
+ // The Presentation being projected, so a failing Instance is found in it
300
+ // and not in another Screen that reuses its node id.
301
+ let projecting;
297
302
  try {
298
303
  for (const context of contextSelections(product, foundation)) {
299
304
  listEffectiveTokens(product, { context, foundation, libraries });
300
305
  }
301
306
  for (const entry of product.manifest.entries.screens) {
302
307
  const screen = product.entries[entry];
303
- for (const presentation of screen.presentations) {
308
+ for (const [index, presentation] of screen.presentations.entries()) {
309
+ projecting = `${entry}.presentations[${index}]`;
304
310
  projectScreen(product, screen.id, {
305
311
  foundation,
306
312
  libraries,
@@ -308,6 +314,7 @@ function validateWorkspaceProjections(product, foundation, libraries = []) {
308
314
  });
309
315
  }
310
316
  }
317
+ projecting = undefined;
311
318
  for (const scenario of product.domain.scenarios.values()) {
312
319
  projectScenario(product, scenario.id, { foundation, libraries });
313
320
  }
@@ -324,7 +331,9 @@ function validateWorkspaceProjections(product, foundation, libraries = []) {
324
331
  if (!path && error.details.instanceId) {
325
332
  const suffix = `.nodes.${error.details.instanceId}.instance.component`;
326
333
  const usage = externalReferences(product).find((candidate) =>
327
- candidate.path.endsWith(suffix),
334
+ projecting
335
+ ? candidate.path === `${projecting}${suffix}`
336
+ : candidate.path.endsWith(suffix),
328
337
  );
329
338
  path = usage?.path;
330
339
  reference = usage?.reference;
@@ -353,6 +362,83 @@ function validateWorkspaceProjections(product, foundation, libraries = []) {
353
362
  }
354
363
  }
355
364
 
365
+ // Instances of the Product whose selection no variant of their Component
366
+ // Set has any more (the Foundation renamed a value or deleted the variant).
367
+ // They still draw, with the closest variant (`degraded` conflicts let reads
368
+ // go on); the Product waits in Repair for one of the typed choices: select
369
+ // a variant, or remove the Instance (or retarget it, as any reference).
370
+ function staleInstanceConflicts(product, foundation, libraries = []) {
371
+ const sets = new Map([[product.manifest.packageId, product.domain.componentSets]]);
372
+ for (const owner of [foundation, ...libraries]) {
373
+ if (owner) sets.set(owner.manifest.packageId, owner.domain.componentSets);
374
+ }
375
+ const conflicts = [];
376
+ const check = (instance, path, nodePath, target) => {
377
+ const reference = instance?.component;
378
+ const componentSet = sets.get(reference?.packageId)?.get(reference?.assetId);
379
+ if (!componentSet || findComponentVariant(componentSet, instance.variant ?? {}).variant) {
380
+ return;
381
+ }
382
+ const closest = closestComponentVariant(componentSet, instance.variant);
383
+ const select = closest
384
+ ? [
385
+ {
386
+ action: "select-instance-variant",
387
+ referencePath: `${nodePath}.instance`,
388
+ selection: structuredClone(closest.selection),
389
+ validSelections: componentSet.variants.map((variant) =>
390
+ structuredClone(variant.selection),
391
+ ),
392
+ ...target,
393
+ },
394
+ ]
395
+ : [];
396
+ conflicts.push({
397
+ ...conflict(
398
+ "missing_variant",
399
+ `Instance ${target.nodeId} selects ${JSON.stringify(instance.variant ?? {})}, ` +
400
+ `which no variant of ${reference.assetId} has. It draws as ` +
401
+ `${JSON.stringify(closest?.selection ?? {})} until it is repaired`,
402
+ `${path}`,
403
+ [...select, ...referenceRepairChoices(path, reference)],
404
+ ),
405
+ degraded: true,
406
+ reference: structuredClone(reference),
407
+ });
408
+ };
409
+ for (const entry of product.manifest.entries.screens) {
410
+ const screen = product.entries[entry];
411
+ screen.presentations.forEach((presentation, index) => {
412
+ for (const [nodeId, node] of Object.entries(presentation.nodes)) {
413
+ if (!node.instance) continue;
414
+ const nodePath = `${entry}.presentations[${index}].nodes.${nodeId}`;
415
+ check(node.instance, `${nodePath}.instance.component`, nodePath, {
416
+ nodeId,
417
+ presentationId: presentation.id,
418
+ screenId: screen.id,
419
+ });
420
+ }
421
+ });
422
+ }
423
+ for (const entry of product.manifest.entries.components) {
424
+ (product.entries[entry].componentSets ?? []).forEach((componentSet, setIndex) => {
425
+ componentSet.variants.forEach((variant, variantIndex) => {
426
+ for (const [nodeId, node] of Object.entries(variant.nodes)) {
427
+ if (!node.instance) continue;
428
+ const nodePath =
429
+ `${entry}.componentSets[${setIndex}].variants[${variantIndex}].nodes.${nodeId}`;
430
+ check(node.instance, `${nodePath}.instance.component`, nodePath, {
431
+ componentSetId: componentSet.id,
432
+ nodeId,
433
+ variantId: variant.id,
434
+ });
435
+ }
436
+ });
437
+ });
438
+ }
439
+ return conflicts;
440
+ }
441
+
356
442
  function chooseLibrarySource(library) {
357
443
  return {
358
444
  action: "choose-library-source",
@@ -633,6 +719,11 @@ export async function resolveWorkspace(productLocator, options = {}) {
633
719
  ...validateWorkspaceProjections(product, foundation, resolved.libraries),
634
720
  );
635
721
  }
722
+ if (conflicts.length === 0) {
723
+ conflicts.push(
724
+ ...staleInstanceConflicts(product, foundation, resolved.libraries),
725
+ );
726
+ }
636
727
  if (conflicts.length > 0) {
637
728
  return repair(product, conflicts, foundation, resolved.libraries, warnings);
638
729
  }