synthesisui 0.16.86 → 0.16.87
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/dist/anatomy-read.js +9 -0
- package/dist/commands/import.js +26 -0
- package/dist/doctor/transcribe.js +32 -1
- package/dist/skill-import.js +34 -0
- package/package.json +1 -1
package/dist/anatomy-read.js
CHANGED
|
@@ -194,6 +194,15 @@ root) {
|
|
|
194
194
|
: [];
|
|
195
195
|
const t = transcribe(classes, declared);
|
|
196
196
|
parts[key] = { base: t.base, dark: t.dark, states: t.states };
|
|
197
|
+
/**
|
|
198
|
+
* A drop on a PART is still a drop. The root path already says these out loud;
|
|
199
|
+
* this one silently swallowed `p-spacing-sm` on a real menu popup, so the part
|
|
200
|
+
* arrived with no padding and the not-expressed file had to discover it from
|
|
201
|
+
* the outside (dono, 01/08).
|
|
202
|
+
*/
|
|
203
|
+
for (const cls of t.unreadable) {
|
|
204
|
+
notes.push(`part \`${key}\`: \`${cls}\` starts like a design decision and reads as nothing - usually a typo in the source, and the element renders without it today`);
|
|
205
|
+
}
|
|
197
206
|
node_.part = key;
|
|
198
207
|
}
|
|
199
208
|
const text = typeof node.text === "string" ? node.text.trim() : "";
|
package/dist/commands/import.js
CHANGED
|
@@ -799,6 +799,31 @@ export async function takeCensus(root, opts) {
|
|
|
799
799
|
console.log(body(line));
|
|
800
800
|
console.log(body(paint.faint("Do not go looking for any of this - it is measured, and a sweep would bring back a different slice than the next one.")));
|
|
801
801
|
}
|
|
802
|
+
/**
|
|
803
|
+
* THE DROPS, SAID OUT LOUD. `p-spacing-sm` on a real menu popup read as nothing and
|
|
804
|
+
* the popup shipped with no padding, invisibly - "if the compiler drops them, the drop
|
|
805
|
+
* is invisible from here" was the not-expressed file calling this exact hole (dono,
|
|
806
|
+
* 01/08). More often than not the class is malformed in THEIR source, which makes this
|
|
807
|
+
* a defect report about their code, not an apology about ours.
|
|
808
|
+
*/
|
|
809
|
+
const unreadableByComponent = Object.entries(looks)
|
|
810
|
+
.filter(([, look]) => (look.unreadable ?? []).length > 0)
|
|
811
|
+
.map(([component, look]) => ({
|
|
812
|
+
component,
|
|
813
|
+
classes: look.unreadable ?? [],
|
|
814
|
+
}));
|
|
815
|
+
if (unreadableByComponent.length > 0) {
|
|
816
|
+
const total = unreadableByComponent.reduce((n, u) => n + u.classes.length, 0);
|
|
817
|
+
console.log("");
|
|
818
|
+
console.log(section("Design classes that read as nothing"));
|
|
819
|
+
console.log(body(`${total} class${total === 1 ? "" : "es"} start like a design decision and resolve to nothing - usually a typo in the source, and the element renders without that decision today. Nothing was guessed on their behalf:`));
|
|
820
|
+
for (const u of unreadableByComponent.slice(0, 8)) {
|
|
821
|
+
console.log(body(paint.faint(` ${u.component}: ${u.classes.slice(0, 4).join(", ")}`)));
|
|
822
|
+
}
|
|
823
|
+
if (unreadableByComponent.length > 8) {
|
|
824
|
+
console.log(body(paint.faint(` and ${unreadableByComponent.length - 8} more components`)));
|
|
825
|
+
}
|
|
826
|
+
}
|
|
802
827
|
const coverageLines = describeCoverage(coverage);
|
|
803
828
|
if (coverageLines.length > 0) {
|
|
804
829
|
console.log("");
|
|
@@ -1590,6 +1615,7 @@ async function resolveReadParts(census, root) {
|
|
|
1590
1615
|
dark: {},
|
|
1591
1616
|
states: {},
|
|
1592
1617
|
skipped: [],
|
|
1618
|
+
unreadable: [],
|
|
1593
1619
|
literals: [],
|
|
1594
1620
|
fromToken: 0,
|
|
1595
1621
|
fromLiteral: 0,
|
|
@@ -447,6 +447,22 @@ function resolveArbitrary(inner, declared) {
|
|
|
447
447
|
return null;
|
|
448
448
|
const v = /^var\(\s*(--[a-zA-Z0-9_-]+)\s*(?:,[^)]*)?\)$/.exec(raw);
|
|
449
449
|
if (!v) {
|
|
450
|
+
/**
|
|
451
|
+
* `[--text-body-s]` IS the var() shorthand - Tailwind v3 defined it that way, so the
|
|
452
|
+
* author wrote a working thing once. v4 dropped the shorthand, which is why their
|
|
453
|
+
* inputs render at the inherited size today; the token they NAMED is still the
|
|
454
|
+
* intent, and a recipe is the rules to rebuild the component, not a photograph of
|
|
455
|
+
* the regression. Their own defect still gets reported - see `unreadable`.
|
|
456
|
+
*
|
|
457
|
+
* A bare `--name` they never declared resolves to nothing under either semantics,
|
|
458
|
+
* and carrying it would emit `font-size: --x`, which is invalid CSS.
|
|
459
|
+
*/
|
|
460
|
+
if (raw.startsWith("--")) {
|
|
461
|
+
const name = raw.split(",")[0].trim();
|
|
462
|
+
return declared.has(name)
|
|
463
|
+
? { value: tokenRefFor(name), token: name }
|
|
464
|
+
: null;
|
|
465
|
+
}
|
|
450
466
|
// A literal in brackets is still a real value somebody typed.
|
|
451
467
|
return /[<>{}@;]/.test(raw) ? null : { value: raw };
|
|
452
468
|
}
|
|
@@ -540,12 +556,18 @@ export function readInlineStyle(source) {
|
|
|
540
556
|
}
|
|
541
557
|
/** Properties React leaves unitless, so a bare number is not pixels. */
|
|
542
558
|
const UNITLESS = /^(opacity|zIndex|flex|flexGrow|flexShrink|order|lineHeight|fontWeight|zoom|columnCount|fillOpacity|strokeOpacity|animationIterationCount)$/;
|
|
559
|
+
/**
|
|
560
|
+
* A prefix this reader claims to understand. A class that starts with one of these and
|
|
561
|
+
* still reads as nothing is a failed DESIGN read, not layout plumbing.
|
|
562
|
+
*/
|
|
563
|
+
const DESIGN_PREFIX = /^(?:p|px|py|pt|pr|pb|pl|m|mx|my|gap|rounded|text|font|bg|border|shadow|w|h|size|min-w|min-h|max-w|max-h|leading|tracking|opacity|fill|stroke)-\S/;
|
|
543
564
|
export function transcribe(classes, declared) {
|
|
544
565
|
const out = {
|
|
545
566
|
base: {},
|
|
546
567
|
states: {},
|
|
547
568
|
dark: {},
|
|
548
569
|
skipped: [],
|
|
570
|
+
unreadable: [],
|
|
549
571
|
literals: [],
|
|
550
572
|
fromToken: 0,
|
|
551
573
|
fromLiteral: 0,
|
|
@@ -585,7 +607,16 @@ export function transcribe(classes, declared) {
|
|
|
585
607
|
out.skipped.push(cls);
|
|
586
608
|
continue;
|
|
587
609
|
}
|
|
588
|
-
if (!decl
|
|
610
|
+
if (!decl) {
|
|
611
|
+
// The prefix says design intent; the rest resolved to nothing. Malformed in their
|
|
612
|
+
// source more often than not - `p-spacing-sm` for `p-sm` - and a silent drop here
|
|
613
|
+
// is how a menu popup ships with no padding and nobody is told.
|
|
614
|
+
if (DESIGN_PREFIX.test(utility) && !out.unreadable.includes(cls)) {
|
|
615
|
+
out.unreadable.push(cls);
|
|
616
|
+
}
|
|
617
|
+
continue;
|
|
618
|
+
}
|
|
619
|
+
if (!target)
|
|
589
620
|
continue;
|
|
590
621
|
/**
|
|
591
622
|
* EVERYTHING IT READS TRAVELS, literals included - as DATA.
|
package/dist/skill-import.js
CHANGED
|
@@ -543,6 +543,20 @@ extensions are configured at construction, not toggled later
|
|
|
543
543
|
of their manifest and attaches it (\`"^2.1.0 in packages/ui"\`), so the rule does not go stale the
|
|
544
544
|
day they upgrade and the information is not lost either.
|
|
545
545
|
|
|
546
|
+
### If \`recipe_vocabulary\` is missing, the MCP registration is stale
|
|
547
|
+
|
|
548
|
+
A real run reported "recipe_vocabulary and validate_recipe do not exist on this server" and
|
|
549
|
+
sent every anatomy unvalidated - the repo's \`.mcp.json\` pinned \`synthesisui@0.16.78\` while
|
|
550
|
+
the import itself ran unpinned at latest: **two CLI versions in one repo, in one run** (dono,
|
|
551
|
+
01/08). Before concluding a tool does not exist, check the registration:
|
|
552
|
+
|
|
553
|
+
\`\`\`json
|
|
554
|
+
"args": ["synthesisui@latest", "mcp"]
|
|
555
|
+
\`\`\`
|
|
556
|
+
|
|
557
|
+
Tell the person to fix the pin and restart the server. Do not work around a stale server by
|
|
558
|
+
skipping validation - unvalidated is how correct work arrives as nothing.
|
|
559
|
+
|
|
546
560
|
### Ask what a recipe can hold, BEFORE you write one
|
|
547
561
|
|
|
548
562
|
\`\`\`
|
|
@@ -669,6 +683,26 @@ found them wastes a turn and risks contradicting the measurement:
|
|
|
669
683
|
What is still yours: the anatomy tree, the part names, the frontiers, the roles, the
|
|
670
684
|
concept, and the rules that are not about a class name.
|
|
671
685
|
|
|
686
|
+
### A scale's INTENT is a rule, and their docs already wrote it
|
|
687
|
+
|
|
688
|
+
A three-step spacing scale with documented meaning - sm "close UI relationships", md
|
|
689
|
+
"standard internal padding", lg "layout gutters" - carries a law nothing else expresses:
|
|
690
|
+
**this system has exactly three steps, and a fourth is a mistake.** A real import read the
|
|
691
|
+
scale and lost the sentence (dono, 01/08).
|
|
692
|
+
|
|
693
|
+
When their docs (a \`Geometry.mdx\`, a design-tokens page, comments beside the \`@theme\`)
|
|
694
|
+
state what a step is FOR, send it as system-wide rules - \`applies: []\`, \`fact: true\`, the
|
|
695
|
+
doc as evidence:
|
|
696
|
+
|
|
697
|
+
\`\`\`
|
|
698
|
+
this system's spacing has exactly three steps - sm for close relationships inside a
|
|
699
|
+
control, md for standard internal padding, lg for layout gutters. A fourth step is a
|
|
700
|
+
mistake, not a gap (Geometry.mdx)
|
|
701
|
+
\`\`\`
|
|
702
|
+
|
|
703
|
+
\`applies: []\` is what makes it reach CLAUDE.md and every prompt after - the same route the
|
|
704
|
+
architecture rule travels.
|
|
705
|
+
|
|
672
706
|
### How much to send
|
|
673
707
|
|
|
674
708
|
Send an anatomy for **every component with visible structure**, which is nearly all of them. A
|
package/package.json
CHANGED