@yschimke/compose-design-map 1.17.0 → 1.19.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.
package/design-map.mjs CHANGED
@@ -406,29 +406,50 @@ export function projectDesignMap(previews, opts = {}) {
406
406
 
407
407
  const components = [];
408
408
  const declarations = [];
409
+ /**
410
+ * Whether a component reaches a design reference at all, and what it said if not.
411
+ *
412
+ * Read from the ANNOTATIONS, before and independently of capture selection — which is the whole
413
+ * point. A component publishing several modes with no Light among them is `ambiguousMode`, and
414
+ * `participates()` is false for every one of its captures; computing absence inside the capture
415
+ * loop therefore dropped such a component out of `unmapped` / `statedAbsent` entirely and
416
+ * reported it only as an ambiguous mode. A stated absence would then be fatal under
417
+ * `--strict --allow-stated-absence`, which is exactly the case that flag exists to accept.
418
+ *
419
+ * Keyed by componentId rather than pushed per preview, because a component's absence is one fact
420
+ * however many captures it publishes.
421
+ */
422
+ const unmappedIds = new Map();
423
+ const statedAbsentIds = new Map();
424
+ for (const preview of previews) {
425
+ const catalog = preview.catalog;
426
+ if (!catalog || catalog.role !== "COMPONENT" || catalog.reference) continue;
427
+ if (isVariantCapture(preview)) continue;
428
+ const id = catalog.componentId;
429
+ if (catalog.noReference) statedAbsentIds.set(id, catalog.noReference);
430
+ else if (!statedAbsentIds.has(id)) unmappedIds.set(id, true);
431
+ }
409
432
  /** Components carrying neither a reference nor a stated reason for its absence. */
410
- const unmapped = [];
433
+ const unmapped = [...unmappedIds.keys()].filter((id) => !statedAbsentIds.has(id));
411
434
  /**
412
435
  * Components whose reference is absent for a STATED reason. Reported apart from `unmapped`
413
436
  * because they are the opposite situation: someone looked, and what they found is that the kit
414
437
  * has nothing live to point at. Rolling the two together is what made a retired pattern read as
415
438
  * neglect.
416
439
  */
417
- const statedAbsent = [];
440
+ const statedAbsent = [...statedAbsentIds].map(([componentId, reason]) => ({
441
+ componentId,
442
+ reason,
443
+ }));
444
+ /** Every component that reaches no reference, however its absence was spelled. */
445
+ const referencelessIds = new Set([...unmapped, ...statedAbsentIds.keys()]);
418
446
 
419
447
  for (const preview of previews) {
420
448
  const catalog = preview.catalog;
421
449
  if (!catalog || catalog.role !== "COMPONENT") continue;
422
450
  if (isVariantCapture(preview) || !selection.participates(preview)) continue;
423
451
 
424
- if (!catalog.reference) {
425
- if (catalog.noReference) {
426
- statedAbsent.push({ componentId: catalog.componentId, reason: catalog.noReference });
427
- } else {
428
- unmapped.push(catalog.componentId);
429
- }
430
- continue;
431
- }
452
+ if (!catalog.reference) continue;
432
453
 
433
454
  const code = codeHandle(preview, opts);
434
455
  components.push({
@@ -478,7 +499,14 @@ export function projectDesignMap(previews, opts = {}) {
478
499
  // Composables whose captures name no mode a reference could pair with — several modes, none
479
500
  // of them light. Reported rather than guessed at: pairing `Dark` when the kit drew `Coral`
480
501
  // diffs a whole palette.
481
- ambiguousMode: selection.ambiguous,
502
+ // An ambiguous mode is only ever a problem BECAUSE a reference needs one capture to pair
503
+ // with. A component that reaches no reference has nothing to pair, so which of its captures
504
+ // the kit drew is not a question anyone is asking — reporting it would be noise on top of the
505
+ // absence already reported above, and under --strict it would be a second, unfixable failure
506
+ // for the same component.
507
+ ambiguousMode: selection.ambiguous.filter(
508
+ (a) => !a.componentIds.length || a.componentIds.some((id) => !referencelessIds.has(id)),
509
+ ),
482
510
  variantRenders: declarations.reduce((n, d) => n + d.renders.length, 0),
483
511
  withSet: components.filter((c) => c.refSet).length,
484
512
  },
@@ -4,7 +4,7 @@
4
4
  *
5
5
  * npx @yschimke/compose-design-map [--previews <path>] [--out design-map.json]
6
6
  * [--variants design-map-variants.json] [--prefix catalog]
7
- * [--check] [--strict]
7
+ * [--check] [--strict] [--allow-stated-absence]
8
8
  *
9
9
  * Run `./gradlew :<module>:composePreviewDiscover` first so the manifest exists.
10
10
  *
@@ -32,6 +32,14 @@
32
32
  * whose captures name no mode the reference could pair with. The annotation still earns its keep in
33
33
  * the default mode, where the three are reported apart so a retired pattern does not read as
34
34
  * neglect; `--strict` simply says there are no exceptions.
35
+ *
36
+ * `--allow-stated-absence` narrows `--strict` back to what it is usually wanted for: it still fails
37
+ * on a missing `reference` and on an ambiguous mode, but accepts a component whose absence a
38
+ * `noReference` explains. That is the posture of a catalog with two doors — one for the components
39
+ * that reproduce a kit set, one for the components of its own library the kit never published —
40
+ * where an exception is a fact about the kit rather than a gap. Without it such a catalog has to
41
+ * drop `--strict` altogether and loses the guard against silence as well. No effect without
42
+ * `--strict`.
35
43
  */
36
44
  import fs from "node:fs";
37
45
  import path from "node:path";
@@ -51,6 +59,7 @@ const VARIANTS_OUT = arg("variants", "design-map-variants.json");
51
59
  const PREFIX = arg("prefix", "catalog");
52
60
  const CHECK = process.argv.includes("--check");
53
61
  const STRICT = process.argv.includes("--strict");
62
+ const ALLOW_STATED_ABSENCE = process.argv.includes("--allow-stated-absence");
54
63
 
55
64
  if (!fs.existsSync(PREVIEWS)) {
56
65
  console.error(
@@ -71,7 +80,16 @@ const { map, variants, diagnostics } = projectDesignMap(manifest.previews ?? [],
71
80
  if (STRICT) {
72
81
  const missing = [
73
82
  ...diagnostics.unmapped.map((id) => `${id} — no reference, and no reason given`),
74
- ...diagnostics.statedAbsent.map((s) => `${s.componentId} ${s.reason}`),
83
+ // A STATED absence is a gap under plain --strict and not under
84
+ // `--strict --allow-stated-absence`. The two postures are both real: a catalog whose inventory
85
+ // is exactly the kit's wants no exceptions at all, while one that also publishes components of
86
+ // its own library that the kit never drew (wear-m3-catalog's `ButtonGroup`, `Scaffold`) wants
87
+ // strictness about SILENCE without being failed by the four cases somebody already looked at
88
+ // and wrote down. Without the opt-in those catalogs cannot use --strict at all, which costs
89
+ // them the guard against silence too — the thing --strict was actually for.
90
+ ...(ALLOW_STATED_ABSENCE
91
+ ? []
92
+ : diagnostics.statedAbsent.map((s) => `${s.componentId} — ${s.reason}`)),
75
93
  // An ambiguous mode is the third way a component ends up outside the map, and the quietest:
76
94
  // the reference is there, but nothing says which capture it pairs with, so the component is
77
95
  // simply absent. Under --strict that is as much a gap as a missing reference.
@@ -90,7 +108,10 @@ if (STRICT) {
90
108
  for (const line of missing) console.error(` - ${line}`);
91
109
  console.error(
92
110
  `A catalog that reproduces a kit has nothing to compare these against — remove them, ` +
93
- `or drop --strict to publish them unmapped.`,
111
+ `or drop --strict to publish them unmapped` +
112
+ (ALLOW_STATED_ABSENCE
113
+ ? `.`
114
+ : `, or pass --allow-stated-absence to accept the ones a noReference explains.`),
94
115
  );
95
116
  process.exit(1);
96
117
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yschimke/compose-design-map",
3
- "version": "1.17.0",
3
+ "version": "1.19.0",
4
4
  "description": "Project a compose-preview discovery manifest into design-parity's design-map.json, plus a sidecar of unresolved variant declarations. Dependency-free.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",