synthesisui 0.16.97 → 0.16.98
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 +18 -4
- package/dist/commands/mcp.js +51 -6
- package/dist/doctor/transcribe.js +72 -1
- package/dist/skill-import.js +11 -0
- package/package.json +1 -1
package/dist/anatomy-read.js
CHANGED
|
@@ -123,7 +123,14 @@ function frontierClasses(node, sketch) {
|
|
|
123
123
|
export function resolveAnatomy(read, declared, deps,
|
|
124
124
|
/** Their name → the slug it reaches in this system. See `RefResolver`. */
|
|
125
125
|
resolve,
|
|
126
|
-
/**
|
|
126
|
+
/**
|
|
127
|
+
* What the component returns, when the skill said and it is not a plain tag.
|
|
128
|
+
*
|
|
129
|
+
* A STRING or an object: `{ name, at }` / `{ name, classes }` carries what the
|
|
130
|
+
* PARENT paints on the root at the call site. `MetricCard` returns
|
|
131
|
+
* `<Card className="flex-1 dark:bg-darkgray-300">` and that override had
|
|
132
|
+
* nowhere to travel (not-expressed.md, dono, 01/08).
|
|
133
|
+
*/
|
|
127
134
|
root,
|
|
128
135
|
/** This component's sketch, so a node can name its classes by INDEX instead
|
|
129
136
|
* of retyping them - see `AnatomyRead.at`. */
|
|
@@ -290,15 +297,22 @@ sketch) {
|
|
|
290
297
|
* through the crosswalk exactly like a child frontier does.
|
|
291
298
|
*/
|
|
292
299
|
let rootOut;
|
|
293
|
-
const
|
|
300
|
+
const rootObj = typeof root === "object" && root ? root : null;
|
|
301
|
+
const rootRaw = String((rootObj ? rootObj.name : root) ?? "").trim();
|
|
302
|
+
// The parent's own override on the root it returns, by index or as written.
|
|
303
|
+
const rootPainted = rootObj
|
|
304
|
+
? (frontierClasses(rootObj, sketch).classes ??
|
|
305
|
+
"")
|
|
306
|
+
: "";
|
|
307
|
+
const paints = rootPainted ? { classes: rootPainted } : {};
|
|
294
308
|
if (rootRaw && /^[A-Z]/.test(rootRaw)) {
|
|
295
309
|
if (rootRaw.includes(".")) {
|
|
296
|
-
rootOut = { from: rootRaw };
|
|
310
|
+
rootOut = { from: rootRaw, ...paints };
|
|
297
311
|
}
|
|
298
312
|
else {
|
|
299
313
|
const slug = resolve?.(rootRaw) ?? safePartName(rootRaw);
|
|
300
314
|
if (slug)
|
|
301
|
-
rootOut = { ref: slug, name: rootRaw };
|
|
315
|
+
rootOut = { ref: slug, name: rootRaw, ...paints };
|
|
302
316
|
}
|
|
303
317
|
}
|
|
304
318
|
if (coerced > 0) {
|
package/dist/commands/mcp.js
CHANGED
|
@@ -393,19 +393,64 @@ async function resolveAtNodes(root, entries) {
|
|
|
393
393
|
// better than refusing to validate at all.
|
|
394
394
|
return entries;
|
|
395
395
|
}
|
|
396
|
-
/** Their spelling → the
|
|
397
|
-
const
|
|
398
|
-
if (looks[name]
|
|
399
|
-
return looks[name]
|
|
396
|
+
/** Their spelling → the look, matched the way the contract kebabs a name. */
|
|
397
|
+
const lookFor = (name) => {
|
|
398
|
+
if (looks[name])
|
|
399
|
+
return looks[name];
|
|
400
400
|
const slug = name.replace(/[^a-z0-9]/gi, "").toLowerCase();
|
|
401
401
|
for (const [theirs, look] of Object.entries(looks)) {
|
|
402
402
|
if (theirs.replace(/[^a-z0-9]/gi, "").toLowerCase() === slug)
|
|
403
|
-
return look
|
|
403
|
+
return look;
|
|
404
404
|
}
|
|
405
405
|
return undefined;
|
|
406
406
|
};
|
|
407
407
|
return entries.map((entry) => {
|
|
408
|
-
const
|
|
408
|
+
const look = lookFor(String(entry.name ?? ""));
|
|
409
|
+
const sketch = look?.sketch;
|
|
410
|
+
/**
|
|
411
|
+
* THE STYLES THE IMPORT WILL MERGE - so the floor measured is the floor the
|
|
412
|
+
* component arrives with.
|
|
413
|
+
*
|
|
414
|
+
* The reading sends an ANATOMY: a tree of `at` indices, deliberately without
|
|
415
|
+
* the classes, because retyping them is the loss the index exists to prevent.
|
|
416
|
+
* The styles are the census's measured `base` and `layers`, merged at import.
|
|
417
|
+
* So the validator was judging a recipe whose look had not arrived yet, and
|
|
418
|
+
* all 35 components came back BELOW THE FLOOR with the same four lines - a
|
|
419
|
+
* verdict about a payload nobody will ever send (not-expressed.md, dono,
|
|
420
|
+
* 01/08).
|
|
421
|
+
*
|
|
422
|
+
* Merged UNDER what the payload carries: a base the reader authored on
|
|
423
|
+
* purpose still wins over the measurement.
|
|
424
|
+
*/
|
|
425
|
+
const recipe0 = entry.recipe;
|
|
426
|
+
const withLook = recipe0
|
|
427
|
+
? {
|
|
428
|
+
...recipe0,
|
|
429
|
+
...(look?.base && Object.keys(look.base).length > 0
|
|
430
|
+
? { base: { ...look.base, ...(recipe0.base ?? {}) } }
|
|
431
|
+
: {}),
|
|
432
|
+
...(look?.layers?.length
|
|
433
|
+
? {
|
|
434
|
+
layers: [
|
|
435
|
+
...look.layers,
|
|
436
|
+
...(recipe0.layers ?? []),
|
|
437
|
+
],
|
|
438
|
+
}
|
|
439
|
+
: {}),
|
|
440
|
+
/**
|
|
441
|
+
* THE ROOT TAG TRAVELS, so the validator can name the KIND.
|
|
442
|
+
*
|
|
443
|
+
* It falls back to `surface` when the payload declares none, and every
|
|
444
|
+
* one of 35 components got the surface checklist - including a Button,
|
|
445
|
+
* two fields, a control and two pills (not-expressed.md, dono, 01/08).
|
|
446
|
+
* The kind is arithmetic from the name and the root tag; the tag is
|
|
447
|
+
* here and the arithmetic lives on the side that owns the contract, so
|
|
448
|
+
* this sends the evidence rather than a second implementation of it.
|
|
449
|
+
*/
|
|
450
|
+
...(look?.rootTag ? { rootTag: look.rootTag } : {}),
|
|
451
|
+
}
|
|
452
|
+
: recipe0;
|
|
453
|
+
entry = { ...entry, recipe: withLook };
|
|
409
454
|
if (!sketch)
|
|
410
455
|
return entry;
|
|
411
456
|
const walk = (nodes) => {
|
|
@@ -1135,6 +1135,44 @@ export function transcribe(classes, declared) {
|
|
|
1135
1135
|
* Absent or unfound, the old behaviour stands exactly - which keeps every
|
|
1136
1136
|
* single-component file reading byte-identically.
|
|
1137
1137
|
*/
|
|
1138
|
+
/**
|
|
1139
|
+
* AN EXPORT THAT IS AN ALIAS - follow it to the function it wraps.
|
|
1140
|
+
*
|
|
1141
|
+
* `export const Chat = Object.assign(React.forwardRef(ChatContainerComponent), …)`
|
|
1142
|
+
* declares the NAME the census knows and none of the markup: the styles live in
|
|
1143
|
+
* `ChatContainerComponent`, declared above. Measured on a real library, EIGHT of
|
|
1144
|
+
* 36 exports are this shape - seven `forwardRef(Fn)` and one
|
|
1145
|
+
* `Object.assign(forwardRef(Fn))` - and Chat arrived with an empty look, which
|
|
1146
|
+
* forced the one hand-read of the whole run (not-expressed.md, dono, 01/08).
|
|
1147
|
+
*
|
|
1148
|
+
* They used to work by accident: with no body brace to find, the reader fell
|
|
1149
|
+
* back to the first `return (` in the file, which for a one-component file is
|
|
1150
|
+
* the right one. Removing that fallback - correctly, because it let a helper
|
|
1151
|
+
* borrow a sibling's return - would have broken all eight. So the alias is
|
|
1152
|
+
* followed on purpose instead: the first capitalised identifier inside the call
|
|
1153
|
+
* is the function this name IS.
|
|
1154
|
+
*/
|
|
1155
|
+
function aliasTarget(source, name) {
|
|
1156
|
+
const decl = new RegExp(`(?:const|let|var)\\s+${name}\\s*(?::[^=]*)?=\\s*([^;\\n]{0,200})`).exec(source);
|
|
1157
|
+
if (!decl)
|
|
1158
|
+
return null;
|
|
1159
|
+
const rhs = decl[1];
|
|
1160
|
+
// Only a WRAPPER call aliases: `forwardRef`, `memo`, `Object.assign`,
|
|
1161
|
+
// `styled(...)`. A plain arrow is the component itself and has no target.
|
|
1162
|
+
if (!/^(?:React\.)?(?:forwardRef|memo|Object\.assign|styled)\b/.test(rhs))
|
|
1163
|
+
return null;
|
|
1164
|
+
for (const m of rhs.matchAll(/\b([A-Z][A-Za-z0-9_]*)\b/g)) {
|
|
1165
|
+
const candidate = m[1];
|
|
1166
|
+
if (/^(React|Object|Component)$/.test(candidate))
|
|
1167
|
+
continue;
|
|
1168
|
+
if (candidate === name)
|
|
1169
|
+
continue;
|
|
1170
|
+
// It has to be declared in this file, or it is a type argument or an import.
|
|
1171
|
+
if (new RegExp(`(?:function|const|let|var)\\s+${candidate}\\b`).test(source))
|
|
1172
|
+
return candidate;
|
|
1173
|
+
}
|
|
1174
|
+
return null;
|
|
1175
|
+
}
|
|
1138
1176
|
function returnAt(source, name) {
|
|
1139
1177
|
if (name) {
|
|
1140
1178
|
const decl = new RegExp(`(?:function|const|let|var)\\s+${name}\\b|${name}\\s*[:=]\\s*(?:function|\\()`).exec(source);
|
|
@@ -1150,6 +1188,16 @@ function returnAt(source, name) {
|
|
|
1150
1188
|
const arrow = /=>\s*\(/.exec(source.slice(decl.index, decl.index + 400));
|
|
1151
1189
|
if (arrow)
|
|
1152
1190
|
return decl.index + arrow.index;
|
|
1191
|
+
/**
|
|
1192
|
+
* AN ALIAS POINTS AT THE FUNCTION THAT HAS THE MARKUP - follow it once.
|
|
1193
|
+
* `const Chat = Object.assign(forwardRef(ChatContainerComponent), …)`.
|
|
1194
|
+
*/
|
|
1195
|
+
const target = aliasTarget(source, name);
|
|
1196
|
+
if (target) {
|
|
1197
|
+
const viaAlias = ownReturn(source, source.search(new RegExp(`(?:function|const|let|var)\\s+${target}\\b`)));
|
|
1198
|
+
if (viaAlias !== -1)
|
|
1199
|
+
return viaAlias;
|
|
1200
|
+
}
|
|
1153
1201
|
/**
|
|
1154
1202
|
* FOUND THE NAME AND IT RETURNS NO JSX IN PARENTHESES - so say nothing.
|
|
1155
1203
|
*
|
|
@@ -1200,13 +1248,36 @@ export function definitionSpan(source, name) {
|
|
|
1200
1248
|
if (!decl)
|
|
1201
1249
|
return null;
|
|
1202
1250
|
const brace = bodyBrace(source, decl.index);
|
|
1203
|
-
if (brace === -1)
|
|
1251
|
+
if (brace === -1) {
|
|
1252
|
+
// The export is an alias; the body belongs to what it wraps.
|
|
1253
|
+
const target = aliasTarget(source, name);
|
|
1254
|
+
if (target)
|
|
1255
|
+
return definitionSpan(source, target);
|
|
1204
1256
|
return null;
|
|
1257
|
+
}
|
|
1205
1258
|
const end = matchingBrace(source, brace);
|
|
1206
1259
|
return { from: decl.index, to: end === -1 ? source.length : end + 1 };
|
|
1207
1260
|
}
|
|
1208
1261
|
/** The `{` that opens a function body declared at `declAt`, or -1. */
|
|
1209
1262
|
function bodyBrace(source, declAt) {
|
|
1263
|
+
/**
|
|
1264
|
+
* A BODY INLINE INSIDE A WRAPPER: `forwardRef<A, B>((props, ref) => { … })`.
|
|
1265
|
+
*
|
|
1266
|
+
* Toggle is written this way and the plain walk below cannot find it - the
|
|
1267
|
+
* wrapper's own parenthesis never closes before the body starts, so it looked
|
|
1268
|
+
* for a `{` that is not there and the component read empty. There is no named
|
|
1269
|
+
* function to alias to either: the body IS the argument.
|
|
1270
|
+
*/
|
|
1271
|
+
const head = source.slice(declAt, declAt + 400);
|
|
1272
|
+
const wrapper = /=\s*(?:React\.)?(?:forwardRef|memo|styled\([^)]*\))\s*(?:<[^>(]*>)?\s*\(/.exec(head);
|
|
1273
|
+
if (wrapper) {
|
|
1274
|
+
const arrow = /(?:=>|function\s*[A-Za-z0-9_]*\s*\([^)]*\))\s*\{/.exec(source.slice(declAt + wrapper.index));
|
|
1275
|
+
if (arrow) {
|
|
1276
|
+
const at = declAt + wrapper.index + arrow.index + arrow[0].length - 1;
|
|
1277
|
+
if (source[at] === "{")
|
|
1278
|
+
return at;
|
|
1279
|
+
}
|
|
1280
|
+
}
|
|
1210
1281
|
let i = declAt;
|
|
1211
1282
|
let paren = 0;
|
|
1212
1283
|
let opened = false;
|
package/dist/skill-import.js
CHANGED
|
@@ -614,10 +614,21 @@ depth appears anyway.
|
|
|
614
614
|
"Modal": {
|
|
615
615
|
"root": "BaseDialog.Root",
|
|
616
616
|
"anatomy": [ … ]
|
|
617
|
+
},
|
|
618
|
+
"MetricCard": {
|
|
619
|
+
"root": { "name": "Card", "at": 1 },
|
|
620
|
+
"anatomy": [ … ]
|
|
617
621
|
}
|
|
618
622
|
}
|
|
619
623
|
\`\`\`
|
|
620
624
|
|
|
625
|
+
**The root takes what the PARENT paints on it.** When the returned root carries an override at
|
|
626
|
+
the call site - \`MetricCard\` returns \`<Card className="flex-1 dark:bg-darkgray-300">\` - send the
|
|
627
|
+
object form and point \`at\` the sketch node: \`{ "name": "Card", "at": 1 }\`. The string form still
|
|
628
|
+
works and means "no override". Sending the root as an anatomy node instead would make it a leaf
|
|
629
|
+
and orphan the content inside it, which is why it is a field on the root rather than a node
|
|
630
|
+
(not-expressed.md, dono, 01/08).
|
|
631
|
+
|
|
621
632
|
**Say what the component RETURNS when it is not a plain tag.** Measured on a real library
|
|
622
633
|
(dono, 01/08): 14 of 23 components return one of their own - \`ArticleCard\` returns a \`<Card>\`,
|
|
623
634
|
\`Button\` and \`Text\` return a \`<Component>\` - and 17 of 23 have no style of their own at all,
|
package/package.json
CHANGED