@archie/devtools 0.0.22 → 0.0.24
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/README.md +6 -0
- package/dist/client/client.js +10 -4
- package/dist/client/client.mjs +10 -4
- package/dist/index.d.mts +182 -1
- package/dist/index.d.ts +182 -1
- package/dist/index.js +322 -38
- package/dist/index.mjs +322 -38
- package/dist/inspector.standalone.js +223 -4
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -206,6 +206,36 @@ function babelPluginDndAuto({ types: t }, opts = {}) {
|
|
|
206
206
|
|
|
207
207
|
// src/babel-plugin-editor-meta.ts
|
|
208
208
|
var nodePath = __toESM(require("path"));
|
|
209
|
+
var KIT_SLOT_ATTR = "data-kit-slot";
|
|
210
|
+
var MAX_SLOT_SEGMENTS = 4;
|
|
211
|
+
var NON_BINDING_ATTRS = /* @__PURE__ */ new Set(["__editorMeta", "key", "ref", KIT_SLOT_ATTR]);
|
|
212
|
+
var STRUCTURAL_ATTRS = /* @__PURE__ */ new Set([
|
|
213
|
+
"id",
|
|
214
|
+
"htmlFor",
|
|
215
|
+
"slot",
|
|
216
|
+
"name",
|
|
217
|
+
"type",
|
|
218
|
+
"role",
|
|
219
|
+
// The camelCase carrier of the SAME durable key as `data-agent-id`: kit
|
|
220
|
+
// components take `agentId` and render it as the data attribute. Found on the
|
|
221
|
+
// real corpus (×4) — blocking only the dashed form would have left the prop
|
|
222
|
+
// form routable, and a durable key with a string-literal usage value sails
|
|
223
|
+
// straight through the usage-value law.
|
|
224
|
+
"agentId"
|
|
225
|
+
]);
|
|
226
|
+
function isNonContentAttribute(name) {
|
|
227
|
+
if (/^on[A-Z]/.test(name)) return true;
|
|
228
|
+
if (name.startsWith("data-")) return true;
|
|
229
|
+
return STRUCTURAL_ATTRS.has(name);
|
|
230
|
+
}
|
|
231
|
+
function normalizeSlot(raw) {
|
|
232
|
+
const value = raw.trim();
|
|
233
|
+
if (!value) return null;
|
|
234
|
+
const segments = value.split("/");
|
|
235
|
+
if (segments.length > MAX_SLOT_SEGMENTS) return null;
|
|
236
|
+
if (segments.some((segment) => segment.trim() === "")) return null;
|
|
237
|
+
return value;
|
|
238
|
+
}
|
|
209
239
|
function isPackageImport(src) {
|
|
210
240
|
if (src.startsWith(".") || src.startsWith("/")) return false;
|
|
211
241
|
if (src.startsWith("@")) {
|
|
@@ -221,7 +251,8 @@ function babelPluginEditorMeta({ types: t }, opts = {}) {
|
|
|
221
251
|
const {
|
|
222
252
|
fileExclude = /node_modules/,
|
|
223
253
|
instrumentImported = true,
|
|
224
|
-
includeHostSourceRef = false
|
|
254
|
+
includeHostSourceRef = false,
|
|
255
|
+
origin = "screen"
|
|
225
256
|
} = opts;
|
|
226
257
|
function getJSXTagName(el) {
|
|
227
258
|
const { name } = el;
|
|
@@ -334,29 +365,275 @@ function babelPluginEditorMeta({ types: t }, opts = {}) {
|
|
|
334
365
|
}
|
|
335
366
|
return false;
|
|
336
367
|
}
|
|
368
|
+
function buildPayloadFilter(payload) {
|
|
369
|
+
return t.callExpression(
|
|
370
|
+
t.arrowFunctionExpression(
|
|
371
|
+
[
|
|
372
|
+
t.objectPattern([
|
|
373
|
+
t.objectProperty(
|
|
374
|
+
t.identifier("__editorMeta"),
|
|
375
|
+
t.identifier("_$em"),
|
|
376
|
+
false,
|
|
377
|
+
false
|
|
378
|
+
),
|
|
379
|
+
t.objectProperty(
|
|
380
|
+
t.stringLiteral(KIT_SLOT_ATTR),
|
|
381
|
+
t.identifier("_$ks"),
|
|
382
|
+
false,
|
|
383
|
+
false
|
|
384
|
+
),
|
|
385
|
+
t.restElement(t.identifier("_$r"))
|
|
386
|
+
])
|
|
387
|
+
],
|
|
388
|
+
t.identifier("_$r")
|
|
389
|
+
),
|
|
390
|
+
[t.objectExpression([t.spreadElement(payload)])]
|
|
391
|
+
);
|
|
392
|
+
}
|
|
337
393
|
function sanitizeSpreadAttributes(attrs) {
|
|
338
394
|
for (const attr of attrs) {
|
|
339
395
|
if (!t.isJSXSpreadAttribute(attr)) continue;
|
|
340
396
|
if (isMetaStripSpreadExpression(attr.argument)) continue;
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
)
|
|
357
|
-
|
|
358
|
-
|
|
397
|
+
attr.argument = buildPayloadFilter(attr.argument);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
function consumeKitSlot(attrs) {
|
|
401
|
+
let slot = null;
|
|
402
|
+
let found = false;
|
|
403
|
+
for (const attr of attrs) {
|
|
404
|
+
if (!t.isJSXAttribute(attr)) continue;
|
|
405
|
+
if (!t.isJSXIdentifier(attr.name, { name: KIT_SLOT_ATTR })) continue;
|
|
406
|
+
found = true;
|
|
407
|
+
if (slot !== null) continue;
|
|
408
|
+
const { value } = attr;
|
|
409
|
+
if (t.isStringLiteral(value)) {
|
|
410
|
+
slot = normalizeSlot(value.value);
|
|
411
|
+
} else if (t.isJSXExpressionContainer(value) && t.isStringLiteral(value.expression)) {
|
|
412
|
+
slot = normalizeSlot(value.expression.value);
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
if (!found) return { slot: null, found: false, attrs };
|
|
416
|
+
return {
|
|
417
|
+
slot,
|
|
418
|
+
found: true,
|
|
419
|
+
attrs: attrs.filter(
|
|
420
|
+
(attr) => !(t.isJSXAttribute(attr) && t.isJSXIdentifier(attr.name, { name: KIT_SLOT_ATTR }))
|
|
421
|
+
)
|
|
422
|
+
};
|
|
423
|
+
}
|
|
424
|
+
function getFunctionName(fn) {
|
|
425
|
+
const node = fn.node;
|
|
426
|
+
if (t.isFunctionDeclaration(node) && node.id) return node.id.name;
|
|
427
|
+
if (t.isFunctionExpression(node) && node.id) return node.id.name;
|
|
428
|
+
const parent = fn.parentPath;
|
|
429
|
+
if (parent?.isVariableDeclarator() && t.isIdentifier(parent.node.id)) {
|
|
430
|
+
return parent.node.id.name;
|
|
431
|
+
}
|
|
432
|
+
return null;
|
|
433
|
+
}
|
|
434
|
+
function buildPropMap(pattern) {
|
|
435
|
+
const map = /* @__PURE__ */ new Map();
|
|
436
|
+
for (const prop of pattern.properties) {
|
|
437
|
+
if (!t.isObjectProperty(prop) || prop.computed) continue;
|
|
438
|
+
const key = t.isIdentifier(prop.key) ? prop.key.name : t.isStringLiteral(prop.key) ? prop.key.value : null;
|
|
439
|
+
if (!key) continue;
|
|
440
|
+
const value = prop.value;
|
|
441
|
+
if (t.isIdentifier(value)) {
|
|
442
|
+
map.set(value.name, key);
|
|
443
|
+
} else if (t.isAssignmentPattern(value) && t.isIdentifier(value.left)) {
|
|
444
|
+
map.set(value.left.name, key);
|
|
445
|
+
}
|
|
359
446
|
}
|
|
447
|
+
return map;
|
|
448
|
+
}
|
|
449
|
+
function resolvePropContext(path) {
|
|
450
|
+
let fn = path.getFunctionParent();
|
|
451
|
+
while (fn) {
|
|
452
|
+
const [first] = fn.node.params;
|
|
453
|
+
if (first && t.isObjectPattern(first)) {
|
|
454
|
+
if (fn.scope.parent !== fn.scope.getProgramParent()) return null;
|
|
455
|
+
return {
|
|
456
|
+
componentScope: fn.scope,
|
|
457
|
+
propMap: buildPropMap(first),
|
|
458
|
+
componentName: getFunctionName(fn)
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
fn = fn.getFunctionParent();
|
|
462
|
+
}
|
|
463
|
+
return null;
|
|
464
|
+
}
|
|
465
|
+
function resolveProp(name, scope, ctx) {
|
|
466
|
+
const prop = ctx.propMap.get(name);
|
|
467
|
+
if (!prop) return null;
|
|
468
|
+
const binding = scope.getBinding(name);
|
|
469
|
+
if (!binding) return null;
|
|
470
|
+
if (binding.scope !== ctx.componentScope) return null;
|
|
471
|
+
if (!binding.constant) return null;
|
|
472
|
+
return prop;
|
|
473
|
+
}
|
|
474
|
+
function isScopeWithinComponent(scope, ctx) {
|
|
475
|
+
let current = scope;
|
|
476
|
+
while (current) {
|
|
477
|
+
if (current === ctx.componentScope) return true;
|
|
478
|
+
current = current.parent;
|
|
479
|
+
}
|
|
480
|
+
return false;
|
|
481
|
+
}
|
|
482
|
+
function resolveLocalConstInit(name, scope, ctx) {
|
|
483
|
+
const binding = scope.getBinding(name);
|
|
484
|
+
if (!binding) return null;
|
|
485
|
+
if (!binding.constant) return null;
|
|
486
|
+
const declarator = binding.path;
|
|
487
|
+
if (!declarator.isVariableDeclarator()) return null;
|
|
488
|
+
if (!isScopeWithinComponent(binding.scope, ctx)) return null;
|
|
489
|
+
const init = declarator.node.init;
|
|
490
|
+
if (!init || !t.isExpression(init)) return null;
|
|
491
|
+
return { init, scope: declarator.scope };
|
|
492
|
+
}
|
|
493
|
+
function isStaticStringLiteral(node) {
|
|
494
|
+
if (t.isStringLiteral(node)) return true;
|
|
495
|
+
return t.isTemplateLiteral(node) && node.expressions.length === 0;
|
|
496
|
+
}
|
|
497
|
+
function collectPropIdentifiers(node, scope, ctx, out = []) {
|
|
498
|
+
if (!node) return out;
|
|
499
|
+
const visit = (child) => collectPropIdentifiers(child, scope, ctx, out);
|
|
500
|
+
if (t.isIdentifier(node)) {
|
|
501
|
+
const prop = resolveProp(node.name, scope, ctx);
|
|
502
|
+
if (prop && !out.includes(prop)) out.push(prop);
|
|
503
|
+
return out;
|
|
504
|
+
}
|
|
505
|
+
if (t.isMemberExpression(node) || t.isOptionalMemberExpression(node)) {
|
|
506
|
+
visit(node.object);
|
|
507
|
+
if (node.computed) visit(node.property);
|
|
508
|
+
return out;
|
|
509
|
+
}
|
|
510
|
+
if (t.isCallExpression(node) || t.isOptionalCallExpression(node)) {
|
|
511
|
+
visit(node.callee);
|
|
512
|
+
node.arguments.forEach((arg) => visit(arg));
|
|
513
|
+
return out;
|
|
514
|
+
}
|
|
515
|
+
if (t.isTemplateLiteral(node)) {
|
|
516
|
+
node.expressions.forEach((expr) => visit(expr));
|
|
517
|
+
return out;
|
|
518
|
+
}
|
|
519
|
+
if (t.isConditionalExpression(node)) {
|
|
520
|
+
visit(node.test);
|
|
521
|
+
visit(node.consequent);
|
|
522
|
+
visit(node.alternate);
|
|
523
|
+
return out;
|
|
524
|
+
}
|
|
525
|
+
if (t.isLogicalExpression(node) || t.isBinaryExpression(node)) {
|
|
526
|
+
visit(node.left);
|
|
527
|
+
visit(node.right);
|
|
528
|
+
return out;
|
|
529
|
+
}
|
|
530
|
+
if (t.isUnaryExpression(node) || t.isAwaitExpression(node)) {
|
|
531
|
+
visit(node.argument);
|
|
532
|
+
return out;
|
|
533
|
+
}
|
|
534
|
+
if (t.isArrayExpression(node)) {
|
|
535
|
+
node.elements.forEach((el) => visit(el));
|
|
536
|
+
return out;
|
|
537
|
+
}
|
|
538
|
+
if (t.isObjectExpression(node)) {
|
|
539
|
+
for (const prop of node.properties) {
|
|
540
|
+
if (t.isObjectProperty(prop)) {
|
|
541
|
+
if (prop.computed) visit(prop.key);
|
|
542
|
+
visit(prop.value);
|
|
543
|
+
} else if (t.isSpreadElement(prop)) {
|
|
544
|
+
visit(prop.argument);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
return out;
|
|
548
|
+
}
|
|
549
|
+
if (t.isSpreadElement(node)) {
|
|
550
|
+
visit(node.argument);
|
|
551
|
+
return out;
|
|
552
|
+
}
|
|
553
|
+
if (t.isTSAsExpression(node) || t.isTSNonNullExpression(node) || t.isTypeCastExpression(node)) {
|
|
554
|
+
visit(node.expression);
|
|
555
|
+
return out;
|
|
556
|
+
}
|
|
557
|
+
return out;
|
|
558
|
+
}
|
|
559
|
+
function classifyExpression(expr, scope, ctx, hop) {
|
|
560
|
+
if (t.isIdentifier(expr)) {
|
|
561
|
+
const prop = resolveProp(expr.name, scope, ctx);
|
|
562
|
+
if (prop) return { kind: "direct", prop };
|
|
563
|
+
if (hop > 0) return null;
|
|
564
|
+
const local = resolveLocalConstInit(expr.name, scope, ctx);
|
|
565
|
+
if (!local) return null;
|
|
566
|
+
const inner = classifyExpression(local.init, local.scope, ctx, hop + 1);
|
|
567
|
+
if (!inner) return null;
|
|
568
|
+
return { kind: inner.kind === "formatted" ? "formatted" : "derived", prop: inner.prop };
|
|
569
|
+
}
|
|
570
|
+
if (t.isLogicalExpression(expr) && (expr.operator === "||" || expr.operator === "??") && isStaticStringLiteral(expr.right)) {
|
|
571
|
+
const left = classifyExpression(expr.left, scope, ctx, hop);
|
|
572
|
+
if (!left) return null;
|
|
573
|
+
return { kind: left.kind === "formatted" ? "formatted" : "derived", prop: left.prop };
|
|
574
|
+
}
|
|
575
|
+
const props = collectPropIdentifiers(expr, scope, ctx);
|
|
576
|
+
return props.length > 0 ? { kind: "formatted", prop: props[0] } : null;
|
|
577
|
+
}
|
|
578
|
+
function meaningfulChildren(children) {
|
|
579
|
+
return children.filter((child) => {
|
|
580
|
+
if (t.isJSXText(child)) return child.value.trim() !== "";
|
|
581
|
+
if (t.isJSXExpressionContainer(child)) return !t.isJSXEmptyExpression(child.expression);
|
|
582
|
+
return true;
|
|
583
|
+
});
|
|
584
|
+
}
|
|
585
|
+
function collectPropBindings(path, attrs) {
|
|
586
|
+
const ctx = resolvePropContext(path);
|
|
587
|
+
if (!ctx || ctx.propMap.size === 0) return { bindings: [], owner: null };
|
|
588
|
+
if (ctx.componentName === null) return { bindings: [], owner: null };
|
|
589
|
+
const scope = path.scope;
|
|
590
|
+
const bindings = [];
|
|
591
|
+
const elementPath = path.parentPath;
|
|
592
|
+
if (elementPath && elementPath.isJSXElement()) {
|
|
593
|
+
const children = meaningfulChildren(elementPath.node.children);
|
|
594
|
+
const isSoleChild = children.length === 1;
|
|
595
|
+
for (const child of children) {
|
|
596
|
+
if (!t.isJSXExpressionContainer(child)) continue;
|
|
597
|
+
const expression = child.expression;
|
|
598
|
+
if (t.isJSXEmptyExpression(expression)) continue;
|
|
599
|
+
const verdict = classifyExpression(expression, scope, ctx, 0);
|
|
600
|
+
if (!verdict) continue;
|
|
601
|
+
bindings.push({
|
|
602
|
+
target: "children",
|
|
603
|
+
prop: verdict.prop,
|
|
604
|
+
kind: isSoleChild ? verdict.kind : "formatted"
|
|
605
|
+
});
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
for (const attr of attrs) {
|
|
609
|
+
if (!t.isJSXAttribute(attr)) continue;
|
|
610
|
+
const name = t.isJSXIdentifier(attr.name) ? attr.name.name : `${attr.name.namespace.name}:${attr.name.name.name}`;
|
|
611
|
+
if (NON_BINDING_ATTRS.has(name)) continue;
|
|
612
|
+
const value = attr.value;
|
|
613
|
+
if (!t.isJSXExpressionContainer(value)) continue;
|
|
614
|
+
const expression = value.expression;
|
|
615
|
+
if (t.isJSXEmptyExpression(expression)) continue;
|
|
616
|
+
const verdict = classifyExpression(expression, scope, ctx, 0);
|
|
617
|
+
if (!verdict) continue;
|
|
618
|
+
bindings.push({
|
|
619
|
+
target: `attr:${name}`,
|
|
620
|
+
prop: verdict.prop,
|
|
621
|
+
// M2b: machine-contract attributes are reported, never offered.
|
|
622
|
+
kind: isNonContentAttribute(name) ? "formatted" : verdict.kind
|
|
623
|
+
});
|
|
624
|
+
}
|
|
625
|
+
return { bindings, owner: bindings.length > 0 ? ctx.componentName : null };
|
|
626
|
+
}
|
|
627
|
+
function propBindingsToAst(bindings) {
|
|
628
|
+
return t.arrayExpression(
|
|
629
|
+
bindings.map(
|
|
630
|
+
(binding) => t.objectExpression([
|
|
631
|
+
t.objectProperty(t.identifier("target"), t.stringLiteral(binding.target)),
|
|
632
|
+
t.objectProperty(t.identifier("prop"), t.stringLiteral(binding.prop)),
|
|
633
|
+
t.objectProperty(t.identifier("kind"), t.stringLiteral(binding.kind))
|
|
634
|
+
])
|
|
635
|
+
)
|
|
636
|
+
);
|
|
360
637
|
}
|
|
361
638
|
return {
|
|
362
639
|
name: "babel-plugin-editor-meta",
|
|
@@ -384,25 +661,13 @@ function babelPluginEditorMeta({ types: t }, opts = {}) {
|
|
|
384
661
|
if (!propsArg || t.isNullLiteral(propsArg)) return;
|
|
385
662
|
if (!t.isExpression(propsArg)) return;
|
|
386
663
|
if (isMetaStripSpreadExpression(propsArg)) return;
|
|
387
|
-
args[1] =
|
|
388
|
-
t.arrowFunctionExpression(
|
|
389
|
-
[
|
|
390
|
-
t.objectPattern([
|
|
391
|
-
t.objectProperty(
|
|
392
|
-
t.identifier("__editorMeta"),
|
|
393
|
-
t.identifier("_$em"),
|
|
394
|
-
false,
|
|
395
|
-
false
|
|
396
|
-
),
|
|
397
|
-
t.restElement(t.identifier("_$r"))
|
|
398
|
-
])
|
|
399
|
-
],
|
|
400
|
-
t.identifier("_$r")
|
|
401
|
-
),
|
|
402
|
-
[t.objectExpression([t.spreadElement(propsArg)])]
|
|
403
|
-
);
|
|
664
|
+
args[1] = buildPayloadFilter(propsArg);
|
|
404
665
|
},
|
|
405
666
|
JSXOpeningElement(path, state) {
|
|
667
|
+
const consumed = consumeKitSlot(path.node.attributes);
|
|
668
|
+
path.node.attributes = consumed.attrs;
|
|
669
|
+
const slot = consumed.slot;
|
|
670
|
+
const hasSlotAttr = consumed.found;
|
|
406
671
|
const filename = state.filename ?? "";
|
|
407
672
|
if (fileExclude.test(filename)) return;
|
|
408
673
|
const existing = path.node.attributes.find(
|
|
@@ -448,9 +713,11 @@ function babelPluginEditorMeta({ types: t }, opts = {}) {
|
|
|
448
713
|
}
|
|
449
714
|
}
|
|
450
715
|
const nodeId = computeNodeId(file, line, col, componentName);
|
|
451
|
-
const
|
|
716
|
+
const isKitOrigin = origin === "kit" || hasSlotAttr;
|
|
717
|
+
const movable = isKitOrigin ? false : isMovable(path);
|
|
452
718
|
const parentNodeId = getParentNodeId(path, file);
|
|
453
719
|
const staticPropsObj = extractStaticProps(path.node.attributes);
|
|
720
|
+
const { bindings, owner } = collectPropBindings(path, path.node.attributes);
|
|
454
721
|
const metaObj = t.objectExpression([
|
|
455
722
|
t.objectProperty(t.identifier("nodeId"), t.stringLiteral(nodeId)),
|
|
456
723
|
t.objectProperty(t.identifier("file"), t.stringLiteral(file)),
|
|
@@ -467,6 +734,22 @@ function babelPluginEditorMeta({ types: t }, opts = {}) {
|
|
|
467
734
|
parentNodeId ? t.stringLiteral(parentNodeId) : t.nullLiteral()
|
|
468
735
|
)
|
|
469
736
|
]);
|
|
737
|
+
if (slot !== null) {
|
|
738
|
+
metaObj.properties.push(
|
|
739
|
+
t.objectProperty(t.identifier("slot"), t.stringLiteral(slot))
|
|
740
|
+
);
|
|
741
|
+
}
|
|
742
|
+
if (bindings.length > 0) {
|
|
743
|
+
metaObj.properties.push(
|
|
744
|
+
t.objectProperty(t.identifier("propBindings"), propBindingsToAst(bindings))
|
|
745
|
+
);
|
|
746
|
+
metaObj.properties.push(
|
|
747
|
+
t.objectProperty(
|
|
748
|
+
t.identifier("propOwner"),
|
|
749
|
+
owner ? t.stringLiteral(owner) : t.nullLiteral()
|
|
750
|
+
)
|
|
751
|
+
);
|
|
752
|
+
}
|
|
470
753
|
if (isHostElement && includeHostSourceRef) {
|
|
471
754
|
path.node.attributes.push(
|
|
472
755
|
t.jsxAttribute(
|
|
@@ -475,10 +758,11 @@ function babelPluginEditorMeta({ types: t }, opts = {}) {
|
|
|
475
758
|
)
|
|
476
759
|
);
|
|
477
760
|
}
|
|
761
|
+
const metaThunk = t.arrowFunctionExpression([], metaObj);
|
|
478
762
|
path.node.attributes.push(
|
|
479
763
|
t.jsxAttribute(
|
|
480
764
|
t.jsxIdentifier("__editorMeta"),
|
|
481
|
-
t.jsxExpressionContainer(
|
|
765
|
+
t.jsxExpressionContainer(metaThunk)
|
|
482
766
|
)
|
|
483
767
|
);
|
|
484
768
|
}
|