@fragments-sdk/cli 0.7.17 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin.js +227 -53
- package/dist/bin.js.map +1 -1
- package/dist/{chunk-QLTLLQBI.js → chunk-2JIKCJX3.js} +312 -24
- package/dist/chunk-2JIKCJX3.js.map +1 -0
- package/dist/{chunk-57OW43NL.js → chunk-CJEGT3WD.js} +2 -2
- package/dist/{chunk-7CRC46HV.js → chunk-GOVI6COW.js} +13 -3
- package/dist/chunk-GOVI6COW.js.map +1 -0
- package/dist/{chunk-WLXFE6XW.js → chunk-NGIMCIK2.js} +60 -2
- package/dist/chunk-NGIMCIK2.js.map +1 -0
- package/dist/{chunk-M42XIHPV.js → chunk-WI6SLMSO.js} +2 -2
- package/dist/core/index.d.ts +110 -3
- package/dist/core/index.js +12 -2
- package/dist/{defineFragment-BI9KoPrs.d.ts → defineFragment-D0UTve-I.d.ts} +9 -0
- package/dist/{generate-ICIPKCKV.js → generate-35OIMW4Y.js} +4 -4
- package/dist/index.d.ts +2 -2
- package/dist/index.js +4 -4
- package/dist/{init-DIZ6UNBL.js → init-KFYN37ZY.js} +4 -4
- package/dist/mcp-bin.js +67 -3
- package/dist/mcp-bin.js.map +1 -1
- package/dist/{scan-X3DI2X5G.js → scan-65RH3QMM.js} +5 -5
- package/dist/{service-JEWWTSKI.js → service-A5GIGGGK.js} +3 -3
- package/dist/{static-viewer-JIWCYKVK.js → static-viewer-NSODM5VX.js} +3 -3
- package/dist/{test-36UELXTE.js → test-RPWZAYSJ.js} +3 -3
- package/dist/{tokens-K2AGUUOJ.js → tokens-NIXSZRX7.js} +4 -4
- package/dist/{viewer-QKIAPTPG.js → viewer-HZK4BSDK.js} +43 -12
- package/dist/viewer-HZK4BSDK.js.map +1 -0
- package/package.json +3 -3
- package/src/bin.ts +32 -0
- package/src/build.ts +47 -0
- package/src/commands/perf.ts +249 -0
- package/src/core/bundle-measurer.ts +421 -0
- package/src/core/index.ts +16 -0
- package/src/core/performance-presets.ts +142 -0
- package/src/core/schema.ts +10 -0
- package/src/core/types.ts +6 -0
- package/src/mcp/server.ts +77 -0
- package/src/viewer/components/BottomPanel.tsx +8 -0
- package/src/viewer/components/PerformancePanel.tsx +301 -0
- package/src/viewer/hooks/useAppState.ts +1 -1
- package/src/viewer/vite-plugin.ts +36 -0
- package/dist/chunk-7CRC46HV.js.map +0 -1
- package/dist/chunk-QLTLLQBI.js.map +0 -1
- package/dist/chunk-WLXFE6XW.js.map +0 -1
- package/dist/viewer-QKIAPTPG.js.map +0 -1
- /package/dist/{chunk-57OW43NL.js.map → chunk-CJEGT3WD.js.map} +0 -0
- /package/dist/{chunk-M42XIHPV.js.map → chunk-WI6SLMSO.js.map} +0 -0
- /package/dist/{generate-ICIPKCKV.js.map → generate-35OIMW4Y.js.map} +0 -0
- /package/dist/{init-DIZ6UNBL.js.map → init-KFYN37ZY.js.map} +0 -0
- /package/dist/{scan-X3DI2X5G.js.map → scan-65RH3QMM.js.map} +0 -0
- /package/dist/{service-JEWWTSKI.js.map → service-A5GIGGGK.js.map} +0 -0
- /package/dist/{static-viewer-JIWCYKVK.js.map → static-viewer-NSODM5VX.js.map} +0 -0
- /package/dist/{test-36UELXTE.js.map → test-RPWZAYSJ.js.map} +0 -0
- /package/dist/{tokens-K2AGUUOJ.js.map → tokens-NIXSZRX7.js.map} +0 -0
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
generateRegistry,
|
|
5
5
|
loadFragmentFile,
|
|
6
6
|
parseFragmentFile
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-CJEGT3WD.js";
|
|
8
8
|
import {
|
|
9
9
|
discoverBlockFiles,
|
|
10
10
|
discoverComponentFiles,
|
|
@@ -23,12 +23,14 @@ import {
|
|
|
23
23
|
getGrade
|
|
24
24
|
} from "./chunk-YMPGYEWK.js";
|
|
25
25
|
import {
|
|
26
|
+
classifyComplexity,
|
|
26
27
|
compileBlock,
|
|
27
|
-
parseTokenFile
|
|
28
|
-
|
|
28
|
+
parseTokenFile,
|
|
29
|
+
resolvePerformanceConfig
|
|
30
|
+
} from "./chunk-NGIMCIK2.js";
|
|
29
31
|
import {
|
|
30
32
|
fragmentDefinitionSchema
|
|
31
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-GOVI6COW.js";
|
|
32
34
|
import {
|
|
33
35
|
BRAND,
|
|
34
36
|
DEFAULTS
|
|
@@ -598,8 +600,8 @@ async function validateSnippets(config, configDir, options = {}) {
|
|
|
598
600
|
|
|
599
601
|
// src/build.ts
|
|
600
602
|
import { readFile as readFile2, writeFile, mkdir } from "fs/promises";
|
|
601
|
-
import { resolve as
|
|
602
|
-
import { existsSync as
|
|
603
|
+
import { resolve as resolve5, join as join5 } from "path";
|
|
604
|
+
import { existsSync as existsSync6 } from "fs";
|
|
603
605
|
|
|
604
606
|
// src/core/token-resolver.ts
|
|
605
607
|
import { resolve, dirname, basename } from "path";
|
|
@@ -1384,6 +1386,252 @@ function findComponentIndex(componentDir, componentName) {
|
|
|
1384
1386
|
|
|
1385
1387
|
// src/build.ts
|
|
1386
1388
|
import { serializeGraph } from "@fragments-sdk/context/graph";
|
|
1389
|
+
|
|
1390
|
+
// src/core/bundle-measurer.ts
|
|
1391
|
+
import { build } from "esbuild";
|
|
1392
|
+
import { gzipSync } from "zlib";
|
|
1393
|
+
import { resolve as resolve4, dirname as dirname3, join as join4, basename as basename3 } from "path";
|
|
1394
|
+
import { existsSync as existsSync5 } from "fs";
|
|
1395
|
+
function resolveEntryPoint(fragmentFilePath, configDir) {
|
|
1396
|
+
const absPath = resolve4(configDir, fragmentFilePath);
|
|
1397
|
+
const dir = dirname3(absPath);
|
|
1398
|
+
const candidates = ["index.tsx", "index.ts", "index.jsx", "index.js"];
|
|
1399
|
+
for (const candidate of candidates) {
|
|
1400
|
+
const path = join4(dir, candidate);
|
|
1401
|
+
if (existsSync5(path)) return path;
|
|
1402
|
+
}
|
|
1403
|
+
return null;
|
|
1404
|
+
}
|
|
1405
|
+
function labelForPath(filePath) {
|
|
1406
|
+
const lastNmIdx = filePath.lastIndexOf("node_modules/");
|
|
1407
|
+
if (lastNmIdx >= 0) {
|
|
1408
|
+
const afterNm = filePath.slice(lastNmIdx + "node_modules/".length);
|
|
1409
|
+
if (afterNm.startsWith("@")) {
|
|
1410
|
+
const parts = afterNm.split("/");
|
|
1411
|
+
return parts.slice(0, 2).join("/");
|
|
1412
|
+
}
|
|
1413
|
+
return afterNm.split("/")[0];
|
|
1414
|
+
}
|
|
1415
|
+
const componentsIdx = filePath.indexOf("components/");
|
|
1416
|
+
if (componentsIdx >= 0) {
|
|
1417
|
+
const afterComponents = filePath.slice(componentsIdx + "components/".length);
|
|
1418
|
+
const componentName = afterComponents.split("/")[0];
|
|
1419
|
+
return componentName;
|
|
1420
|
+
}
|
|
1421
|
+
const srcIdx = filePath.indexOf("src/");
|
|
1422
|
+
if (srcIdx >= 0) return filePath.slice(srcIdx);
|
|
1423
|
+
return filePath;
|
|
1424
|
+
}
|
|
1425
|
+
function groupImportsByDirectDep(metafile, entryPoint) {
|
|
1426
|
+
const inputs = metafile.inputs;
|
|
1427
|
+
const outputKey = Object.keys(metafile.outputs)[0];
|
|
1428
|
+
const outputMeta = outputKey ? metafile.outputs[outputKey] : void 0;
|
|
1429
|
+
if (!outputMeta?.inputs) return [];
|
|
1430
|
+
const bytesMap = /* @__PURE__ */ new Map();
|
|
1431
|
+
for (const [path, info] of Object.entries(outputMeta.inputs)) {
|
|
1432
|
+
if (info.bytesInOutput > 0) {
|
|
1433
|
+
bytesMap.set(path, info.bytesInOutput);
|
|
1434
|
+
}
|
|
1435
|
+
}
|
|
1436
|
+
let entryKey;
|
|
1437
|
+
for (const key of Object.keys(inputs)) {
|
|
1438
|
+
if (key === entryPoint || entryPoint.endsWith(key) || key.endsWith(basename3(entryPoint))) {
|
|
1439
|
+
const entryDir = dirname3(entryPoint);
|
|
1440
|
+
if (key.includes(basename3(entryDir))) {
|
|
1441
|
+
entryKey = key;
|
|
1442
|
+
break;
|
|
1443
|
+
}
|
|
1444
|
+
}
|
|
1445
|
+
}
|
|
1446
|
+
if (!entryKey) {
|
|
1447
|
+
const entryBasename = basename3(dirname3(entryPoint));
|
|
1448
|
+
for (const key of Object.keys(inputs)) {
|
|
1449
|
+
if (key.includes(`/${entryBasename}/index.`)) {
|
|
1450
|
+
entryKey = key;
|
|
1451
|
+
break;
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1454
|
+
}
|
|
1455
|
+
if (!entryKey || !inputs[entryKey]) {
|
|
1456
|
+
return groupByPackage(bytesMap);
|
|
1457
|
+
}
|
|
1458
|
+
const directImports = inputs[entryKey].imports.map((imp) => imp.path).filter((p) => inputs[p]);
|
|
1459
|
+
const claimed = /* @__PURE__ */ new Set();
|
|
1460
|
+
claimed.add(entryKey);
|
|
1461
|
+
const groupMap = /* @__PURE__ */ new Map();
|
|
1462
|
+
for (const directPath of directImports) {
|
|
1463
|
+
if (claimed.has(directPath)) continue;
|
|
1464
|
+
const queue = [directPath];
|
|
1465
|
+
const reachable = /* @__PURE__ */ new Set();
|
|
1466
|
+
while (queue.length > 0) {
|
|
1467
|
+
const current = queue.pop();
|
|
1468
|
+
if (reachable.has(current) || claimed.has(current)) continue;
|
|
1469
|
+
reachable.add(current);
|
|
1470
|
+
claimed.add(current);
|
|
1471
|
+
const entry = inputs[current];
|
|
1472
|
+
if (entry?.imports) {
|
|
1473
|
+
for (const imp of entry.imports) {
|
|
1474
|
+
if (inputs[imp.path] && !claimed.has(imp.path)) {
|
|
1475
|
+
queue.push(imp.path);
|
|
1476
|
+
}
|
|
1477
|
+
}
|
|
1478
|
+
}
|
|
1479
|
+
}
|
|
1480
|
+
let totalBytes = 0;
|
|
1481
|
+
for (const path of reachable) {
|
|
1482
|
+
totalBytes += bytesMap.get(path) ?? 0;
|
|
1483
|
+
}
|
|
1484
|
+
if (totalBytes > 0) {
|
|
1485
|
+
const label = labelForPath(directPath);
|
|
1486
|
+
const existing = groupMap.get(label);
|
|
1487
|
+
if (existing) {
|
|
1488
|
+
existing.bytes += totalBytes;
|
|
1489
|
+
} else {
|
|
1490
|
+
const entry = { path: label, bytes: totalBytes };
|
|
1491
|
+
groupMap.set(label, entry);
|
|
1492
|
+
}
|
|
1493
|
+
}
|
|
1494
|
+
}
|
|
1495
|
+
const entryLabel = labelForPath(entryKey);
|
|
1496
|
+
const selfLabel = entryLabel + " (self)";
|
|
1497
|
+
let selfBytes = bytesMap.get(entryKey) ?? 0;
|
|
1498
|
+
const siblingGroup = groupMap.get(entryLabel);
|
|
1499
|
+
if (siblingGroup) {
|
|
1500
|
+
selfBytes += siblingGroup.bytes;
|
|
1501
|
+
groupMap.delete(entryLabel);
|
|
1502
|
+
}
|
|
1503
|
+
if (selfBytes > 0) {
|
|
1504
|
+
groupMap.set(selfLabel, { path: selfLabel, bytes: selfBytes });
|
|
1505
|
+
}
|
|
1506
|
+
let unclaimedBytes = 0;
|
|
1507
|
+
for (const [path, bytes] of bytesMap) {
|
|
1508
|
+
if (!claimed.has(path)) unclaimedBytes += bytes;
|
|
1509
|
+
}
|
|
1510
|
+
if (unclaimedBytes > 0) {
|
|
1511
|
+
groupMap.set("(other)", { path: "(other)", bytes: unclaimedBytes });
|
|
1512
|
+
}
|
|
1513
|
+
return [...groupMap.values()].sort((a, b) => b.bytes - a.bytes);
|
|
1514
|
+
}
|
|
1515
|
+
function groupByPackage(bytesMap) {
|
|
1516
|
+
const groups = /* @__PURE__ */ new Map();
|
|
1517
|
+
for (const [path, bytes] of bytesMap) {
|
|
1518
|
+
const label = labelForPath(path);
|
|
1519
|
+
const key = label.includes("/") && !label.startsWith("components/") ? label.split("/").slice(0, label.startsWith("@") ? 2 : 1).join("/") : label;
|
|
1520
|
+
groups.set(key, (groups.get(key) ?? 0) + bytes);
|
|
1521
|
+
}
|
|
1522
|
+
return [...groups.entries()].map(([path, bytes]) => ({ path, bytes })).sort((a, b) => b.bytes - a.bytes);
|
|
1523
|
+
}
|
|
1524
|
+
async function measureSingleComponent(entryPoint, name) {
|
|
1525
|
+
const result = await build({
|
|
1526
|
+
entryPoints: [entryPoint],
|
|
1527
|
+
bundle: true,
|
|
1528
|
+
write: false,
|
|
1529
|
+
minify: true,
|
|
1530
|
+
metafile: true,
|
|
1531
|
+
format: "esm",
|
|
1532
|
+
target: "es2020",
|
|
1533
|
+
platform: "browser",
|
|
1534
|
+
treeShaking: true,
|
|
1535
|
+
external: [
|
|
1536
|
+
"react",
|
|
1537
|
+
"react-dom",
|
|
1538
|
+
"react/jsx-runtime",
|
|
1539
|
+
"react/jsx-dev-runtime",
|
|
1540
|
+
// Optional peer deps — excluded from measurement
|
|
1541
|
+
"recharts",
|
|
1542
|
+
"shiki",
|
|
1543
|
+
"react-day-picker",
|
|
1544
|
+
"@tanstack/react-table",
|
|
1545
|
+
"date-fns",
|
|
1546
|
+
"@base-ui-components/*",
|
|
1547
|
+
"@base-ui/react/*"
|
|
1548
|
+
],
|
|
1549
|
+
loader: {
|
|
1550
|
+
".scss": "empty",
|
|
1551
|
+
".css": "empty",
|
|
1552
|
+
".svg": "empty",
|
|
1553
|
+
".png": "empty",
|
|
1554
|
+
".jpg": "empty",
|
|
1555
|
+
".gif": "empty",
|
|
1556
|
+
".woff": "empty",
|
|
1557
|
+
".woff2": "empty",
|
|
1558
|
+
".ttf": "empty",
|
|
1559
|
+
".eot": "empty"
|
|
1560
|
+
},
|
|
1561
|
+
logLevel: "silent"
|
|
1562
|
+
});
|
|
1563
|
+
const output = result.outputFiles[0];
|
|
1564
|
+
const rawBytes = output.contents.byteLength;
|
|
1565
|
+
const gzipBytes = gzipSync(output.contents).byteLength;
|
|
1566
|
+
const imports = result.metafile ? groupImportsByDirectDep(result.metafile, entryPoint) : void 0;
|
|
1567
|
+
return { name, rawBytes, gzipBytes, imports };
|
|
1568
|
+
}
|
|
1569
|
+
async function measureBundleSizes(fragments, configDir, options = {}) {
|
|
1570
|
+
const concurrency = options.concurrency ?? 4;
|
|
1571
|
+
const measurements = /* @__PURE__ */ new Map();
|
|
1572
|
+
const errors = [];
|
|
1573
|
+
const start = Date.now();
|
|
1574
|
+
const entries = [];
|
|
1575
|
+
for (const [name, fragment] of Object.entries(fragments)) {
|
|
1576
|
+
const entryPoint = resolveEntryPoint(fragment.filePath, configDir);
|
|
1577
|
+
if (entryPoint) {
|
|
1578
|
+
entries.push({ name, entryPoint });
|
|
1579
|
+
} else {
|
|
1580
|
+
errors.push({
|
|
1581
|
+
name,
|
|
1582
|
+
error: `Could not resolve entry point from ${fragment.filePath}`
|
|
1583
|
+
});
|
|
1584
|
+
}
|
|
1585
|
+
}
|
|
1586
|
+
let completed = 0;
|
|
1587
|
+
for (let i = 0; i < entries.length; i += concurrency) {
|
|
1588
|
+
const batch = entries.slice(i, i + concurrency);
|
|
1589
|
+
const results = await Promise.allSettled(
|
|
1590
|
+
batch.map(
|
|
1591
|
+
({ name, entryPoint }) => measureSingleComponent(entryPoint, name)
|
|
1592
|
+
)
|
|
1593
|
+
);
|
|
1594
|
+
for (let j = 0; j < results.length; j++) {
|
|
1595
|
+
const result = results[j];
|
|
1596
|
+
const { name } = batch[j];
|
|
1597
|
+
completed++;
|
|
1598
|
+
if (result.status === "fulfilled") {
|
|
1599
|
+
measurements.set(name, result.value);
|
|
1600
|
+
} else {
|
|
1601
|
+
errors.push({
|
|
1602
|
+
name,
|
|
1603
|
+
error: result.reason instanceof Error ? result.reason.message : String(result.reason)
|
|
1604
|
+
});
|
|
1605
|
+
}
|
|
1606
|
+
options.onProgress?.(completed, entries.length, name);
|
|
1607
|
+
}
|
|
1608
|
+
}
|
|
1609
|
+
return {
|
|
1610
|
+
measurements,
|
|
1611
|
+
errors,
|
|
1612
|
+
elapsed: Date.now() - start
|
|
1613
|
+
};
|
|
1614
|
+
}
|
|
1615
|
+
function toPerformanceData(measurement, config, contractBudget) {
|
|
1616
|
+
const budget = contractBudget ?? config.budgets.bundleSize;
|
|
1617
|
+
const budgetPercent = Math.round(measurement.gzipBytes / budget * 100);
|
|
1618
|
+
const imports = measurement.imports?.slice(0, 10).map((imp) => ({
|
|
1619
|
+
path: imp.path,
|
|
1620
|
+
bytes: imp.bytes,
|
|
1621
|
+
percent: Math.round(imp.bytes / measurement.rawBytes * 100)
|
|
1622
|
+
}));
|
|
1623
|
+
return {
|
|
1624
|
+
bundleSize: measurement.gzipBytes,
|
|
1625
|
+
rawSize: measurement.rawBytes,
|
|
1626
|
+
complexity: classifyComplexity(measurement.gzipBytes),
|
|
1627
|
+
budgetPercent,
|
|
1628
|
+
overBudget: budgetPercent > 100,
|
|
1629
|
+
measuredAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1630
|
+
...imports && imports.length > 0 ? { imports } : {}
|
|
1631
|
+
};
|
|
1632
|
+
}
|
|
1633
|
+
|
|
1634
|
+
// src/build.ts
|
|
1387
1635
|
function normalizeParsedProps(parsedProps) {
|
|
1388
1636
|
return Object.fromEntries(
|
|
1389
1637
|
Object.entries(parsedProps).map(([name, prop]) => [
|
|
@@ -1593,7 +1841,7 @@ async function buildFragments(config, configDir) {
|
|
|
1593
1841
|
(t) => t.value && (t.value.includes("#{") || t.value.includes("$"))
|
|
1594
1842
|
);
|
|
1595
1843
|
if (unresolved.length > 0 && tokenFiles.length > 0) {
|
|
1596
|
-
const tokensDir =
|
|
1844
|
+
const tokensDir = resolve5(configDir, tokenFiles[0].relativePath, "..");
|
|
1597
1845
|
const sassResolved = await resolveTokensWithSass(
|
|
1598
1846
|
unresolved,
|
|
1599
1847
|
tokensDir
|
|
@@ -1615,15 +1863,15 @@ async function buildFragments(config, configDir) {
|
|
|
1615
1863
|
} catch {
|
|
1616
1864
|
}
|
|
1617
1865
|
let packageName;
|
|
1618
|
-
const pkgJsonPath =
|
|
1619
|
-
if (
|
|
1866
|
+
const pkgJsonPath = resolve5(configDir, "package.json");
|
|
1867
|
+
if (existsSync6(pkgJsonPath)) {
|
|
1620
1868
|
try {
|
|
1621
1869
|
const pkg = JSON.parse(await readFile2(pkgJsonPath, "utf-8"));
|
|
1622
1870
|
if (pkg.name) packageName = pkg.name;
|
|
1623
1871
|
} catch {
|
|
1624
1872
|
}
|
|
1625
1873
|
}
|
|
1626
|
-
const componentDir =
|
|
1874
|
+
const componentDir = resolve5(configDir, "src", "components");
|
|
1627
1875
|
let graphData;
|
|
1628
1876
|
try {
|
|
1629
1877
|
const graphResult = await buildComponentGraph(fragments, blocks, componentDir);
|
|
@@ -1654,6 +1902,43 @@ async function buildFragments(config, configDir) {
|
|
|
1654
1902
|
warning: `Graph extraction failed: ${error instanceof Error ? error.message : String(error)}`
|
|
1655
1903
|
});
|
|
1656
1904
|
}
|
|
1905
|
+
let performanceSummary;
|
|
1906
|
+
if (config.performance) {
|
|
1907
|
+
try {
|
|
1908
|
+
const perfConfig = resolvePerformanceConfig(config.performance);
|
|
1909
|
+
const perfResult = await measureBundleSizes(fragments, configDir, {
|
|
1910
|
+
perfConfig
|
|
1911
|
+
});
|
|
1912
|
+
const tiers = { lightweight: 0, moderate: 0, heavy: 0 };
|
|
1913
|
+
let overBudgetCount = 0;
|
|
1914
|
+
for (const [name, measurement] of perfResult.measurements) {
|
|
1915
|
+
const fragment = fragments[name];
|
|
1916
|
+
const contractBudget = fragment?.contract?.performanceBudget;
|
|
1917
|
+
const perfData = toPerformanceData(measurement, perfConfig, contractBudget);
|
|
1918
|
+
fragment.performance = perfData;
|
|
1919
|
+
tiers[perfData.complexity]++;
|
|
1920
|
+
if (perfData.overBudget) overBudgetCount++;
|
|
1921
|
+
}
|
|
1922
|
+
performanceSummary = {
|
|
1923
|
+
preset: perfConfig.preset,
|
|
1924
|
+
budget: perfConfig.budgets.bundleSize,
|
|
1925
|
+
total: perfResult.measurements.size,
|
|
1926
|
+
overBudget: overBudgetCount,
|
|
1927
|
+
tiers
|
|
1928
|
+
};
|
|
1929
|
+
for (const err of perfResult.errors) {
|
|
1930
|
+
warnings.push({
|
|
1931
|
+
file: "performance",
|
|
1932
|
+
warning: `Could not measure ${err.name}: ${err.error}`
|
|
1933
|
+
});
|
|
1934
|
+
}
|
|
1935
|
+
} catch (error) {
|
|
1936
|
+
warnings.push({
|
|
1937
|
+
file: "performance",
|
|
1938
|
+
warning: `Performance measurement failed: ${error instanceof Error ? error.message : String(error)}`
|
|
1939
|
+
});
|
|
1940
|
+
}
|
|
1941
|
+
}
|
|
1657
1942
|
const output = {
|
|
1658
1943
|
version: "1.0.0",
|
|
1659
1944
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -1661,9 +1946,10 @@ async function buildFragments(config, configDir) {
|
|
|
1661
1946
|
fragments,
|
|
1662
1947
|
...Object.keys(blocks).length > 0 && { blocks },
|
|
1663
1948
|
...tokens && { tokens },
|
|
1664
|
-
...graphData && { graph: graphData }
|
|
1949
|
+
...graphData && { graph: graphData },
|
|
1950
|
+
...performanceSummary && { performanceSummary }
|
|
1665
1951
|
};
|
|
1666
|
-
const outputPath =
|
|
1952
|
+
const outputPath = resolve5(configDir, config.outFile ?? BRAND.outFile);
|
|
1667
1953
|
await writeFile(outputPath, JSON.stringify(output));
|
|
1668
1954
|
return {
|
|
1669
1955
|
success: errors.length === 0,
|
|
@@ -1674,8 +1960,8 @@ async function buildFragments(config, configDir) {
|
|
|
1674
1960
|
};
|
|
1675
1961
|
}
|
|
1676
1962
|
async function buildFragmentsDir(config, configDir) {
|
|
1677
|
-
const fragmentsDir =
|
|
1678
|
-
const componentsDir =
|
|
1963
|
+
const fragmentsDir = join5(configDir, BRAND.dataDir);
|
|
1964
|
+
const componentsDir = join5(fragmentsDir, BRAND.componentsDir);
|
|
1679
1965
|
await mkdir(fragmentsDir, { recursive: true });
|
|
1680
1966
|
await mkdir(componentsDir, { recursive: true });
|
|
1681
1967
|
const registryResult = await generateRegistry({
|
|
@@ -1687,9 +1973,9 @@ async function buildFragmentsDir(config, configDir) {
|
|
|
1687
1973
|
});
|
|
1688
1974
|
const errors = [...registryResult.errors];
|
|
1689
1975
|
const warnings = [...registryResult.warnings];
|
|
1690
|
-
const indexPath =
|
|
1976
|
+
const indexPath = join5(fragmentsDir, "index.json");
|
|
1691
1977
|
await writeFile(indexPath, JSON.stringify(registryResult.index, null, 2));
|
|
1692
|
-
const registryPath =
|
|
1978
|
+
const registryPath = join5(fragmentsDir, BRAND.registryFile);
|
|
1693
1979
|
await writeFile(registryPath, JSON.stringify(registryResult.registry, null, 2));
|
|
1694
1980
|
const contextResult = generateContextMd(registryResult.registry, {
|
|
1695
1981
|
format: "markdown",
|
|
@@ -1701,7 +1987,7 @@ async function buildFragmentsDir(config, configDir) {
|
|
|
1701
1987
|
code: false
|
|
1702
1988
|
}
|
|
1703
1989
|
});
|
|
1704
|
-
const contextPath =
|
|
1990
|
+
const contextPath = join5(fragmentsDir, BRAND.contextFile);
|
|
1705
1991
|
await writeFile(contextPath, contextResult.content);
|
|
1706
1992
|
return {
|
|
1707
1993
|
success: errors.length === 0,
|
|
@@ -2054,9 +2340,9 @@ ${BRAND.name} Diff
|
|
|
2054
2340
|
}
|
|
2055
2341
|
|
|
2056
2342
|
// src/analyze.ts
|
|
2057
|
-
import { existsSync as
|
|
2343
|
+
import { existsSync as existsSync7 } from "fs";
|
|
2058
2344
|
import { readFile as readFile3, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
2059
|
-
import { join as
|
|
2345
|
+
import { join as join6, dirname as dirname4 } from "path";
|
|
2060
2346
|
import pc3 from "picocolors";
|
|
2061
2347
|
async function runAnalyzeCommand(config, configDir, options = {}) {
|
|
2062
2348
|
const format = options.format ?? "html";
|
|
@@ -2064,8 +2350,8 @@ async function runAnalyzeCommand(config, configDir, options = {}) {
|
|
|
2064
2350
|
console.log(pc3.cyan(`
|
|
2065
2351
|
${BRAND.name} Analyzer
|
|
2066
2352
|
`));
|
|
2067
|
-
const fragmentsPath =
|
|
2068
|
-
if (!
|
|
2353
|
+
const fragmentsPath = join6(configDir, config.outFile ?? "fragments.json");
|
|
2354
|
+
if (!existsSync7(fragmentsPath)) {
|
|
2069
2355
|
console.log(pc3.red(`\u2717 No fragments.json found. Run \`${BRAND.cliCommand} build\` first.
|
|
2070
2356
|
`));
|
|
2071
2357
|
return {
|
|
@@ -2081,7 +2367,7 @@ ${BRAND.name} Analyzer
|
|
|
2081
2367
|
let outputPath;
|
|
2082
2368
|
if (format === "html" || format === "json") {
|
|
2083
2369
|
outputPath = options.output ?? getDefaultOutputPath(format, configDir);
|
|
2084
|
-
await mkdir2(
|
|
2370
|
+
await mkdir2(dirname4(outputPath), { recursive: true });
|
|
2085
2371
|
if (format === "html") {
|
|
2086
2372
|
const html = generateHtmlReport(analytics);
|
|
2087
2373
|
await writeFile2(outputPath, html);
|
|
@@ -2160,7 +2446,7 @@ function colorizeScore(score) {
|
|
|
2160
2446
|
}
|
|
2161
2447
|
function getDefaultOutputPath(format, configDir) {
|
|
2162
2448
|
const filename = format === "html" ? "fragments-report.html" : "fragments-report.json";
|
|
2163
|
-
return
|
|
2449
|
+
return join6(configDir, filename);
|
|
2164
2450
|
}
|
|
2165
2451
|
async function openInBrowser(path) {
|
|
2166
2452
|
const { platform } = await import("os");
|
|
@@ -2223,10 +2509,12 @@ export {
|
|
|
2223
2509
|
validateCoverage,
|
|
2224
2510
|
validateAll,
|
|
2225
2511
|
validateSnippets,
|
|
2512
|
+
measureBundleSizes,
|
|
2513
|
+
toPerformanceData,
|
|
2226
2514
|
buildFragments,
|
|
2227
2515
|
buildFragmentsDir,
|
|
2228
2516
|
runScreenshotCommand,
|
|
2229
2517
|
runDiffCommand,
|
|
2230
2518
|
runAnalyzeCommand
|
|
2231
2519
|
};
|
|
2232
|
-
//# sourceMappingURL=chunk-
|
|
2520
|
+
//# sourceMappingURL=chunk-2JIKCJX3.js.map
|