aem-eds-kit 0.4.7 → 0.4.9
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/CHANGELOG.md +29 -1
- package/README.md +13 -0
- package/dist/bin/eds.js +623 -175
- package/dist/bin/eds.js.map +1 -1
- package/package.json +2 -1
package/dist/bin/eds.js
CHANGED
|
@@ -1424,15 +1424,451 @@ var init_init = __esm({
|
|
|
1424
1424
|
}
|
|
1425
1425
|
});
|
|
1426
1426
|
|
|
1427
|
+
// src/lib/migrate/clientlib.ts
|
|
1428
|
+
import { existsSync as existsSync5 } from "fs";
|
|
1429
|
+
import { readFile as readFile3, readdir } from "fs/promises";
|
|
1430
|
+
import path7 from "path";
|
|
1431
|
+
async function listFiles(dir) {
|
|
1432
|
+
const out = [];
|
|
1433
|
+
const walk3 = async (d) => {
|
|
1434
|
+
for (const e of await readdir(d, { withFileTypes: true })) {
|
|
1435
|
+
const p = path7.join(d, e.name);
|
|
1436
|
+
if (e.isDirectory()) await walk3(p);
|
|
1437
|
+
else out.push(p);
|
|
1438
|
+
}
|
|
1439
|
+
};
|
|
1440
|
+
if (existsSync5(dir)) await walk3(dir);
|
|
1441
|
+
return out;
|
|
1442
|
+
}
|
|
1443
|
+
async function findClientlibDir(componentDir) {
|
|
1444
|
+
if (!existsSync5(componentDir)) return null;
|
|
1445
|
+
const entries = await readdir(componentDir, { withFileTypes: true });
|
|
1446
|
+
const match = entries.find((e) => e.isDirectory() && /clientlib/i.test(e.name));
|
|
1447
|
+
if (match) return path7.join(componentDir, match.name);
|
|
1448
|
+
const hasCss = entries.some((e) => e.isFile() && e.name.endsWith(".css"));
|
|
1449
|
+
return hasCss ? componentDir : null;
|
|
1450
|
+
}
|
|
1451
|
+
async function readClientlibCss(clientlibDir) {
|
|
1452
|
+
const all = await listFiles(clientlibDir);
|
|
1453
|
+
const preprocessed = all.filter((f) => /\.(less|scss|sass)$/i.test(f)).map((f) => path7.relative(clientlibDir, f));
|
|
1454
|
+
let cssFiles;
|
|
1455
|
+
const cssTxt = path7.join(clientlibDir, "css.txt");
|
|
1456
|
+
if (existsSync5(cssTxt)) {
|
|
1457
|
+
const lines = (await readFile3(cssTxt, "utf-8")).split("\n").map((l) => l.trim());
|
|
1458
|
+
let base = clientlibDir;
|
|
1459
|
+
const listed = [];
|
|
1460
|
+
for (const l of lines) {
|
|
1461
|
+
if (!l) continue;
|
|
1462
|
+
const baseMatch = l.match(/^#base\s*=\s*(.+)$/);
|
|
1463
|
+
if (baseMatch) base = path7.join(clientlibDir, baseMatch[1].trim());
|
|
1464
|
+
else if (!l.startsWith("#")) listed.push(l);
|
|
1465
|
+
}
|
|
1466
|
+
cssFiles = listed.map((rel) => path7.join(base, rel)).filter((f) => existsSync5(f) && f.endsWith(".css"));
|
|
1467
|
+
} else {
|
|
1468
|
+
cssFiles = all.filter((f) => f.endsWith(".css"));
|
|
1469
|
+
}
|
|
1470
|
+
const parts = [];
|
|
1471
|
+
for (const f of cssFiles) parts.push(await readFile3(f, "utf-8"));
|
|
1472
|
+
return {
|
|
1473
|
+
css: parts.join("\n\n"),
|
|
1474
|
+
files: cssFiles.map((f) => path7.relative(clientlibDir, f)),
|
|
1475
|
+
preprocessed
|
|
1476
|
+
};
|
|
1477
|
+
}
|
|
1478
|
+
var init_clientlib = __esm({
|
|
1479
|
+
"src/lib/migrate/clientlib.ts"() {
|
|
1480
|
+
"use strict";
|
|
1481
|
+
init_esm_shims();
|
|
1482
|
+
}
|
|
1483
|
+
});
|
|
1484
|
+
|
|
1485
|
+
// src/lib/migrate/dialog.ts
|
|
1486
|
+
import { XMLParser } from "fast-xml-parser";
|
|
1487
|
+
function tagOf(n) {
|
|
1488
|
+
return Object.keys(n).find((k) => k !== ":@") ?? "";
|
|
1489
|
+
}
|
|
1490
|
+
function childrenOf(n) {
|
|
1491
|
+
const t = tagOf(n);
|
|
1492
|
+
const v = n[t];
|
|
1493
|
+
return Array.isArray(v) ? v : [];
|
|
1494
|
+
}
|
|
1495
|
+
function attrsOf(n) {
|
|
1496
|
+
return n[":@"] ?? {};
|
|
1497
|
+
}
|
|
1498
|
+
function stripType(v) {
|
|
1499
|
+
return typeof v === "string" ? v.replace(/^\{[^}]+\}/, "") : v;
|
|
1500
|
+
}
|
|
1501
|
+
function attr(n, name) {
|
|
1502
|
+
return stripType(attrsOf(n)[`@_${name}`]);
|
|
1503
|
+
}
|
|
1504
|
+
function leafComponent(rt, n) {
|
|
1505
|
+
const multiple = attr(n, "multiple") === "true" || attr(n, "multiple") === "{Boolean}true";
|
|
1506
|
+
if (rt.endsWith("/form/textfield")) return "text";
|
|
1507
|
+
if (rt.endsWith("/form/textarea")) return "textarea";
|
|
1508
|
+
if (rt.includes("/richtext")) return "richtext";
|
|
1509
|
+
if (rt.endsWith("/form/numberfield")) return "number";
|
|
1510
|
+
if (rt.endsWith("/form/checkbox")) return "boolean";
|
|
1511
|
+
if (rt.endsWith("/form/radiogroup")) return "radio-group";
|
|
1512
|
+
if (rt.endsWith("/form/select")) return multiple ? "multiselect" : "select";
|
|
1513
|
+
if (rt.endsWith("/form/datepicker")) return "date-time";
|
|
1514
|
+
if (rt.endsWith("/form/pathfield") || rt.endsWith("/form/pathbrowser")) return "aem-content";
|
|
1515
|
+
if (rt.includes("/fileupload") || rt.endsWith("/form/fileupload")) return "reference";
|
|
1516
|
+
if (rt.includes("tagfield") || rt.includes("tagpicker") || rt.includes("tagbrowser"))
|
|
1517
|
+
return "aem-tag";
|
|
1518
|
+
if (rt.includes("contentfragment")) return "aem-content-fragment";
|
|
1519
|
+
if (rt.includes("experiencefragment")) return "aem-experience-fragment";
|
|
1520
|
+
return null;
|
|
1521
|
+
}
|
|
1522
|
+
function isWrapper(rt) {
|
|
1523
|
+
return rt.includes("/foundation/container") || rt.includes("/foundation/fixedcolumns") || rt.includes("/foundation/well") || rt.includes("/foundation/tabs") || rt.includes("/foundation/form/fieldset") || rt.includes("/foundation/accordion");
|
|
1524
|
+
}
|
|
1525
|
+
function valueTypeFor(c) {
|
|
1526
|
+
switch (c) {
|
|
1527
|
+
case "number":
|
|
1528
|
+
return "number";
|
|
1529
|
+
case "boolean":
|
|
1530
|
+
return "boolean";
|
|
1531
|
+
case "date-time":
|
|
1532
|
+
return "date";
|
|
1533
|
+
case "checkbox-group":
|
|
1534
|
+
return "string[]";
|
|
1535
|
+
case "aem-content":
|
|
1536
|
+
case "aem-content-fragment":
|
|
1537
|
+
case "aem-experience-fragment":
|
|
1538
|
+
return void 0;
|
|
1539
|
+
default:
|
|
1540
|
+
return "string";
|
|
1541
|
+
}
|
|
1542
|
+
}
|
|
1543
|
+
function cleanName(raw, fallback) {
|
|
1544
|
+
const n = (raw ?? "").replace(/^\.\//, "").trim();
|
|
1545
|
+
return n || fallback;
|
|
1546
|
+
}
|
|
1547
|
+
function readOptions(fieldNode) {
|
|
1548
|
+
const items = childrenOf(fieldNode).find((c) => tagOf(c) === "items");
|
|
1549
|
+
if (!items) return [];
|
|
1550
|
+
return childrenOf(items).map((opt) => {
|
|
1551
|
+
const value = attr(opt, "value") ?? "";
|
|
1552
|
+
const name = attr(opt, "text") ?? attr(opt, "jcr:title") ?? value;
|
|
1553
|
+
return { name, value };
|
|
1554
|
+
});
|
|
1555
|
+
}
|
|
1556
|
+
function walk(nodes, out, unmapped, counter) {
|
|
1557
|
+
for (const node of nodes) {
|
|
1558
|
+
const rt = attr(node, "sling:resourceType") ?? "";
|
|
1559
|
+
if (rt.endsWith("/foundation/tabs")) {
|
|
1560
|
+
const items = childrenOf(node).find((c) => tagOf(c) === "items");
|
|
1561
|
+
for (const tab of items ? childrenOf(items) : []) {
|
|
1562
|
+
const label = attr(tab, "jcr:title");
|
|
1563
|
+
out.push({ component: "tab", name: cleanName(void 0, tagOf(tab)), label });
|
|
1564
|
+
walk(childrenOf(tab), out, unmapped, counter);
|
|
1565
|
+
}
|
|
1566
|
+
continue;
|
|
1567
|
+
}
|
|
1568
|
+
if (rt.endsWith("/form/multifield")) {
|
|
1569
|
+
const sub = [];
|
|
1570
|
+
walk(childrenOf(node), sub, unmapped, counter);
|
|
1571
|
+
const name = cleanName(attr(node, "name"), `items${counter.i++}`);
|
|
1572
|
+
out.push({
|
|
1573
|
+
component: "container",
|
|
1574
|
+
name,
|
|
1575
|
+
label: attr(node, "fieldLabel") ?? "Items",
|
|
1576
|
+
multi: true,
|
|
1577
|
+
collapsible: true,
|
|
1578
|
+
fields: sub
|
|
1579
|
+
});
|
|
1580
|
+
continue;
|
|
1581
|
+
}
|
|
1582
|
+
const comp = rt ? leafComponent(rt, node) : null;
|
|
1583
|
+
if (comp) {
|
|
1584
|
+
const name = cleanName(attr(node, "name"), `field${counter.i++}`);
|
|
1585
|
+
const field = { component: comp, name };
|
|
1586
|
+
const vt = valueTypeFor(comp);
|
|
1587
|
+
if (vt) field.valueType = vt;
|
|
1588
|
+
const label = attr(node, "fieldLabel") ?? attr(node, "text");
|
|
1589
|
+
if (label) field.label = label;
|
|
1590
|
+
if (comp === "select" || comp === "radio-group" || comp === "multiselect") {
|
|
1591
|
+
const options = readOptions(node);
|
|
1592
|
+
if (options.length) field.options = options;
|
|
1593
|
+
}
|
|
1594
|
+
const def = attr(node, "value") ?? (comp === "boolean" ? attr(node, "checked") : void 0);
|
|
1595
|
+
if (def !== void 0 && def !== "") field.value = comp === "boolean" ? def === "true" : def;
|
|
1596
|
+
out.push(field);
|
|
1597
|
+
continue;
|
|
1598
|
+
}
|
|
1599
|
+
if (rt && attr(node, "name") && !isWrapper(rt)) unmapped.add(rt);
|
|
1600
|
+
walk(childrenOf(node), out, unmapped, counter);
|
|
1601
|
+
}
|
|
1602
|
+
}
|
|
1603
|
+
function parseDialog(xml) {
|
|
1604
|
+
const parser = new XMLParser({
|
|
1605
|
+
ignoreAttributes: false,
|
|
1606
|
+
attributeNamePrefix: "@_",
|
|
1607
|
+
preserveOrder: true,
|
|
1608
|
+
removeNSPrefix: false,
|
|
1609
|
+
trimValues: true
|
|
1610
|
+
});
|
|
1611
|
+
const tree = parser.parse(xml);
|
|
1612
|
+
const root = tree.find((n) => tagOf(n) === "jcr:root");
|
|
1613
|
+
const fields = [];
|
|
1614
|
+
const unmapped = /* @__PURE__ */ new Set();
|
|
1615
|
+
if (root) walk(childrenOf(root), fields, unmapped, { i: 1 });
|
|
1616
|
+
return { fields, unmapped: [...unmapped] };
|
|
1617
|
+
}
|
|
1618
|
+
var init_dialog = __esm({
|
|
1619
|
+
"src/lib/migrate/dialog.ts"() {
|
|
1620
|
+
"use strict";
|
|
1621
|
+
init_esm_shims();
|
|
1622
|
+
}
|
|
1623
|
+
});
|
|
1624
|
+
|
|
1625
|
+
// src/lib/migrate/component.ts
|
|
1626
|
+
import { existsSync as existsSync6 } from "fs";
|
|
1627
|
+
import { readFile as readFile4 } from "fs/promises";
|
|
1628
|
+
import path8 from "path";
|
|
1629
|
+
import { XMLParser as XMLParser2 } from "fast-xml-parser";
|
|
1630
|
+
function findDialogFile(componentDir) {
|
|
1631
|
+
const candidates = [
|
|
1632
|
+
path8.join(componentDir, "_cq_dialog", ".content.xml"),
|
|
1633
|
+
path8.join(componentDir, "_cq_dialog.xml"),
|
|
1634
|
+
path8.join(componentDir, "cq:dialog", ".content.xml")
|
|
1635
|
+
];
|
|
1636
|
+
return candidates.find((c) => existsSync6(c)) ?? null;
|
|
1637
|
+
}
|
|
1638
|
+
async function readComponentTitle(componentDir) {
|
|
1639
|
+
const file = path8.join(componentDir, ".content.xml");
|
|
1640
|
+
if (!existsSync6(file)) return void 0;
|
|
1641
|
+
try {
|
|
1642
|
+
const parser = new XMLParser2({ ignoreAttributes: false, attributeNamePrefix: "@_" });
|
|
1643
|
+
const parsed = parser.parse(await readFile4(file, "utf-8"));
|
|
1644
|
+
const root = parsed["jcr:root"] ?? {};
|
|
1645
|
+
const title = root["@_jcr:title"];
|
|
1646
|
+
return typeof title === "string" ? title.replace(/^\{[^}]+\}/, "") : void 0;
|
|
1647
|
+
} catch {
|
|
1648
|
+
return void 0;
|
|
1649
|
+
}
|
|
1650
|
+
}
|
|
1651
|
+
async function readDialogFields(componentDir) {
|
|
1652
|
+
const dialog = findDialogFile(componentDir);
|
|
1653
|
+
if (!dialog) return null;
|
|
1654
|
+
return parseDialog(await readFile4(dialog, "utf-8"));
|
|
1655
|
+
}
|
|
1656
|
+
function migratedModelFile(blockName, title, fields) {
|
|
1657
|
+
const model = {
|
|
1658
|
+
definitions: [
|
|
1659
|
+
{
|
|
1660
|
+
title,
|
|
1661
|
+
id: blockName,
|
|
1662
|
+
plugins: {
|
|
1663
|
+
xwalk: {
|
|
1664
|
+
page: {
|
|
1665
|
+
resourceType: "core/franklin/components/block/v1/block",
|
|
1666
|
+
template: { name: title, model: blockName }
|
|
1667
|
+
}
|
|
1668
|
+
}
|
|
1669
|
+
}
|
|
1670
|
+
}
|
|
1671
|
+
],
|
|
1672
|
+
models: [{ id: blockName, fields }],
|
|
1673
|
+
filters: []
|
|
1674
|
+
};
|
|
1675
|
+
return `${JSON.stringify(model, null, 2)}
|
|
1676
|
+
`;
|
|
1677
|
+
}
|
|
1678
|
+
function migratedBlockJs(blockName, fields) {
|
|
1679
|
+
const hasContainer = fields.some((f) => f.component === "container" && f.multi);
|
|
1680
|
+
const body = hasContainer ? ` // This block was migrated from a classic AEM component with a multifield.
|
|
1681
|
+
// Each child row is one repeated item - enhance them here.
|
|
1682
|
+
[...block.children].forEach((row) => {
|
|
1683
|
+
row.classList.add('${blockName}-item');
|
|
1684
|
+
});` : ` // Migrated from a classic AEM component. The authored fields arrive as
|
|
1685
|
+
// rows; read and enhance them here (port the old HTL logic as needed).`;
|
|
1686
|
+
return `// Block: ${blockName}
|
|
1687
|
+
// Migrated from a classic AEM component by \`eds migrate component\`.
|
|
1688
|
+
// TODO: port the component's HTL/JS behaviour into this decorator.
|
|
1689
|
+
export default function decorate(block) {
|
|
1690
|
+
block.classList.add('${blockName}');
|
|
1691
|
+
${body}
|
|
1692
|
+
}
|
|
1693
|
+
`;
|
|
1694
|
+
}
|
|
1695
|
+
function migratedBlockCss(blockName) {
|
|
1696
|
+
return `/* Block: ${blockName} */
|
|
1697
|
+
/* Migrated from a classic AEM component. Bring the component's styles here */
|
|
1698
|
+
/* (from its clientlib or the rendered page) and keep them scoped to the block. */
|
|
1699
|
+
.${blockName} {
|
|
1700
|
+
}
|
|
1701
|
+
`;
|
|
1702
|
+
}
|
|
1703
|
+
var init_component = __esm({
|
|
1704
|
+
"src/lib/migrate/component.ts"() {
|
|
1705
|
+
"use strict";
|
|
1706
|
+
init_esm_shims();
|
|
1707
|
+
init_dialog();
|
|
1708
|
+
}
|
|
1709
|
+
});
|
|
1710
|
+
|
|
1711
|
+
// src/commands/migrate.ts
|
|
1712
|
+
var migrate_exports = {};
|
|
1713
|
+
__export(migrate_exports, {
|
|
1714
|
+
migrateComponent: () => migrateComponent
|
|
1715
|
+
});
|
|
1716
|
+
import { existsSync as existsSync7 } from "fs";
|
|
1717
|
+
import { mkdir as mkdir3, writeFile as writeFile5 } from "fs/promises";
|
|
1718
|
+
import path9 from "path";
|
|
1719
|
+
function clientlibBlockCss(blockName, css, files) {
|
|
1720
|
+
return `/* Block: ${blockName} */
|
|
1721
|
+
/* Migrated from the component clientlib: ${files.join(", ")}. */
|
|
1722
|
+
/* TODO: review selectors and scope them under .${blockName} (and port any LESS/SCSS). */
|
|
1723
|
+
|
|
1724
|
+
${css.trim()}
|
|
1725
|
+
`;
|
|
1726
|
+
}
|
|
1727
|
+
function previewFields(fields, depth = 0) {
|
|
1728
|
+
const lines = [];
|
|
1729
|
+
for (const f of fields) {
|
|
1730
|
+
const indent = " ".repeat(depth);
|
|
1731
|
+
if (f.component === "tab") {
|
|
1732
|
+
lines.push(`${indent}${brand.blue("\u25B8")} ${f.label ?? f.name}`);
|
|
1733
|
+
} else {
|
|
1734
|
+
const opts = f.options?.length ? ` (${f.options.length} options)` : "";
|
|
1735
|
+
const multi = f.multi ? " \xB7multi" : "";
|
|
1736
|
+
const label = f.label ? `- ${f.label}` : "";
|
|
1737
|
+
lines.push(`${indent}${brand.accent(f.component)}${multi} ${f.name}${opts} ${label}`);
|
|
1738
|
+
if (f.fields?.length) lines.push(...previewFields(f.fields, depth + 1));
|
|
1739
|
+
}
|
|
1740
|
+
}
|
|
1741
|
+
return lines;
|
|
1742
|
+
}
|
|
1743
|
+
function countLeaves(fields) {
|
|
1744
|
+
let n = 0;
|
|
1745
|
+
for (const f of fields) {
|
|
1746
|
+
if (f.component === "tab") continue;
|
|
1747
|
+
n += 1;
|
|
1748
|
+
if (f.fields) n += countLeaves(f.fields);
|
|
1749
|
+
}
|
|
1750
|
+
return n;
|
|
1751
|
+
}
|
|
1752
|
+
async function migrateComponent(dirArg, options = {}) {
|
|
1753
|
+
const projectRoot = findProjectRoot();
|
|
1754
|
+
if (!projectRoot) {
|
|
1755
|
+
logger.error("Not inside an EDS project (no EDS project markers found).");
|
|
1756
|
+
process.exitCode = 1;
|
|
1757
|
+
return;
|
|
1758
|
+
}
|
|
1759
|
+
await logger.logoOnceAnimated("Migrate component");
|
|
1760
|
+
const { input, confirm } = await import("@inquirer/prompts");
|
|
1761
|
+
const interactive = !options.yes;
|
|
1762
|
+
let componentDir = dirArg;
|
|
1763
|
+
if (!componentDir && interactive) {
|
|
1764
|
+
componentDir = await input({
|
|
1765
|
+
message: "Path to the classic component folder",
|
|
1766
|
+
validate: (v) => existsSync7(v.trim()) || "Folder not found"
|
|
1767
|
+
});
|
|
1768
|
+
}
|
|
1769
|
+
if (!componentDir) {
|
|
1770
|
+
logger.error("Provide the path to the classic component folder.");
|
|
1771
|
+
process.exitCode = 1;
|
|
1772
|
+
return;
|
|
1773
|
+
}
|
|
1774
|
+
componentDir = path9.resolve(componentDir.trim());
|
|
1775
|
+
if (!findDialogFile(componentDir)) {
|
|
1776
|
+
logger.error(`No Touch UI dialog (_cq_dialog/.content.xml) found in ${componentDir}.`);
|
|
1777
|
+
process.exitCode = 1;
|
|
1778
|
+
return;
|
|
1779
|
+
}
|
|
1780
|
+
const parsed = await readDialogFields(componentDir);
|
|
1781
|
+
if (!parsed || parsed.fields.length === 0) {
|
|
1782
|
+
logger.warn("Dialog found but no mappable fields were detected.");
|
|
1783
|
+
if (parsed?.unmapped.length)
|
|
1784
|
+
logger.info(`Unmapped resourceTypes: ${parsed.unmapped.join(", ")}`);
|
|
1785
|
+
process.exitCode = 1;
|
|
1786
|
+
return;
|
|
1787
|
+
}
|
|
1788
|
+
const title = await readComponentTitle(componentDir) ?? path9.basename(componentDir);
|
|
1789
|
+
const blockName = options.name && slug2(options.name) || (interactive ? slug2(await input({ message: "Block name", default: slug2(title) })) : slug2(title));
|
|
1790
|
+
logger.info(heading("Mapped fields", `${countLeaves(parsed.fields)} from dialog`));
|
|
1791
|
+
for (const line of previewFields(parsed.fields)) logger.info(` ${line}`);
|
|
1792
|
+
if (parsed.unmapped.length) {
|
|
1793
|
+
logger.info("");
|
|
1794
|
+
logger.warn(`Skipped (unrecognised): ${parsed.unmapped.join(", ")}`);
|
|
1795
|
+
}
|
|
1796
|
+
logger.info("");
|
|
1797
|
+
if (interactive) {
|
|
1798
|
+
const go = await confirm({ message: `Generate block "${blockName}"?`, default: true });
|
|
1799
|
+
if (!go) {
|
|
1800
|
+
logger.info("Cancelled.");
|
|
1801
|
+
return;
|
|
1802
|
+
}
|
|
1803
|
+
}
|
|
1804
|
+
const blockDir = path9.join(projectRoot, "blocks", blockName);
|
|
1805
|
+
if (existsSync7(blockDir)) {
|
|
1806
|
+
logger.error(
|
|
1807
|
+
`Block "${blockName}" already exists at blocks/${blockName}. Use --name to pick another.`
|
|
1808
|
+
);
|
|
1809
|
+
process.exitCode = 1;
|
|
1810
|
+
return;
|
|
1811
|
+
}
|
|
1812
|
+
const clibDir = options.clientlib ? path9.resolve(options.clientlib.trim()) : await findClientlibDir(componentDir);
|
|
1813
|
+
let cssContent = migratedBlockCss(blockName);
|
|
1814
|
+
let cssMessage = "empty - add styles from clientlib / rendered CSS";
|
|
1815
|
+
let preprocessedNote = [];
|
|
1816
|
+
if (clibDir && existsSync7(clibDir)) {
|
|
1817
|
+
const lib = await readClientlibCss(clibDir);
|
|
1818
|
+
if (lib.css.trim()) {
|
|
1819
|
+
cssContent = clientlibBlockCss(blockName, lib.css, lib.files);
|
|
1820
|
+
cssMessage = `from clientlib (${lib.files.length} file(s)) - review & scope`;
|
|
1821
|
+
}
|
|
1822
|
+
preprocessedNote = lib.preprocessed;
|
|
1823
|
+
}
|
|
1824
|
+
await mkdir3(blockDir, { recursive: true });
|
|
1825
|
+
await writeFile5(
|
|
1826
|
+
path9.join(blockDir, `${blockName}.js`),
|
|
1827
|
+
migratedBlockJs(blockName, parsed.fields)
|
|
1828
|
+
);
|
|
1829
|
+
await writeFile5(path9.join(blockDir, `${blockName}.css`), cssContent);
|
|
1830
|
+
await writeFile5(
|
|
1831
|
+
path9.join(blockDir, `_${blockName}.json`),
|
|
1832
|
+
migratedModelFile(blockName, title, parsed.fields)
|
|
1833
|
+
);
|
|
1834
|
+
logger.info(heading("Created"));
|
|
1835
|
+
const files = [`${blockName}.js`, `${blockName}.css`, `_${blockName}.json`];
|
|
1836
|
+
const w = columnWidth(files);
|
|
1837
|
+
logger.info(accentLine(`${blockName}.js`, "decorator stub (port HTL logic)", w));
|
|
1838
|
+
logger.info(accentLine(`${blockName}.css`, cssMessage, w));
|
|
1839
|
+
logger.info(accentLine(`_${blockName}.json`, "Universal Editor model", w));
|
|
1840
|
+
if (preprocessedNote.length) {
|
|
1841
|
+
logger.info("");
|
|
1842
|
+
logger.warn(`LESS/SCSS found (needs a build, not copied): ${preprocessedNote.join(", ")}`);
|
|
1843
|
+
}
|
|
1844
|
+
logger.info("");
|
|
1845
|
+
logger.info(
|
|
1846
|
+
box([`"${blockName}" migrated. Next: add CSS, then \`eds block preview ${blockName}\``])
|
|
1847
|
+
);
|
|
1848
|
+
}
|
|
1849
|
+
var slug2;
|
|
1850
|
+
var init_migrate = __esm({
|
|
1851
|
+
"src/commands/migrate.ts"() {
|
|
1852
|
+
"use strict";
|
|
1853
|
+
init_esm_shims();
|
|
1854
|
+
init_logger();
|
|
1855
|
+
init_clientlib();
|
|
1856
|
+
init_component();
|
|
1857
|
+
init_project();
|
|
1858
|
+
init_ui();
|
|
1859
|
+
slug2 = (s) => s.trim().toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
1860
|
+
}
|
|
1861
|
+
});
|
|
1862
|
+
|
|
1427
1863
|
// src/commands/block/create.ts
|
|
1428
1864
|
var create_exports = {};
|
|
1429
1865
|
__export(create_exports, {
|
|
1430
1866
|
createBlock: () => createBlock,
|
|
1431
1867
|
ueModelFor: () => ueModelFor
|
|
1432
1868
|
});
|
|
1433
|
-
import { existsSync as
|
|
1434
|
-
import { mkdir as
|
|
1435
|
-
import
|
|
1869
|
+
import { existsSync as existsSync8 } from "fs";
|
|
1870
|
+
import { mkdir as mkdir4, writeFile as writeFile6 } from "fs/promises";
|
|
1871
|
+
import path10 from "path";
|
|
1436
1872
|
import chalk4 from "chalk";
|
|
1437
1873
|
function titleCase(name) {
|
|
1438
1874
|
return name.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
@@ -1511,13 +1947,13 @@ async function createBlock(name, options = {}) {
|
|
|
1511
1947
|
process.exitCode = 1;
|
|
1512
1948
|
return;
|
|
1513
1949
|
}
|
|
1514
|
-
const blocksDir =
|
|
1515
|
-
if (
|
|
1950
|
+
const blocksDir = path10.join(projectRoot, "blocks", name);
|
|
1951
|
+
if (existsSync8(blocksDir)) {
|
|
1516
1952
|
logger.error(`Block "${name}" already exists at ${blocksDir}`);
|
|
1517
1953
|
process.exitCode = 1;
|
|
1518
1954
|
return;
|
|
1519
1955
|
}
|
|
1520
|
-
await
|
|
1956
|
+
await mkdir4(blocksDir, { recursive: true });
|
|
1521
1957
|
const jsContent = `export default function decorate(block) {
|
|
1522
1958
|
// TODO: implement ${name} block
|
|
1523
1959
|
}
|
|
@@ -1526,14 +1962,14 @@ async function createBlock(name, options = {}) {
|
|
|
1526
1962
|
/* TODO: style ${name} block */
|
|
1527
1963
|
}
|
|
1528
1964
|
`;
|
|
1529
|
-
await
|
|
1530
|
-
await
|
|
1965
|
+
await writeFile6(path10.join(blocksDir, `${name}.js`), jsContent);
|
|
1966
|
+
await writeFile6(path10.join(blocksDir, `${name}.css`), cssContent);
|
|
1531
1967
|
const withUe = options.ueModel !== false;
|
|
1532
1968
|
if (withUe) {
|
|
1533
|
-
await
|
|
1969
|
+
await writeFile6(path10.join(blocksDir, `_${name}.json`), ueModelFor(name));
|
|
1534
1970
|
}
|
|
1535
1971
|
logger.success(
|
|
1536
|
-
`Block "${name}" created at ${chalk4.cyan(
|
|
1972
|
+
`Block "${name}" created at ${chalk4.cyan(path10.relative(projectRoot, blocksDir))}${withUe ? chalk4.dim(" (+ Universal Editor model)") : ""}`
|
|
1537
1973
|
);
|
|
1538
1974
|
}
|
|
1539
1975
|
var init_create = __esm({
|
|
@@ -1547,10 +1983,10 @@ var init_create = __esm({
|
|
|
1547
1983
|
});
|
|
1548
1984
|
|
|
1549
1985
|
// src/lib/agents/detect.ts
|
|
1550
|
-
import { existsSync as
|
|
1551
|
-
import { readFile as
|
|
1986
|
+
import { existsSync as existsSync9 } from "fs";
|
|
1987
|
+
import { readFile as readFile5 } from "fs/promises";
|
|
1552
1988
|
import { homedir } from "os";
|
|
1553
|
-
import
|
|
1989
|
+
import path11 from "path";
|
|
1554
1990
|
async function whichBinary(name) {
|
|
1555
1991
|
const { execaCommand } = await import("execa");
|
|
1556
1992
|
try {
|
|
@@ -1578,8 +2014,8 @@ function findFigmaServerKey(node) {
|
|
|
1578
2014
|
async function findFigmaMcpServer(configPaths) {
|
|
1579
2015
|
for (const configPath of configPaths) {
|
|
1580
2016
|
try {
|
|
1581
|
-
if (!
|
|
1582
|
-
const content = await
|
|
2017
|
+
if (!existsSync9(configPath)) continue;
|
|
2018
|
+
const content = await readFile5(configPath, "utf-8");
|
|
1583
2019
|
try {
|
|
1584
2020
|
const key = findFigmaServerKey(JSON.parse(content));
|
|
1585
2021
|
if (key) return key;
|
|
@@ -1601,7 +2037,7 @@ async function detectAgent(preferred) {
|
|
|
1601
2037
|
return {
|
|
1602
2038
|
type: def.type,
|
|
1603
2039
|
path: binPath,
|
|
1604
|
-
configDir:
|
|
2040
|
+
configDir: existsSync9(def.configDir) ? def.configDir : void 0,
|
|
1605
2041
|
hasFigmaMcp: !!figmaMcpServerName,
|
|
1606
2042
|
figmaMcpServerName
|
|
1607
2043
|
};
|
|
@@ -1616,7 +2052,7 @@ async function detectAgent(preferred) {
|
|
|
1616
2052
|
return {
|
|
1617
2053
|
type: def.type,
|
|
1618
2054
|
path: binPath,
|
|
1619
|
-
configDir:
|
|
2055
|
+
configDir: existsSync9(def.configDir) ? def.configDir : void 0,
|
|
1620
2056
|
hasFigmaMcp: !!figmaMcpServerName,
|
|
1621
2057
|
figmaMcpServerName
|
|
1622
2058
|
};
|
|
@@ -1633,7 +2069,7 @@ async function detectAllAgents() {
|
|
|
1633
2069
|
agents.push({
|
|
1634
2070
|
type: def.type,
|
|
1635
2071
|
path: binPath,
|
|
1636
|
-
configDir:
|
|
2072
|
+
configDir: existsSync9(def.configDir) ? def.configDir : void 0,
|
|
1637
2073
|
hasFigmaMcp: !!figmaMcpServerName,
|
|
1638
2074
|
figmaMcpServerName
|
|
1639
2075
|
});
|
|
@@ -1651,22 +2087,22 @@ var init_detect = __esm({
|
|
|
1651
2087
|
{
|
|
1652
2088
|
type: "claude",
|
|
1653
2089
|
binary: "claude",
|
|
1654
|
-
configDir:
|
|
2090
|
+
configDir: path11.join(homedir(), ".claude"),
|
|
1655
2091
|
mcpConfigPaths: [
|
|
1656
|
-
|
|
1657
|
-
|
|
2092
|
+
path11.join(homedir(), ".claude", "plugins.json"),
|
|
2093
|
+
path11.join(homedir(), ".claude.json")
|
|
1658
2094
|
]
|
|
1659
2095
|
},
|
|
1660
2096
|
{
|
|
1661
2097
|
type: "cursor",
|
|
1662
2098
|
binary: "cursor",
|
|
1663
|
-
configDir:
|
|
1664
|
-
mcpConfigPaths: [
|
|
2099
|
+
configDir: path11.join(homedir(), ".cursor"),
|
|
2100
|
+
mcpConfigPaths: [path11.join(homedir(), ".cursor", "mcp.json")]
|
|
1665
2101
|
},
|
|
1666
2102
|
{
|
|
1667
2103
|
type: "codex",
|
|
1668
2104
|
binary: "codex",
|
|
1669
|
-
configDir:
|
|
2105
|
+
configDir: path11.join(homedir(), ".codex"),
|
|
1670
2106
|
mcpConfigPaths: []
|
|
1671
2107
|
}
|
|
1672
2108
|
];
|
|
@@ -1674,23 +2110,23 @@ var init_detect = __esm({
|
|
|
1674
2110
|
});
|
|
1675
2111
|
|
|
1676
2112
|
// src/lib/agents/invoke.ts
|
|
1677
|
-
import { mkdir as
|
|
2113
|
+
import { mkdir as mkdir5, readFile as readFile6, writeFile as writeFile7 } from "fs/promises";
|
|
1678
2114
|
import { tmpdir } from "os";
|
|
1679
|
-
import
|
|
2115
|
+
import path12 from "path";
|
|
1680
2116
|
import readline from "readline";
|
|
1681
2117
|
import chalk5 from "chalk";
|
|
1682
2118
|
async function savePromptToFile(prompt, projectRoot) {
|
|
1683
|
-
const base = projectRoot ?
|
|
1684
|
-
const dir =
|
|
1685
|
-
await
|
|
2119
|
+
const base = projectRoot ? path12.join(projectRoot, "tmp") : tmpdir();
|
|
2120
|
+
const dir = path12.join(base, "eds-cli");
|
|
2121
|
+
await mkdir5(dir, { recursive: true });
|
|
1686
2122
|
const filename = `from-design-${Date.now()}.md`;
|
|
1687
|
-
const filePath =
|
|
1688
|
-
await
|
|
2123
|
+
const filePath = path12.join(dir, filename);
|
|
2124
|
+
await writeFile7(filePath, prompt, "utf-8");
|
|
1689
2125
|
return filePath;
|
|
1690
2126
|
}
|
|
1691
2127
|
async function invokeAgent(agent, promptFile, cwd) {
|
|
1692
2128
|
const { execa } = await import("execa");
|
|
1693
|
-
const prompt = await
|
|
2129
|
+
const prompt = await readFile6(promptFile, "utf-8");
|
|
1694
2130
|
try {
|
|
1695
2131
|
switch (agent.type) {
|
|
1696
2132
|
case "claude": {
|
|
@@ -1830,7 +2266,7 @@ function toolLabel(name, input, cwd) {
|
|
|
1830
2266
|
const rel = (key) => {
|
|
1831
2267
|
const p = input?.[key];
|
|
1832
2268
|
if (typeof p !== "string") return "";
|
|
1833
|
-
return p.startsWith(cwd) ?
|
|
2269
|
+
return p.startsWith(cwd) ? path12.relative(cwd, p) : path12.basename(p);
|
|
1834
2270
|
};
|
|
1835
2271
|
if (name.includes("figma")) {
|
|
1836
2272
|
const short = name.split("__").pop() ?? name;
|
|
@@ -1861,13 +2297,13 @@ var init_invoke = __esm({
|
|
|
1861
2297
|
});
|
|
1862
2298
|
|
|
1863
2299
|
// src/lib/config.ts
|
|
1864
|
-
import { existsSync as
|
|
1865
|
-
import { readFile as
|
|
2300
|
+
import { existsSync as existsSync10 } from "fs";
|
|
2301
|
+
import { readFile as readFile7 } from "fs/promises";
|
|
1866
2302
|
import { homedir as homedir2 } from "os";
|
|
1867
|
-
import
|
|
2303
|
+
import path13 from "path";
|
|
1868
2304
|
async function loadJsonFile(filePath) {
|
|
1869
2305
|
try {
|
|
1870
|
-
const content = await
|
|
2306
|
+
const content = await readFile7(filePath, "utf-8");
|
|
1871
2307
|
return JSON.parse(content);
|
|
1872
2308
|
} catch {
|
|
1873
2309
|
return void 0;
|
|
@@ -1875,7 +2311,7 @@ async function loadJsonFile(filePath) {
|
|
|
1875
2311
|
}
|
|
1876
2312
|
async function loadConfig(projectRoot) {
|
|
1877
2313
|
const globalRaw = await loadJsonFile(GLOBAL_CONFIG_PATH);
|
|
1878
|
-
const projectRaw = projectRoot ? await loadJsonFile(
|
|
2314
|
+
const projectRaw = projectRoot ? await loadJsonFile(path13.join(projectRoot, PROJECT_CONFIG_NAME)) : void 0;
|
|
1879
2315
|
const merged = {
|
|
1880
2316
|
...typeof globalRaw === "object" && globalRaw !== null ? globalRaw : {},
|
|
1881
2317
|
...typeof projectRaw === "object" && projectRaw !== null ? projectRaw : {}
|
|
@@ -1894,7 +2330,7 @@ function globalConfigPath() {
|
|
|
1894
2330
|
return GLOBAL_CONFIG_PATH;
|
|
1895
2331
|
}
|
|
1896
2332
|
function globalConfigExists() {
|
|
1897
|
-
return
|
|
2333
|
+
return existsSync10(GLOBAL_CONFIG_PATH);
|
|
1898
2334
|
}
|
|
1899
2335
|
var GLOBAL_CONFIG_DIR, GLOBAL_CONFIG_PATH, PROJECT_CONFIG_NAME;
|
|
1900
2336
|
var init_config = __esm({
|
|
@@ -1903,8 +2339,8 @@ var init_config = __esm({
|
|
|
1903
2339
|
init_esm_shims();
|
|
1904
2340
|
init_logger();
|
|
1905
2341
|
init_schemas();
|
|
1906
|
-
GLOBAL_CONFIG_DIR =
|
|
1907
|
-
GLOBAL_CONFIG_PATH =
|
|
2342
|
+
GLOBAL_CONFIG_DIR = path13.join(homedir2(), ".eds");
|
|
2343
|
+
GLOBAL_CONFIG_PATH = path13.join(GLOBAL_CONFIG_DIR, "config.json");
|
|
1908
2344
|
PROJECT_CONFIG_NAME = ".edsrc.json";
|
|
1909
2345
|
}
|
|
1910
2346
|
});
|
|
@@ -1954,9 +2390,9 @@ var init_node_id = __esm({
|
|
|
1954
2390
|
});
|
|
1955
2391
|
|
|
1956
2392
|
// src/lib/figma/prompt-builder.ts
|
|
1957
|
-
import { existsSync as
|
|
1958
|
-
import { readFile as
|
|
1959
|
-
import
|
|
2393
|
+
import { existsSync as existsSync11 } from "fs";
|
|
2394
|
+
import { readFile as readFile8 } from "fs/promises";
|
|
2395
|
+
import path14 from "path";
|
|
1960
2396
|
function contentSourceGuidance(source, cfHint, blockName) {
|
|
1961
2397
|
if (!source || source === "document" || source === "ue") return "";
|
|
1962
2398
|
const q = cfHint ? ` (model / persisted query: \`${cfHint}\`)` : "";
|
|
@@ -2168,10 +2604,10 @@ ${tokensHint}
|
|
|
2168
2604
|
`;
|
|
2169
2605
|
}
|
|
2170
2606
|
async function getTokensHint(projectRoot) {
|
|
2171
|
-
const stylesPath =
|
|
2172
|
-
if (!
|
|
2607
|
+
const stylesPath = path14.join(projectRoot, "styles", "styles.css");
|
|
2608
|
+
if (!existsSync11(stylesPath)) return "";
|
|
2173
2609
|
try {
|
|
2174
|
-
const css = await
|
|
2610
|
+
const css = await readFile8(stylesPath, "utf-8");
|
|
2175
2611
|
const rootMatch = css.match(/:root\s*\{([^}]+)\}/);
|
|
2176
2612
|
if (!rootMatch) return "";
|
|
2177
2613
|
const props = rootMatch[1].split("\n").filter((line) => line.trim().startsWith("--")).map((line) => line.trim()).join("\n ");
|
|
@@ -2311,11 +2747,11 @@ var init_harness = __esm({
|
|
|
2311
2747
|
});
|
|
2312
2748
|
|
|
2313
2749
|
// src/lib/preview/server.ts
|
|
2314
|
-
import { createReadStream, existsSync as
|
|
2750
|
+
import { createReadStream, existsSync as existsSync12, statSync } from "fs";
|
|
2315
2751
|
import http from "http";
|
|
2316
|
-
import
|
|
2752
|
+
import path15 from "path";
|
|
2317
2753
|
function startServer(root, routes, port, host = "127.0.0.1") {
|
|
2318
|
-
const resolvedRoot =
|
|
2754
|
+
const resolvedRoot = path15.resolve(root);
|
|
2319
2755
|
const clients = /* @__PURE__ */ new Set();
|
|
2320
2756
|
const server = http.createServer((req, res) => {
|
|
2321
2757
|
const urlPath = decodeURIComponent((req.url ?? "/").split("?")[0]);
|
|
@@ -2341,19 +2777,19 @@ function startServer(root, routes, port, host = "127.0.0.1") {
|
|
|
2341
2777
|
res.end(route.body);
|
|
2342
2778
|
return;
|
|
2343
2779
|
}
|
|
2344
|
-
const filePath =
|
|
2780
|
+
const filePath = path15.join(resolvedRoot, urlPath);
|
|
2345
2781
|
if (!filePath.startsWith(resolvedRoot)) {
|
|
2346
2782
|
res.writeHead(403);
|
|
2347
2783
|
res.end("Forbidden");
|
|
2348
2784
|
return;
|
|
2349
2785
|
}
|
|
2350
|
-
if (!
|
|
2786
|
+
if (!existsSync12(filePath) || !statSync(filePath).isFile()) {
|
|
2351
2787
|
res.writeHead(404, { "content-type": "text/plain" });
|
|
2352
2788
|
res.end(`Not found: ${urlPath}`);
|
|
2353
2789
|
return;
|
|
2354
2790
|
}
|
|
2355
2791
|
res.writeHead(200, {
|
|
2356
|
-
"content-type": MIME[
|
|
2792
|
+
"content-type": MIME[path15.extname(filePath).toLowerCase()] ?? "application/octet-stream"
|
|
2357
2793
|
});
|
|
2358
2794
|
createReadStream(filePath).pipe(res);
|
|
2359
2795
|
});
|
|
@@ -2417,9 +2853,9 @@ var preview_exports = {};
|
|
|
2417
2853
|
__export(preview_exports, {
|
|
2418
2854
|
previewBlock: () => previewBlock
|
|
2419
2855
|
});
|
|
2420
|
-
import { existsSync as
|
|
2421
|
-
import { readFile as
|
|
2422
|
-
import
|
|
2856
|
+
import { existsSync as existsSync13, watch } from "fs";
|
|
2857
|
+
import { readFile as readFile9 } from "fs/promises";
|
|
2858
|
+
import path16 from "path";
|
|
2423
2859
|
import chalk6 from "chalk";
|
|
2424
2860
|
function labelFor(width) {
|
|
2425
2861
|
if (width <= 480) return `${width} mobile`;
|
|
@@ -2472,30 +2908,30 @@ async function previewBlock(name, options = {}) {
|
|
|
2472
2908
|
process.exitCode = 1;
|
|
2473
2909
|
return;
|
|
2474
2910
|
}
|
|
2475
|
-
const blockDir =
|
|
2476
|
-
if (!
|
|
2911
|
+
const blockDir = path16.join(projectRoot, "blocks", name);
|
|
2912
|
+
if (!existsSync13(blockDir)) {
|
|
2477
2913
|
logger.error(`Block "${name}" not found at blocks/${name}/.`);
|
|
2478
2914
|
process.exitCode = 1;
|
|
2479
2915
|
return;
|
|
2480
2916
|
}
|
|
2481
|
-
if (!
|
|
2917
|
+
if (!existsSync13(path16.join(blockDir, `${name}.css`)) && !existsSync13(path16.join(blockDir, `${name}.js`))) {
|
|
2482
2918
|
logger.error(`Block "${name}" has no ${name}.css / ${name}.js to preview.`);
|
|
2483
2919
|
process.exitCode = 1;
|
|
2484
2920
|
return;
|
|
2485
2921
|
}
|
|
2486
2922
|
let meta = null;
|
|
2487
|
-
const metaPath =
|
|
2488
|
-
if (
|
|
2923
|
+
const metaPath = path16.join(blockDir, ".eds-meta.json");
|
|
2924
|
+
if (existsSync13(metaPath)) {
|
|
2489
2925
|
try {
|
|
2490
|
-
meta = JSON.parse(await
|
|
2926
|
+
meta = JSON.parse(await readFile9(metaPath, "utf-8"));
|
|
2491
2927
|
} catch {
|
|
2492
2928
|
}
|
|
2493
2929
|
}
|
|
2494
|
-
const samplePath =
|
|
2930
|
+
const samplePath = path16.join(blockDir, `_${name}.preview.html`);
|
|
2495
2931
|
let sampleContent;
|
|
2496
2932
|
let placeholder = false;
|
|
2497
|
-
if (
|
|
2498
|
-
sampleContent = await
|
|
2933
|
+
if (existsSync13(samplePath)) {
|
|
2934
|
+
sampleContent = await readFile9(samplePath, "utf-8");
|
|
2499
2935
|
} else {
|
|
2500
2936
|
sampleContent = defaultSample(name);
|
|
2501
2937
|
placeholder = true;
|
|
@@ -2576,9 +3012,9 @@ var from_design_exports = {};
|
|
|
2576
3012
|
__export(from_design_exports, {
|
|
2577
3013
|
blockFromDesign: () => blockFromDesign
|
|
2578
3014
|
});
|
|
2579
|
-
import { existsSync as
|
|
2580
|
-
import { readFile as
|
|
2581
|
-
import
|
|
3015
|
+
import { existsSync as existsSync14 } from "fs";
|
|
3016
|
+
import { readFile as readFile10, writeFile as writeFile8 } from "fs/promises";
|
|
3017
|
+
import path17 from "path";
|
|
2582
3018
|
import chalk7 from "chalk";
|
|
2583
3019
|
import ora from "ora";
|
|
2584
3020
|
async function previewRunning(port = 8777) {
|
|
@@ -2759,7 +3195,7 @@ async function blockFromDesign(figmaUrlArg, optionsArg) {
|
|
|
2759
3195
|
screenshot: options.screenshot !== false
|
|
2760
3196
|
});
|
|
2761
3197
|
const promptFile = await savePromptToFile(prompt, projectRoot);
|
|
2762
|
-
const hasTokens =
|
|
3198
|
+
const hasTokens = existsSync14(path17.join(projectRoot, "styles", "styles.css"));
|
|
2763
3199
|
promptSpinner.succeed(
|
|
2764
3200
|
hasTokens ? `Loaded design tokens ${chalk7.dim("styles/styles.css")}` : `Built prompt ${chalk7.dim("no project tokens found")}`
|
|
2765
3201
|
);
|
|
@@ -2819,9 +3255,9 @@ async function blockFromDesign(figmaUrlArg, optionsArg) {
|
|
|
2819
3255
|
process.exitCode = 1;
|
|
2820
3256
|
return;
|
|
2821
3257
|
}
|
|
2822
|
-
const blockDir =
|
|
3258
|
+
const blockDir = path17.join(projectRoot, "blocks", blockName);
|
|
2823
3259
|
const ok = await verifyGeneratedBlock(blockDir, blockName, options.ueModel !== false);
|
|
2824
|
-
if (
|
|
3260
|
+
if (existsSync14(blockDir)) {
|
|
2825
3261
|
const meta = {
|
|
2826
3262
|
provider,
|
|
2827
3263
|
designRef,
|
|
@@ -2831,7 +3267,7 @@ async function blockFromDesign(figmaUrlArg, optionsArg) {
|
|
|
2831
3267
|
promptVersion: PROMPT_VERSION,
|
|
2832
3268
|
agentUsed: agent.type
|
|
2833
3269
|
};
|
|
2834
|
-
await
|
|
3270
|
+
await writeFile8(path17.join(blockDir, ".eds-meta.json"), `${JSON.stringify(meta, null, 2)}
|
|
2835
3271
|
`);
|
|
2836
3272
|
}
|
|
2837
3273
|
if (!ok) {
|
|
@@ -2860,10 +3296,10 @@ async function blockFromDesign(figmaUrlArg, optionsArg) {
|
|
|
2860
3296
|
}
|
|
2861
3297
|
async function verifyGeneratedBlock(blockDir, blockName, withUeModel) {
|
|
2862
3298
|
const checks = [];
|
|
2863
|
-
const jsPath =
|
|
2864
|
-
const cssPath =
|
|
2865
|
-
const hasJs =
|
|
2866
|
-
const hasCss =
|
|
3299
|
+
const jsPath = path17.join(blockDir, `${blockName}.js`);
|
|
3300
|
+
const cssPath = path17.join(blockDir, `${blockName}.css`);
|
|
3301
|
+
const hasJs = existsSync14(jsPath);
|
|
3302
|
+
const hasCss = existsSync14(cssPath);
|
|
2867
3303
|
checks.push({
|
|
2868
3304
|
status: hasJs ? "pass" : "fail",
|
|
2869
3305
|
name: `${blockName}.js`,
|
|
@@ -2875,7 +3311,7 @@ async function verifyGeneratedBlock(blockDir, blockName, withUeModel) {
|
|
|
2875
3311
|
message: hasCss ? "created" : "missing \u2014 agent did not write the CSS file"
|
|
2876
3312
|
});
|
|
2877
3313
|
if (hasJs) {
|
|
2878
|
-
const js = await
|
|
3314
|
+
const js = await readFile10(jsPath, "utf-8");
|
|
2879
3315
|
checks.push({
|
|
2880
3316
|
status: /export\s+default/.test(js) ? "pass" : "fail",
|
|
2881
3317
|
name: "decorate export",
|
|
@@ -2890,7 +3326,7 @@ async function verifyGeneratedBlock(blockDir, blockName, withUeModel) {
|
|
|
2890
3326
|
}
|
|
2891
3327
|
}
|
|
2892
3328
|
if (hasCss) {
|
|
2893
|
-
const css = await
|
|
3329
|
+
const css = await readFile10(cssPath, "utf-8");
|
|
2894
3330
|
checks.push({
|
|
2895
3331
|
status: css.includes(`.${blockName}`) ? "pass" : "warn",
|
|
2896
3332
|
name: "scoped CSS",
|
|
@@ -2898,12 +3334,12 @@ async function verifyGeneratedBlock(blockDir, blockName, withUeModel) {
|
|
|
2898
3334
|
});
|
|
2899
3335
|
}
|
|
2900
3336
|
if (withUeModel) {
|
|
2901
|
-
const hasPerBlock =
|
|
2902
|
-
const modelsFile =
|
|
3337
|
+
const hasPerBlock = existsSync14(path17.join(blockDir, `_${blockName}.json`));
|
|
3338
|
+
const modelsFile = path17.join(blockDir, "..", "..", "component-models.json");
|
|
2903
3339
|
let hasAggregated = false;
|
|
2904
|
-
if (!hasPerBlock &&
|
|
3340
|
+
if (!hasPerBlock && existsSync14(modelsFile)) {
|
|
2905
3341
|
try {
|
|
2906
|
-
hasAggregated = (await
|
|
3342
|
+
hasAggregated = (await readFile10(modelsFile, "utf-8")).includes(`"${blockName}"`);
|
|
2907
3343
|
} catch {
|
|
2908
3344
|
}
|
|
2909
3345
|
}
|
|
@@ -2915,8 +3351,8 @@ async function verifyGeneratedBlock(blockDir, blockName, withUeModel) {
|
|
|
2915
3351
|
});
|
|
2916
3352
|
if (hasPerBlock && hasJs) {
|
|
2917
3353
|
try {
|
|
2918
|
-
const modelRaw = await
|
|
2919
|
-
const js = await
|
|
3354
|
+
const modelRaw = await readFile10(path17.join(blockDir, `_${blockName}.json`), "utf-8");
|
|
3355
|
+
const js = await readFile10(jsPath, "utf-8");
|
|
2920
3356
|
const isRepeatable = /"resourceType"\s*:\s*"[^"]*\/item"/.test(modelRaw) || /"filter"\s*:/.test(modelRaw) || /"multi"\s*:\s*true/.test(modelRaw);
|
|
2921
3357
|
const iterates = /\.children/.test(js) || /\bfor\s*\(/.test(js) || /\.forEach\s*\(/.test(js);
|
|
2922
3358
|
if (isRepeatable) {
|
|
@@ -2959,9 +3395,9 @@ var list_exports = {};
|
|
|
2959
3395
|
__export(list_exports, {
|
|
2960
3396
|
listBlocks: () => listBlocks
|
|
2961
3397
|
});
|
|
2962
|
-
import { existsSync as
|
|
2963
|
-
import { readFile as
|
|
2964
|
-
import
|
|
3398
|
+
import { existsSync as existsSync15 } from "fs";
|
|
3399
|
+
import { readFile as readFile11, readdir as readdir2 } from "fs/promises";
|
|
3400
|
+
import path18 from "path";
|
|
2965
3401
|
import chalk8 from "chalk";
|
|
2966
3402
|
async function listBlocks(options = {}) {
|
|
2967
3403
|
const projectRoot = findProjectRoot();
|
|
@@ -2970,27 +3406,27 @@ async function listBlocks(options = {}) {
|
|
|
2970
3406
|
process.exitCode = 1;
|
|
2971
3407
|
return;
|
|
2972
3408
|
}
|
|
2973
|
-
const blocksDir =
|
|
2974
|
-
if (!
|
|
3409
|
+
const blocksDir = path18.join(projectRoot, "blocks");
|
|
3410
|
+
if (!existsSync15(blocksDir)) {
|
|
2975
3411
|
logger.info("No blocks/ directory found.");
|
|
2976
3412
|
return;
|
|
2977
3413
|
}
|
|
2978
|
-
const entries = await
|
|
3414
|
+
const entries = await readdir2(blocksDir, { withFileTypes: true });
|
|
2979
3415
|
const blocks = [];
|
|
2980
3416
|
for (const entry of entries) {
|
|
2981
3417
|
if (!entry.isDirectory()) continue;
|
|
2982
3418
|
const name = entry.name;
|
|
2983
|
-
const blockDir =
|
|
3419
|
+
const blockDir = path18.join(blocksDir, name);
|
|
2984
3420
|
const info = {
|
|
2985
3421
|
name,
|
|
2986
|
-
hasJs:
|
|
2987
|
-
hasCss:
|
|
2988
|
-
hasUeModel:
|
|
3422
|
+
hasJs: existsSync15(path18.join(blockDir, `${name}.js`)),
|
|
3423
|
+
hasCss: existsSync15(path18.join(blockDir, `${name}.css`)),
|
|
3424
|
+
hasUeModel: existsSync15(path18.join(blockDir, `_${name}.json`))
|
|
2989
3425
|
};
|
|
2990
|
-
const metaFile =
|
|
2991
|
-
if (
|
|
3426
|
+
const metaFile = path18.join(blockDir, ".eds-meta.json");
|
|
3427
|
+
if (existsSync15(metaFile)) {
|
|
2992
3428
|
try {
|
|
2993
|
-
const meta = JSON.parse(await
|
|
3429
|
+
const meta = JSON.parse(await readFile11(metaFile, "utf-8"));
|
|
2994
3430
|
info.figmaSource = {
|
|
2995
3431
|
fileKey: meta.figmaFileKey,
|
|
2996
3432
|
nodeId: meta.figmaNodeId,
|
|
@@ -3140,9 +3576,9 @@ var integrate_exports = {};
|
|
|
3140
3576
|
__export(integrate_exports, {
|
|
3141
3577
|
integrate: () => integrate
|
|
3142
3578
|
});
|
|
3143
|
-
import { existsSync as
|
|
3144
|
-
import { mkdir as
|
|
3145
|
-
import
|
|
3579
|
+
import { existsSync as existsSync16 } from "fs";
|
|
3580
|
+
import { mkdir as mkdir6, readFile as readFile12, writeFile as writeFile9 } from "fs/promises";
|
|
3581
|
+
import path19 from "path";
|
|
3146
3582
|
import chalk9 from "chalk";
|
|
3147
3583
|
async function integrate(type) {
|
|
3148
3584
|
const projectRoot = findProjectRoot();
|
|
@@ -3171,10 +3607,10 @@ async function integrate(type) {
|
|
|
3171
3607
|
values[f.name] = answer.trim();
|
|
3172
3608
|
}
|
|
3173
3609
|
const block2 = wrapBlock(integration.name, integration.code(values));
|
|
3174
|
-
const delayedPath =
|
|
3175
|
-
await
|
|
3176
|
-
const existing =
|
|
3177
|
-
await
|
|
3610
|
+
const delayedPath = path19.join(projectRoot, "scripts", "delayed.js");
|
|
3611
|
+
await mkdir6(path19.dirname(delayedPath), { recursive: true });
|
|
3612
|
+
const existing = existsSync16(delayedPath) ? await readFile12(delayedPath, "utf-8") : DELAYED_HEADER;
|
|
3613
|
+
await writeFile9(delayedPath, `${existing.replace(/\s*$/, "")}
|
|
3178
3614
|
${block2}`);
|
|
3179
3615
|
logger.info(heading("Added"));
|
|
3180
3616
|
logger.info(accentLine(integration.name, "\u2192 scripts/delayed.js"));
|
|
@@ -3215,8 +3651,8 @@ var setup_exports = {};
|
|
|
3215
3651
|
__export(setup_exports, {
|
|
3216
3652
|
figmaSetup: () => figmaSetup
|
|
3217
3653
|
});
|
|
3218
|
-
import { existsSync as
|
|
3219
|
-
import { mkdir as
|
|
3654
|
+
import { existsSync as existsSync17 } from "fs";
|
|
3655
|
+
import { mkdir as mkdir7, writeFile as writeFile10 } from "fs/promises";
|
|
3220
3656
|
import chalk10 from "chalk";
|
|
3221
3657
|
async function figmaSetup() {
|
|
3222
3658
|
const { select, confirm } = await import("@inquirer/prompts");
|
|
@@ -3296,14 +3732,14 @@ async function figmaSetup() {
|
|
|
3296
3732
|
});
|
|
3297
3733
|
if (shouldSave) {
|
|
3298
3734
|
const configDir = globalConfigDir();
|
|
3299
|
-
if (!
|
|
3300
|
-
await
|
|
3735
|
+
if (!existsSync17(configDir)) {
|
|
3736
|
+
await mkdir7(configDir, { recursive: true });
|
|
3301
3737
|
}
|
|
3302
3738
|
const config = {};
|
|
3303
3739
|
if (selectedAgent !== "none") {
|
|
3304
3740
|
config.agent = selectedAgent;
|
|
3305
3741
|
}
|
|
3306
|
-
await
|
|
3742
|
+
await writeFile10(globalConfigPath(), `${JSON.stringify(config, null, 2)}
|
|
3307
3743
|
`, {
|
|
3308
3744
|
mode: 384
|
|
3309
3745
|
});
|
|
@@ -3330,9 +3766,9 @@ var doctor_exports = {};
|
|
|
3330
3766
|
__export(doctor_exports, {
|
|
3331
3767
|
doctor: () => doctor
|
|
3332
3768
|
});
|
|
3333
|
-
import { existsSync as
|
|
3334
|
-
import { readFile as
|
|
3335
|
-
import
|
|
3769
|
+
import { existsSync as existsSync18 } from "fs";
|
|
3770
|
+
import { readFile as readFile13, readdir as readdir3 } from "fs/promises";
|
|
3771
|
+
import path20 from "path";
|
|
3336
3772
|
import { parse as parseYaml } from "yaml";
|
|
3337
3773
|
async function doctor(options = {}) {
|
|
3338
3774
|
const projectRoot = findProjectRoot();
|
|
@@ -3354,7 +3790,7 @@ async function doctor(options = {}) {
|
|
|
3354
3790
|
});
|
|
3355
3791
|
if (project.hasFstab) {
|
|
3356
3792
|
try {
|
|
3357
|
-
const content = await
|
|
3793
|
+
const content = await readFile13(path20.join(projectRoot, "fstab.yaml"), "utf-8");
|
|
3358
3794
|
parseYaml(content);
|
|
3359
3795
|
results.push({ name: "fstab.yaml valid YAML", status: "pass", message: "Valid" });
|
|
3360
3796
|
} catch {
|
|
@@ -3376,28 +3812,28 @@ async function doctor(options = {}) {
|
|
|
3376
3812
|
message: project.hasBlocks ? "Found" : "Missing - no blocks yet"
|
|
3377
3813
|
});
|
|
3378
3814
|
if (project.hasBlocks) {
|
|
3379
|
-
const blocksDir =
|
|
3380
|
-
const entries = await
|
|
3815
|
+
const blocksDir = path20.join(projectRoot, "blocks");
|
|
3816
|
+
const entries = await readdir3(blocksDir, { withFileTypes: true });
|
|
3381
3817
|
let aggregatedModels = "";
|
|
3382
|
-
const aggregatedPath =
|
|
3383
|
-
if (
|
|
3818
|
+
const aggregatedPath = path20.join(projectRoot, "component-models.json");
|
|
3819
|
+
if (existsSync18(aggregatedPath)) {
|
|
3384
3820
|
try {
|
|
3385
|
-
aggregatedModels = await
|
|
3821
|
+
aggregatedModels = await readFile13(aggregatedPath, "utf-8");
|
|
3386
3822
|
} catch {
|
|
3387
3823
|
}
|
|
3388
3824
|
}
|
|
3389
3825
|
for (const entry of entries) {
|
|
3390
3826
|
if (!entry.isDirectory()) continue;
|
|
3391
3827
|
const blockName = entry.name;
|
|
3392
|
-
const jsFile =
|
|
3393
|
-
const hasJs =
|
|
3828
|
+
const jsFile = path20.join(blocksDir, blockName, `${blockName}.js`);
|
|
3829
|
+
const hasJs = existsSync18(jsFile);
|
|
3394
3830
|
results.push({
|
|
3395
3831
|
name: `blocks/${blockName} has JS`,
|
|
3396
3832
|
status: hasJs ? "pass" : "warn",
|
|
3397
3833
|
message: hasJs ? "Found" : `Missing ${blockName}.js`
|
|
3398
3834
|
});
|
|
3399
3835
|
if (hasJs) {
|
|
3400
|
-
const jsContent = await
|
|
3836
|
+
const jsContent = await readFile13(jsFile, "utf-8");
|
|
3401
3837
|
if (jsContent.includes("console.log")) {
|
|
3402
3838
|
results.push({
|
|
3403
3839
|
name: `blocks/${blockName} no console.log`,
|
|
@@ -3406,17 +3842,17 @@ async function doctor(options = {}) {
|
|
|
3406
3842
|
});
|
|
3407
3843
|
}
|
|
3408
3844
|
}
|
|
3409
|
-
const hasPerBlockModel =
|
|
3845
|
+
const hasPerBlockModel = existsSync18(path20.join(blocksDir, blockName, `_${blockName}.json`));
|
|
3410
3846
|
const hasAggregatedModel = aggregatedModels.includes(`"${blockName}"`);
|
|
3411
3847
|
results.push({
|
|
3412
3848
|
name: `blocks/${blockName} UE model`,
|
|
3413
3849
|
status: hasPerBlockModel || hasAggregatedModel ? "pass" : "warn",
|
|
3414
3850
|
message: hasPerBlockModel || hasAggregatedModel ? hasPerBlockModel ? `_${blockName}.json` : "in component-models.json" : "no Universal Editor model - authors can't edit this block in UE"
|
|
3415
3851
|
});
|
|
3416
|
-
const metaFile =
|
|
3417
|
-
if (
|
|
3852
|
+
const metaFile = path20.join(blocksDir, blockName, ".eds-meta.json");
|
|
3853
|
+
if (existsSync18(metaFile)) {
|
|
3418
3854
|
try {
|
|
3419
|
-
const meta = JSON.parse(await
|
|
3855
|
+
const meta = JSON.parse(await readFile13(metaFile, "utf-8"));
|
|
3420
3856
|
const syncDate = new Date(meta.lastSyncedAt);
|
|
3421
3857
|
const daysSinceSync = Math.floor(
|
|
3422
3858
|
(Date.now() - syncDate.getTime()) / (1e3 * 60 * 60 * 24)
|
|
@@ -3436,10 +3872,10 @@ async function doctor(options = {}) {
|
|
|
3436
3872
|
}
|
|
3437
3873
|
}
|
|
3438
3874
|
}
|
|
3439
|
-
const queryFile =
|
|
3440
|
-
if (
|
|
3875
|
+
const queryFile = path20.join(projectRoot, "helix-query.yaml");
|
|
3876
|
+
if (existsSync18(queryFile)) {
|
|
3441
3877
|
try {
|
|
3442
|
-
const content = await
|
|
3878
|
+
const content = await readFile13(queryFile, "utf-8");
|
|
3443
3879
|
parseYaml(content);
|
|
3444
3880
|
results.push({ name: "helix-query.yaml valid", status: "pass", message: "Valid YAML" });
|
|
3445
3881
|
} catch {
|
|
@@ -3496,9 +3932,9 @@ var audit_loading_exports = {};
|
|
|
3496
3932
|
__export(audit_loading_exports, {
|
|
3497
3933
|
auditLoading: () => auditLoading
|
|
3498
3934
|
});
|
|
3499
|
-
import { existsSync as
|
|
3500
|
-
import { readFile as
|
|
3501
|
-
import
|
|
3935
|
+
import { existsSync as existsSync19 } from "fs";
|
|
3936
|
+
import { readFile as readFile14, readdir as readdir4, stat as stat3 } from "fs/promises";
|
|
3937
|
+
import path21 from "path";
|
|
3502
3938
|
import chalk11 from "chalk";
|
|
3503
3939
|
async function auditLoading(options = {}) {
|
|
3504
3940
|
const projectRoot = findProjectRoot();
|
|
@@ -3532,8 +3968,8 @@ async function auditLoading(options = {}) {
|
|
|
3532
3968
|
printResults(results);
|
|
3533
3969
|
}
|
|
3534
3970
|
async function checkHeadHtml(root, results) {
|
|
3535
|
-
const filePath =
|
|
3536
|
-
if (!
|
|
3971
|
+
const filePath = path21.join(root, "head.html");
|
|
3972
|
+
if (!existsSync19(filePath)) {
|
|
3537
3973
|
results.push({
|
|
3538
3974
|
rule: "head.html exists",
|
|
3539
3975
|
status: "warn",
|
|
@@ -3541,7 +3977,7 @@ async function checkHeadHtml(root, results) {
|
|
|
3541
3977
|
});
|
|
3542
3978
|
return;
|
|
3543
3979
|
}
|
|
3544
|
-
const content = await
|
|
3980
|
+
const content = await readFile14(filePath, "utf-8");
|
|
3545
3981
|
const lines = content.split("\n");
|
|
3546
3982
|
for (let i = 0; i < lines.length; i++) {
|
|
3547
3983
|
const line = lines[i];
|
|
@@ -3613,8 +4049,8 @@ async function checkHeadHtml(root, results) {
|
|
|
3613
4049
|
}
|
|
3614
4050
|
}
|
|
3615
4051
|
async function checkScriptsJs(root, results) {
|
|
3616
|
-
const filePath =
|
|
3617
|
-
if (!
|
|
4052
|
+
const filePath = path21.join(root, "scripts", "scripts.js");
|
|
4053
|
+
if (!existsSync19(filePath)) {
|
|
3618
4054
|
results.push({
|
|
3619
4055
|
rule: "scripts/scripts.js exists",
|
|
3620
4056
|
status: "warn",
|
|
@@ -3622,7 +4058,7 @@ async function checkScriptsJs(root, results) {
|
|
|
3622
4058
|
});
|
|
3623
4059
|
return;
|
|
3624
4060
|
}
|
|
3625
|
-
const content = await
|
|
4061
|
+
const content = await readFile14(filePath, "utf-8");
|
|
3626
4062
|
const lines = content.split("\n");
|
|
3627
4063
|
const hasLoadEager = /function\s+loadEager|loadEager\s*=/i.test(content);
|
|
3628
4064
|
const hasLoadLazy = /function\s+loadLazy|loadLazy\s*=/i.test(content);
|
|
@@ -3700,8 +4136,8 @@ async function checkScriptsJs(root, results) {
|
|
|
3700
4136
|
}
|
|
3701
4137
|
}
|
|
3702
4138
|
async function checkStylesCss(root, results) {
|
|
3703
|
-
const filePath =
|
|
3704
|
-
if (!
|
|
4139
|
+
const filePath = path21.join(root, "styles", "styles.css");
|
|
4140
|
+
if (!existsSync19(filePath)) return;
|
|
3705
4141
|
const stats = await stat3(filePath);
|
|
3706
4142
|
const sizeKb = stats.size / 1024;
|
|
3707
4143
|
results.push({
|
|
@@ -3710,7 +4146,7 @@ async function checkStylesCss(root, results) {
|
|
|
3710
4146
|
message: `${sizeKb.toFixed(1)} KB${sizeKb > 40 ? " \u2014 large CSS competes with 100KB LCP budget" : ""}`,
|
|
3711
4147
|
file: "styles/styles.css"
|
|
3712
4148
|
});
|
|
3713
|
-
const content = await
|
|
4149
|
+
const content = await readFile14(filePath, "utf-8");
|
|
3714
4150
|
if (/@import\s/.test(content)) {
|
|
3715
4151
|
results.push({
|
|
3716
4152
|
rule: "No @import in styles.css",
|
|
@@ -3721,8 +4157,8 @@ async function checkStylesCss(root, results) {
|
|
|
3721
4157
|
}
|
|
3722
4158
|
}
|
|
3723
4159
|
async function checkDelayedJs(root, results) {
|
|
3724
|
-
const filePath =
|
|
3725
|
-
if (!
|
|
4160
|
+
const filePath = path21.join(root, "scripts", "delayed.js");
|
|
4161
|
+
if (!existsSync19(filePath)) {
|
|
3726
4162
|
results.push({
|
|
3727
4163
|
rule: "scripts/delayed.js exists",
|
|
3728
4164
|
status: "info",
|
|
@@ -3730,7 +4166,7 @@ async function checkDelayedJs(root, results) {
|
|
|
3730
4166
|
});
|
|
3731
4167
|
return;
|
|
3732
4168
|
}
|
|
3733
|
-
const content = await
|
|
4169
|
+
const content = await readFile14(filePath, "utf-8");
|
|
3734
4170
|
const stripped = content.replace(/\/\/.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "").trim();
|
|
3735
4171
|
if (!stripped) {
|
|
3736
4172
|
results.push({
|
|
@@ -3742,15 +4178,15 @@ async function checkDelayedJs(root, results) {
|
|
|
3742
4178
|
}
|
|
3743
4179
|
}
|
|
3744
4180
|
async function checkBlocks(root, results) {
|
|
3745
|
-
const blocksDir =
|
|
3746
|
-
if (!
|
|
3747
|
-
const entries = await
|
|
4181
|
+
const blocksDir = path21.join(root, "blocks");
|
|
4182
|
+
if (!existsSync19(blocksDir)) return;
|
|
4183
|
+
const entries = await readdir4(blocksDir, { withFileTypes: true });
|
|
3748
4184
|
for (const entry of entries) {
|
|
3749
4185
|
if (!entry.isDirectory()) continue;
|
|
3750
4186
|
const blockName = entry.name;
|
|
3751
|
-
const jsFile =
|
|
3752
|
-
if (!
|
|
3753
|
-
const content = await
|
|
4187
|
+
const jsFile = path21.join(blocksDir, blockName, `${blockName}.js`);
|
|
4188
|
+
if (!existsSync19(jsFile)) continue;
|
|
4189
|
+
const content = await readFile14(jsFile, "utf-8");
|
|
3754
4190
|
const lines = content.split("\n");
|
|
3755
4191
|
const heavyLibs = [
|
|
3756
4192
|
"jquery",
|
|
@@ -3800,9 +4236,9 @@ async function checkBlocks(root, results) {
|
|
|
3800
4236
|
for (const entry of entries) {
|
|
3801
4237
|
if (!entry.isDirectory()) continue;
|
|
3802
4238
|
const blockName = entry.name;
|
|
3803
|
-
const cssFile =
|
|
3804
|
-
if (!
|
|
3805
|
-
const content = await
|
|
4239
|
+
const cssFile = path21.join(blocksDir, blockName, `${blockName}.css`);
|
|
4240
|
+
if (!existsSync19(cssFile)) continue;
|
|
4241
|
+
const content = await readFile14(cssFile, "utf-8");
|
|
3806
4242
|
const selectorPattern = /^([a-z][a-z0-9-]*)\s*\{/gm;
|
|
3807
4243
|
for (const selectorMatch of content.matchAll(selectorPattern)) {
|
|
3808
4244
|
const selector = selectorMatch[1];
|
|
@@ -3818,8 +4254,8 @@ async function checkBlocks(root, results) {
|
|
|
3818
4254
|
}
|
|
3819
4255
|
}
|
|
3820
4256
|
async function checkAemJs(root, results) {
|
|
3821
|
-
const filePath =
|
|
3822
|
-
if (!
|
|
4257
|
+
const filePath = path21.join(root, "scripts", "aem.js");
|
|
4258
|
+
if (!existsSync19(filePath)) {
|
|
3823
4259
|
results.push({
|
|
3824
4260
|
rule: "scripts/aem.js exists",
|
|
3825
4261
|
status: "warn",
|
|
@@ -3891,17 +4327,17 @@ var audit_security_exports = {};
|
|
|
3891
4327
|
__export(audit_security_exports, {
|
|
3892
4328
|
auditSecurity: () => auditSecurity
|
|
3893
4329
|
});
|
|
3894
|
-
import { existsSync as
|
|
3895
|
-
import { readFile as
|
|
3896
|
-
import
|
|
4330
|
+
import { existsSync as existsSync20 } from "fs";
|
|
4331
|
+
import { readFile as readFile15, readdir as readdir5 } from "fs/promises";
|
|
4332
|
+
import path22 from "path";
|
|
3897
4333
|
import chalk12 from "chalk";
|
|
3898
|
-
async function*
|
|
3899
|
-
const entries = await
|
|
4334
|
+
async function* walk2(dir) {
|
|
4335
|
+
const entries = await readdir5(dir, { withFileTypes: true });
|
|
3900
4336
|
for (const entry of entries) {
|
|
3901
|
-
const full =
|
|
4337
|
+
const full = path22.join(dir, entry.name);
|
|
3902
4338
|
if (entry.isDirectory()) {
|
|
3903
4339
|
if (IGNORE_DIRS.has(entry.name)) continue;
|
|
3904
|
-
yield*
|
|
4340
|
+
yield* walk2(full);
|
|
3905
4341
|
} else if (entry.isFile()) {
|
|
3906
4342
|
yield full;
|
|
3907
4343
|
}
|
|
@@ -3932,11 +4368,11 @@ function scanContent(content, relFile, ext) {
|
|
|
3932
4368
|
return findings;
|
|
3933
4369
|
}
|
|
3934
4370
|
async function auditDependencies(root) {
|
|
3935
|
-
if (!
|
|
4371
|
+
if (!existsSync20(path22.join(root, "package.json"))) {
|
|
3936
4372
|
return { status: "skipped", note: "no package.json" };
|
|
3937
4373
|
}
|
|
3938
|
-
const hasLock =
|
|
3939
|
-
if (!hasLock && !
|
|
4374
|
+
const hasLock = existsSync20(path22.join(root, "package-lock.json")) || existsSync20(path22.join(root, "npm-shrinkwrap.json"));
|
|
4375
|
+
if (!hasLock && !existsSync20(path22.join(root, "node_modules"))) {
|
|
3940
4376
|
return { status: "skipped", note: "no package-lock.json / node_modules \u2014 run npm install" };
|
|
3941
4377
|
}
|
|
3942
4378
|
try {
|
|
@@ -3967,12 +4403,12 @@ async function auditSecurity(options = {}) {
|
|
|
3967
4403
|
return;
|
|
3968
4404
|
}
|
|
3969
4405
|
const findings = [];
|
|
3970
|
-
for await (const file of
|
|
3971
|
-
const ext =
|
|
4406
|
+
for await (const file of walk2(projectRoot)) {
|
|
4407
|
+
const ext = path22.extname(file).slice(1).toLowerCase();
|
|
3972
4408
|
if (!SCAN_EXT.has(ext)) continue;
|
|
3973
|
-
const rel =
|
|
4409
|
+
const rel = path22.relative(projectRoot, file);
|
|
3974
4410
|
if (rel.endsWith("aem.js") || rel.endsWith("lib-franklin.js")) continue;
|
|
3975
|
-
const content = await
|
|
4411
|
+
const content = await readFile15(file, "utf-8");
|
|
3976
4412
|
findings.push(...scanContent(content, rel, ext));
|
|
3977
4413
|
}
|
|
3978
4414
|
const deps = await auditDependencies(projectRoot);
|
|
@@ -4390,13 +4826,13 @@ var menu_exports = {};
|
|
|
4390
4826
|
__export(menu_exports, {
|
|
4391
4827
|
mainMenu: () => mainMenu
|
|
4392
4828
|
});
|
|
4393
|
-
import { existsSync as
|
|
4394
|
-
import { readdir as
|
|
4395
|
-
import
|
|
4829
|
+
import { existsSync as existsSync21 } from "fs";
|
|
4830
|
+
import { readdir as readdir6 } from "fs/promises";
|
|
4831
|
+
import path23 from "path";
|
|
4396
4832
|
async function listBlockNames(projectRoot) {
|
|
4397
|
-
const dir =
|
|
4398
|
-
if (!
|
|
4399
|
-
const entries = await
|
|
4833
|
+
const dir = path23.join(projectRoot, "blocks");
|
|
4834
|
+
if (!existsSync21(dir)) return [];
|
|
4835
|
+
const entries = await readdir6(dir, { withFileTypes: true });
|
|
4400
4836
|
return entries.filter((e) => e.isDirectory()).map((e) => e.name);
|
|
4401
4837
|
}
|
|
4402
4838
|
async function mainMenu() {
|
|
@@ -4407,6 +4843,7 @@ async function mainMenu() {
|
|
|
4407
4843
|
choices: [
|
|
4408
4844
|
{ name: "Set up this project (authoring model, CI, naming)", value: "init" },
|
|
4409
4845
|
{ name: "Generate a block from a design (Figma/Stitch/Canva/Sketch)", value: "from-design" },
|
|
4846
|
+
{ name: "Migrate a classic AEM component to EDS", value: "migrate" },
|
|
4410
4847
|
{ name: "Scaffold Universal Editor components", value: "scaffold" },
|
|
4411
4848
|
{ name: "Create an empty block", value: "create" },
|
|
4412
4849
|
{ name: "Add a third-party integration (GTM, chat, consent\u2026)", value: "integrate" },
|
|
@@ -4427,6 +4864,11 @@ async function mainMenu() {
|
|
|
4427
4864
|
await blockFromDesign2(void 0, {});
|
|
4428
4865
|
return;
|
|
4429
4866
|
}
|
|
4867
|
+
case "migrate": {
|
|
4868
|
+
const { migrateComponent: migrateComponent2 } = await Promise.resolve().then(() => (init_migrate(), migrate_exports));
|
|
4869
|
+
await migrateComponent2(void 0, {});
|
|
4870
|
+
return;
|
|
4871
|
+
}
|
|
4430
4872
|
case "scaffold": {
|
|
4431
4873
|
const { scaffoldInteractive: scaffoldInteractive2 } = await Promise.resolve().then(() => (init_scaffold(), scaffold_exports));
|
|
4432
4874
|
await scaffoldInteractive2();
|
|
@@ -4516,7 +4958,7 @@ import { Command } from "commander";
|
|
|
4516
4958
|
// package.json
|
|
4517
4959
|
var package_default = {
|
|
4518
4960
|
name: "aem-eds-kit",
|
|
4519
|
-
version: "0.4.
|
|
4961
|
+
version: "0.4.9",
|
|
4520
4962
|
description: "CLI for AEM Edge Delivery Services with Figma MCP integration",
|
|
4521
4963
|
type: "module",
|
|
4522
4964
|
engines: {
|
|
@@ -4566,6 +5008,7 @@ var package_default = {
|
|
|
4566
5008
|
chalk: "^5.4.0",
|
|
4567
5009
|
commander: "^13.0.0",
|
|
4568
5010
|
execa: "^9.5.0",
|
|
5011
|
+
"fast-xml-parser": "^5.11.2",
|
|
4569
5012
|
ora: "^8.1.0",
|
|
4570
5013
|
yaml: "^2.6.0",
|
|
4571
5014
|
zod: "^3.24.0"
|
|
@@ -4598,6 +5041,11 @@ program.command("init").description("Set up a freshly cloned EDS boilerplate for
|
|
|
4598
5041
|
const { initProject: initProject2 } = await Promise.resolve().then(() => (init_init(), init_exports));
|
|
4599
5042
|
await initProject2(options);
|
|
4600
5043
|
});
|
|
5044
|
+
var migrate = program.command("migrate").description("Migrate from classic AEM to EDS");
|
|
5045
|
+
migrate.command("component [dir]").description("Migrate a classic AEM component's dialog into an EDS block + UE model").option("--name <name>", "Block name (otherwise inferred from the component)").option("--clientlib <dir>", "Path to the component's clientlib (otherwise auto-detected)").option("--yes", "Skip confirmation prompts").action(async (dir, options) => {
|
|
5046
|
+
const { migrateComponent: migrateComponent2 } = await Promise.resolve().then(() => (init_migrate(), migrate_exports));
|
|
5047
|
+
await migrateComponent2(dir, options);
|
|
5048
|
+
});
|
|
4601
5049
|
var block = program.command("block").description("Manage EDS blocks");
|
|
4602
5050
|
block.command("create <name>").description("Scaffold a new EDS block (with Universal Editor model by default)").option("--no-ue-model", "Skip the Universal Editor model (generated by default)").action(async (name, options) => {
|
|
4603
5051
|
const { createBlock: createBlock2 } = await Promise.resolve().then(() => (init_create(), create_exports));
|