@yschimke/compose-design-map 1.45.0 → 1.46.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 +61 -5
- package/package.json +1 -1
package/design-map.mjs
CHANGED
|
@@ -68,9 +68,37 @@ const LIGHT_MODE = "Light";
|
|
|
68
68
|
/** The tag discovery puts in the id of an `@OverrideVariant` reseed: `…_VARIANT_<name>`. */
|
|
69
69
|
const VARIANT_TAG = "_VARIANT_";
|
|
70
70
|
|
|
71
|
+
/**
|
|
72
|
+
* The head of a capture's id with the `_VARIANT_<name>` reseed suffix removed, and whether there
|
|
73
|
+
* was one — `{ head, reseed }`.
|
|
74
|
+
*
|
|
75
|
+
* `_VARIANT_` is a legal substring of a Kotlin function name, so a plain `includes()` read the BASE
|
|
76
|
+
* capture of a composable called `Icon_VARIANT_Only` as a generated reseed. Every `continue` guarded
|
|
77
|
+
* by that test then dropped the composable outright, including its explicit `noReference` — a
|
|
78
|
+
* record whose whole purpose is to survive into the diagnostics.
|
|
79
|
+
*
|
|
80
|
+
* Discovery appends the tag to the id it has already built (`base.id + "_VARIANT_<name>"`), so the
|
|
81
|
+
* marker of an actual reseed is the LAST one and the function's own name is still in front of it.
|
|
82
|
+
* Splitting there and requiring the `.<functionName>` marker to survive in the head distinguishes
|
|
83
|
+
* the two: `…FooKt.Icon_VARIANT_Only_Light` splits to `…FooKt.Icon`, which no longer contains
|
|
84
|
+
* `.Icon_VARIANT_Only`, so it is a base capture; a real reseed of `Icon`,
|
|
85
|
+
* `…FooKt.Icon_Light_VARIANT_pressed`, splits to `…FooKt.Icon_Light`, which still contains `.Icon`.
|
|
86
|
+
*
|
|
87
|
+
* A capture that names no function cannot be told apart this way, so it keeps the old reading.
|
|
88
|
+
*/
|
|
89
|
+
function splitVariantTag(preview) {
|
|
90
|
+
const id = String(preview.id ?? "");
|
|
91
|
+
const at = id.lastIndexOf(VARIANT_TAG);
|
|
92
|
+
if (at < 0) return { head: id, reseed: false };
|
|
93
|
+
const head = id.slice(0, at);
|
|
94
|
+
const marker = preview.functionName ? `.${preview.functionName}` : null;
|
|
95
|
+
if (marker && !head.includes(marker)) return { head: id, reseed: false };
|
|
96
|
+
return { head, reseed: true };
|
|
97
|
+
}
|
|
98
|
+
|
|
71
99
|
/** Whether a capture is an `@OverrideVariant` reseed rather than a base capture. */
|
|
72
100
|
function isVariantCapture(preview) {
|
|
73
|
-
return
|
|
101
|
+
return splitVariantTag(preview).reseed;
|
|
74
102
|
}
|
|
75
103
|
|
|
76
104
|
/**
|
|
@@ -80,13 +108,14 @@ function isVariantCapture(preview) {
|
|
|
80
108
|
* is the `@Preview` name a multipreview gives the capture — `Light` / `Dark` for a themed pair, and
|
|
81
109
|
* EMPTY for an unnamed single capture. Splitting on the function name rather than pattern-matching
|
|
82
110
|
* the tail is what lets a dark-first catalog be recognised at all: its ids carry no mode segment to
|
|
83
|
-
* match against.
|
|
111
|
+
* match against. The reseed suffix comes off first, via [splitVariantTag] rather than a bare
|
|
112
|
+
* substring split, so a function whose own name contains `_VARIANT_` keeps its whole identity.
|
|
84
113
|
*
|
|
85
114
|
* A capture whose id does not contain its own function name is left as its own subject with an
|
|
86
115
|
* empty mode — it cannot be grouped with anything, so it selects itself.
|
|
87
116
|
*/
|
|
88
117
|
export function captureIdentity(preview) {
|
|
89
|
-
const head =
|
|
118
|
+
const { head } = splitVariantTag(preview);
|
|
90
119
|
const marker = preview.functionName ? `.${preview.functionName}` : null;
|
|
91
120
|
const at = marker ? head.lastIndexOf(marker) : -1;
|
|
92
121
|
if (at < 0) return { subject: head, mode: "" };
|
|
@@ -519,8 +548,28 @@ export function variantRendersByComponent(previews, selection = selectCaptures(p
|
|
|
519
548
|
const seeds = variantSeeds(preview);
|
|
520
549
|
if (!seeds.length) continue;
|
|
521
550
|
|
|
551
|
+
// A `@CatalogVariant` may state its OWN kit correspondence, and either spelling changes what a
|
|
552
|
+
// resolver should do with this render. Without reading them here a variant's declaration is
|
|
553
|
+
// emitted under the parent's `reference` regardless — which is precisely the mispairing the two
|
|
554
|
+
// fields were added to prevent.
|
|
555
|
+
//
|
|
556
|
+
// `noReference` says the kit exports no cell this render could honestly pair with. Handing it
|
|
557
|
+
// to the resolver anyway scores it against the PARENT's picture, so it is dropped: the absence
|
|
558
|
+
// is already reported once, as a stated absence, and a render that says "there is nothing to
|
|
559
|
+
// compare me to" must not then be compared.
|
|
560
|
+
if (isCatalogVariant && catalog.noReference) continue;
|
|
561
|
+
|
|
522
562
|
const list = byComponent.get(catalog.componentId) ?? [];
|
|
523
|
-
list.push({
|
|
563
|
+
list.push({
|
|
564
|
+
previewId: preview.id,
|
|
565
|
+
name: variantName(preview, seeds),
|
|
566
|
+
seeds,
|
|
567
|
+
// `reference` names the variant's own kit cell. Carried onto the render so a resolver pairs
|
|
568
|
+
// that handle instead of deriving one from the parent's by seed. Additive to the sidecar's
|
|
569
|
+
// shape — a resolver that does not read it sees exactly what it saw before, which is why the
|
|
570
|
+
// schema string does not move.
|
|
571
|
+
...(isCatalogVariant && catalog.reference ? { reference: catalog.reference } : {}),
|
|
572
|
+
});
|
|
524
573
|
byComponent.set(catalog.componentId, list);
|
|
525
574
|
}
|
|
526
575
|
return byComponent;
|
|
@@ -608,7 +657,14 @@ export function projectDesignMap(previews, opts = {}) {
|
|
|
608
657
|
if (catalog.noReference) {
|
|
609
658
|
statedAbsentIds.set(`component:${id}`, { label: id, reason: catalog.noReference });
|
|
610
659
|
statedAbsentComponentIds.add(id);
|
|
611
|
-
|
|
660
|
+
// Unconditional: [unmapped] below filters this set through [statedAbsentComponentIds], which
|
|
661
|
+
// is the only correct place for it — a component's stated absence may be read from a LATER
|
|
662
|
+
// capture than the one that first reports it unmapped, and a guard here can only see what has
|
|
663
|
+
// been read so far. The guard that used to stand here tested a bare `id` against a map now
|
|
664
|
+
// keyed `component:<id>` / `subject:<id>`, so for an ordinary id it never matched, and for a
|
|
665
|
+
// component legally named `component:X` it matched the wrong entry and dropped it from
|
|
666
|
+
// `unmapped` — letting `--strict` pass over a component with no reference and no reason.
|
|
667
|
+
} else unmappedIds.set(id, true);
|
|
612
668
|
}
|
|
613
669
|
/** Components carrying neither a reference nor a stated reason for its absence. */
|
|
614
670
|
const unmapped = [...unmappedIds.keys()].filter((id) => !statedAbsentComponentIds.has(id));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yschimke/compose-design-map",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.46.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",
|