@bettercms-ai/convert 0.2.0 → 0.3.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/CHANGELOG.md +109 -0
- package/README.md +88 -9
- package/dist/cli.js +626 -164
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +78 -2
- package/dist/index.js +629 -166
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -2628,6 +2628,71 @@ function locate(brief, sources, options) {
|
|
|
2628
2628
|
// src/loops.ts
|
|
2629
2629
|
import MagicString from "magic-string";
|
|
2630
2630
|
|
|
2631
|
+
// src/declarations.ts
|
|
2632
|
+
var BINDING_ATTR = /data-bcms-(?:layout-)?field\s*=\s*["']([^"']+)["']/g;
|
|
2633
|
+
var PROPS_ATTR = /data-bcms-props\s*=\s*["']([^"']+)["']/g;
|
|
2634
|
+
var TEMPLATE_SCAN = /:?data-bcms-(?:layout-)?field\s*=\s*(?:\{\s*`([^`]+)`\s*\}|"\s*`([^`]+)`\s*")/g;
|
|
2635
|
+
var BINDINGS_SCAN = /bcmsBindings\s*=\s*\{\{[^}]*\}\}/g;
|
|
2636
|
+
var propsDeclarations = (value, at) => value.split(";").flatMap((entry) => {
|
|
2637
|
+
const [address, kind] = entry.split("|");
|
|
2638
|
+
if (!address) return [];
|
|
2639
|
+
const scope = address.startsWith("layout:") ? "layout" : "page";
|
|
2640
|
+
return [{ scope, path: stripLayoutPrefix(address), kind: kind ?? "", at, via: "props" }];
|
|
2641
|
+
});
|
|
2642
|
+
var propsPaths = (value) => propsDeclarations(value, 0).map((d) => ({ scope: d.scope, path: d.path }));
|
|
2643
|
+
var TEMPLATE_BINDING = /^:?data-bcms-(?:layout-)?field\s*=\s*(?:\{\s*`([^`]+)`\s*\}|"\s*`([^`]+)`\s*")$/;
|
|
2644
|
+
var shapeOfPath = (path) => path.replace(/\[(?:\d+|\$\{[^}]*\})\]/g, "[*]");
|
|
2645
|
+
function declarationsIn(roots, content) {
|
|
2646
|
+
const out = [];
|
|
2647
|
+
const visit = (node) => {
|
|
2648
|
+
if (node.type === "expr") {
|
|
2649
|
+
for (const child of node.children) visit(child);
|
|
2650
|
+
return;
|
|
2651
|
+
}
|
|
2652
|
+
if (node.type !== "element") return;
|
|
2653
|
+
const kind = node.attrs.find((a) => a.name === "data-bcms-kind")?.value ?? "";
|
|
2654
|
+
const at = node.attrInsertAt;
|
|
2655
|
+
for (const attr of node.attrs) {
|
|
2656
|
+
const name = attr.name.replace(/^:/, "");
|
|
2657
|
+
if (name === "data-bcms-field" || name === "data-bcms-layout-field") {
|
|
2658
|
+
const scope = name === "data-bcms-layout-field" ? "layout" : "page";
|
|
2659
|
+
const template = content.slice(attr.range.start, attr.range.end).match(TEMPLATE_BINDING);
|
|
2660
|
+
const templated = template?.[1] ?? template?.[2];
|
|
2661
|
+
if (templated) out.push({ scope, path: shapeOfPath(stripLayoutPrefix(templated)), kind, at, via: "field" });
|
|
2662
|
+
else if (attr.value) out.push({ scope, path: stripLayoutPrefix(attr.value), kind, at, via: "field" });
|
|
2663
|
+
} else if (attr.name === "data-bcms-props") {
|
|
2664
|
+
out.push(...propsDeclarations(attr.value, at));
|
|
2665
|
+
} else if (attr.name === "bcmsBindings") {
|
|
2666
|
+
for (const path of bindingsPaths(content.slice(attr.range.start, attr.range.end))) {
|
|
2667
|
+
out.push({ scope: "page", path, kind: "", at, via: "prop" });
|
|
2668
|
+
}
|
|
2669
|
+
}
|
|
2670
|
+
}
|
|
2671
|
+
for (const child of node.children) visit(child);
|
|
2672
|
+
};
|
|
2673
|
+
for (const root of roots) visit(root);
|
|
2674
|
+
return out;
|
|
2675
|
+
}
|
|
2676
|
+
var bindingsPaths = (text) => [...text.matchAll(/["']([^"']+)["']/g)].map((match) => match[1]);
|
|
2677
|
+
var scopedPath = (scope, path) => `${scope}::${path}`;
|
|
2678
|
+
var covers = (declared, target) => declared !== void 0 && (declared.has(scopedPath(target.scope, target.path)) || declared.has(scopedPath(target.scope, shapeOfPath(target.path))));
|
|
2679
|
+
var declaredInTree = (roots, content) => new Set(declarationsIn(roots, content).map((d) => scopedPath(d.scope, d.path)));
|
|
2680
|
+
function declaredByScan(content) {
|
|
2681
|
+
const out = /* @__PURE__ */ new Set();
|
|
2682
|
+
const add = (scope, path) => void out.add(scopedPath(scope, path));
|
|
2683
|
+
for (const match of content.matchAll(BINDING_ATTR)) {
|
|
2684
|
+
add(match[0].includes("layout-field") ? "layout" : "page", stripLayoutPrefix(match[1]));
|
|
2685
|
+
}
|
|
2686
|
+
for (const match of content.matchAll(TEMPLATE_SCAN)) {
|
|
2687
|
+
add(match[0].includes("layout-field") ? "layout" : "page", shapeOfPath(stripLayoutPrefix(match[1] ?? match[2])));
|
|
2688
|
+
}
|
|
2689
|
+
for (const match of content.matchAll(BINDINGS_SCAN)) for (const path of bindingsPaths(match[0])) add("page", path);
|
|
2690
|
+
for (const match of content.matchAll(PROPS_ATTR))
|
|
2691
|
+
for (const entry of propsPaths(match[1])) add(entry.scope, entry.path);
|
|
2692
|
+
return out;
|
|
2693
|
+
}
|
|
2694
|
+
var stripLayoutPrefix = (value) => value.startsWith("layout:") ? value.slice("layout:".length) : value;
|
|
2695
|
+
|
|
2631
2696
|
// src/scope.ts
|
|
2632
2697
|
function patternNames(node, out) {
|
|
2633
2698
|
if (!node || typeof node !== "object") return;
|
|
@@ -2914,7 +2979,10 @@ function wordBounded(haystack, needle) {
|
|
|
2914
2979
|
}
|
|
2915
2980
|
|
|
2916
2981
|
// src/loops.ts
|
|
2917
|
-
|
|
2982
|
+
function splitNested(leaf) {
|
|
2983
|
+
const match = leaf.match(/^([^[\]]+)\[(\d+)\]\.(.+)$/);
|
|
2984
|
+
return match ? { array: match[1], index: Number(match[2]), leaf: match[3] } : null;
|
|
2985
|
+
}
|
|
2918
2986
|
var elementEnd = (node) => node.inner ? node.inner.end + node.tag.length + 3 : null;
|
|
2919
2987
|
function findRows(roots, members) {
|
|
2920
2988
|
const wanted = new Set(members.map((m) => m.index));
|
|
@@ -2986,6 +3054,69 @@ function indentOf(content, at) {
|
|
|
2986
3054
|
const prefix = content.slice(lineStart, at);
|
|
2987
3055
|
return prefix.trim() === "" ? prefix : "";
|
|
2988
3056
|
}
|
|
3057
|
+
function writeLeaf(source, shift, member, rule, read, row, literal) {
|
|
3058
|
+
const site = member.site;
|
|
3059
|
+
const expression = `${read}(${row}, ${JSON.stringify(member.leaf)}, "")`;
|
|
3060
|
+
if (member.kind === "richtext" && rule.richtext) {
|
|
3061
|
+
source.remove(site.inner.start + shift, site.inner.end + shift);
|
|
3062
|
+
source.appendLeft(site.attrInsertAt + shift, ` ${rule.richtext(expression)}`);
|
|
3063
|
+
} else {
|
|
3064
|
+
source.overwrite(site.inner.start + shift, site.inner.end + shift, rule.text(expression));
|
|
3065
|
+
}
|
|
3066
|
+
const kind = member.kind ? ` data-bcms-kind="${member.kind}"` : "";
|
|
3067
|
+
source.appendLeft(site.attrInsertAt + shift, ` ${rule.attr("data-bcms-field", `\`${literal}\``)}${kind}`);
|
|
3068
|
+
}
|
|
3069
|
+
function emitNested(rule, array, members, prefix, outer, parent, ctx) {
|
|
3070
|
+
if (!rule.loop || !rule.text) return null;
|
|
3071
|
+
const inner = [];
|
|
3072
|
+
for (const member of members) {
|
|
3073
|
+
const split = splitNested(member.leaf);
|
|
3074
|
+
if (!split || splitNested(split.leaf) !== null) return null;
|
|
3075
|
+
inner.push({ ...member, index: split.index, leaf: split.leaf });
|
|
3076
|
+
}
|
|
3077
|
+
const rows = findRows([parent.node], inner);
|
|
3078
|
+
if (!rows || rows.length === 0) return null;
|
|
3079
|
+
if (!consecutive(rows, ctx.content)) return null;
|
|
3080
|
+
if (!sameShape(rows, ctx.content)) return null;
|
|
3081
|
+
const template = rows[0];
|
|
3082
|
+
const used = /* @__PURE__ */ new Set([
|
|
3083
|
+
...ctx.content.slice(template.range.start, template.range.end).match(/[A-Za-z_$][\w$]*/g) ?? [],
|
|
3084
|
+
outer.row,
|
|
3085
|
+
outer.index
|
|
3086
|
+
]);
|
|
3087
|
+
const allocated = allocateNames(used, [
|
|
3088
|
+
{ key: "row", name: "item" },
|
|
3089
|
+
{ key: "index", name: "j" }
|
|
3090
|
+
]);
|
|
3091
|
+
const names = { row: allocated.get("row"), index: allocated.get("index") };
|
|
3092
|
+
const fallback = [];
|
|
3093
|
+
const writable = inner.every((member) => setLeaf(fallback[member.index] ??= emptyRow(), member.leaf, member.fallback));
|
|
3094
|
+
if (!writable) return null;
|
|
3095
|
+
const source = new MagicString(ctx.content.slice(template.range.start, template.range.end));
|
|
3096
|
+
const shift = -template.range.start;
|
|
3097
|
+
const declarations = [];
|
|
3098
|
+
for (const member of template.members) {
|
|
3099
|
+
const literal = `${prefix}.${array}[\${${names.index}}].${member.leaf}`;
|
|
3100
|
+
writeLeaf(source, shift, member, rule, ctx.read, names.row, literal);
|
|
3101
|
+
declarations.push({ path: shapeOfPath(literal), literal });
|
|
3102
|
+
}
|
|
3103
|
+
const rowsExpr = `${ctx.rows}(${outer.row}, ${JSON.stringify(array)}, ${JSON.stringify(fallback.filter(Boolean))})`;
|
|
3104
|
+
if (rule.loop.kind === "attr") {
|
|
3105
|
+
source.appendRight(template.attrInsertAt + shift, ` ${rule.loop.attr(rowsExpr, names.row, names.index)}`);
|
|
3106
|
+
}
|
|
3107
|
+
if (rule.loopKey) {
|
|
3108
|
+
const key = rule.loopKey(names.index);
|
|
3109
|
+
if (!template.keyAttr) source.appendRight(template.attrInsertAt + shift, ` ${key}`);
|
|
3110
|
+
else if (template.keyAttr.end > template.keyAttr.start)
|
|
3111
|
+
source.overwrite(template.keyAttr.start + shift, template.keyAttr.end + shift, key);
|
|
3112
|
+
else return null;
|
|
3113
|
+
}
|
|
3114
|
+
const indent = indentOf(ctx.content, template.range.start);
|
|
3115
|
+
const text = rule.loop.kind === "wrap" ? `${rule.loop.open(rowsExpr, names.row, names.index)}
|
|
3116
|
+
${indented(source.toString(), indent)}
|
|
3117
|
+
${indent}${rule.loop.close}` : source.toString();
|
|
3118
|
+
return { range: { start: template.range.start, end: rows[rows.length - 1].range.end }, text, declarations };
|
|
3119
|
+
}
|
|
2989
3120
|
function emitRepeater(dialect, group, arrayPath, fallbackRows, ctx) {
|
|
2990
3121
|
const rule = DIALECT_RULES[dialect];
|
|
2991
3122
|
if (!rule.loop || !rule.text || group.length === 0) return null;
|
|
@@ -3003,20 +3134,25 @@ function emitRepeater(dialect, group, arrayPath, fallbackRows, ctx) {
|
|
|
3003
3134
|
const names = { row: allocated.get("row"), index: allocated.get("index") };
|
|
3004
3135
|
const source = new MagicString(ctx.content.slice(template.range.start, template.range.end));
|
|
3005
3136
|
const shift = -template.range.start;
|
|
3006
|
-
const
|
|
3137
|
+
const declarations = [];
|
|
3138
|
+
const nested = /* @__PURE__ */ new Map();
|
|
3139
|
+
const direct = [];
|
|
3007
3140
|
for (const member of template.members) {
|
|
3008
|
-
const
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
}
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3141
|
+
const inner = splitNested(member.leaf);
|
|
3142
|
+
if (inner === null) direct.push(member);
|
|
3143
|
+
else nested.set(inner.array, [...nested.get(inner.array) ?? [], member]);
|
|
3144
|
+
}
|
|
3145
|
+
for (const [array, members] of nested) {
|
|
3146
|
+
const plan2 = emitNested(rule, array, members, `${arrayPath}[\${${names.index}}]`, names, template, ctx);
|
|
3147
|
+
if (!plan2) return null;
|
|
3148
|
+
if (direct.some((m) => m.site.range.start >= plan2.range.start && m.site.range.end <= plan2.range.end)) return null;
|
|
3149
|
+
source.overwrite(plan2.range.start + shift, plan2.range.end + shift, plan2.text);
|
|
3150
|
+
declarations.push(...plan2.declarations);
|
|
3151
|
+
}
|
|
3152
|
+
for (const member of direct) {
|
|
3153
|
+
const literal = `${arrayPath}[\${${names.index}}].${member.leaf}`;
|
|
3154
|
+
writeLeaf(source, shift, member, rule, ctx.read, names.row, literal);
|
|
3155
|
+
declarations.push({ path: shapeOfPath(literal), literal });
|
|
3020
3156
|
}
|
|
3021
3157
|
const args = [ctx.snapshot, JSON.stringify(arrayPath), JSON.stringify(fallbackRows), ...ctx.slug ? [ctx.slug] : []];
|
|
3022
3158
|
const rowsExpr = `${ctx.rows}(${args.join(", ")})`;
|
|
@@ -3037,7 +3173,8 @@ ${indent}${rule.loop.close}` : source.toString();
|
|
|
3037
3173
|
return {
|
|
3038
3174
|
range: { start: template.range.start, end: rows[rows.length - 1].range.end },
|
|
3039
3175
|
text,
|
|
3040
|
-
|
|
3176
|
+
declarations,
|
|
3177
|
+
bindings: [...new Set(declarations.map((d) => d.path))],
|
|
3041
3178
|
names
|
|
3042
3179
|
};
|
|
3043
3180
|
}
|
|
@@ -3067,9 +3204,9 @@ function setLeaf(row, leaf, value) {
|
|
|
3067
3204
|
var FORBIDDEN = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
3068
3205
|
var emptyRow = () => /* @__PURE__ */ Object.create(null);
|
|
3069
3206
|
function splitIndexed(arrayPath, path) {
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
return { index: Number(match[
|
|
3207
|
+
if (!path.startsWith(`${arrayPath}[`)) return null;
|
|
3208
|
+
const match = path.slice(arrayPath.length).match(/^\[(\d+)\]\.(.+)$/);
|
|
3209
|
+
return match ? { index: Number(match[1]), leaf: match[2] } : null;
|
|
3073
3210
|
}
|
|
3074
3211
|
|
|
3075
3212
|
// src/sites/jsx.ts
|
|
@@ -3562,22 +3699,68 @@ var firstPresent = (base, files) => [base, ...EXTENSIONS.map((ext) => `${base}${
|
|
|
3562
3699
|
function aliasesFrom(sources) {
|
|
3563
3700
|
const out = /* @__PURE__ */ new Map();
|
|
3564
3701
|
for (const source of sources) {
|
|
3565
|
-
if (!
|
|
3566
|
-
|
|
3567
|
-
|
|
3568
|
-
|
|
3569
|
-
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
|
|
3574
|
-
|
|
3575
|
-
}
|
|
3576
|
-
} catch {
|
|
3702
|
+
if (!isProjectConfig(source.path)) continue;
|
|
3703
|
+
const parsed = readJsonc(source.content);
|
|
3704
|
+
if (parsed === null) continue;
|
|
3705
|
+
const base = parsed.compilerOptions?.baseUrl?.replace(/^\.\/?/, "").replace(/\/$/, "") ?? "";
|
|
3706
|
+
const root = source.path.split("/").slice(0, -1).join("/");
|
|
3707
|
+
for (const [pattern, targets] of Object.entries(parsed.compilerOptions?.paths ?? {})) {
|
|
3708
|
+
out.set(
|
|
3709
|
+
pattern,
|
|
3710
|
+
targets.map((target) => [root, base, target.replace(/^\.\/?/, "")].filter(Boolean).join("/"))
|
|
3711
|
+
);
|
|
3577
3712
|
}
|
|
3578
3713
|
}
|
|
3579
3714
|
return out;
|
|
3580
3715
|
}
|
|
3716
|
+
var isProjectConfig = (path) => path.endsWith("tsconfig.json") || path.endsWith("jsconfig.json");
|
|
3717
|
+
function readJsonc(content) {
|
|
3718
|
+
let out = "";
|
|
3719
|
+
let at = 0;
|
|
3720
|
+
while (at < content.length) {
|
|
3721
|
+
const char = content[at];
|
|
3722
|
+
if (char === '"') {
|
|
3723
|
+
const start = at++;
|
|
3724
|
+
while (at < content.length && content[at] !== '"') at += content[at] === "\\" ? 2 : 1;
|
|
3725
|
+
out += content.slice(start, Math.min(at + 1, content.length));
|
|
3726
|
+
at++;
|
|
3727
|
+
continue;
|
|
3728
|
+
}
|
|
3729
|
+
if (char === "/" && content[at + 1] === "/") {
|
|
3730
|
+
while (at < content.length && content[at] !== "\n") at++;
|
|
3731
|
+
continue;
|
|
3732
|
+
}
|
|
3733
|
+
if (char === "/" && content[at + 1] === "*") {
|
|
3734
|
+
const close = content.indexOf("*/", at + 2);
|
|
3735
|
+
at = close < 0 ? content.length : close + 2;
|
|
3736
|
+
continue;
|
|
3737
|
+
}
|
|
3738
|
+
out += char;
|
|
3739
|
+
at++;
|
|
3740
|
+
}
|
|
3741
|
+
try {
|
|
3742
|
+
const parsed = JSON.parse(out.replace(/,(?=\s*[}\]])/g, ""));
|
|
3743
|
+
return isAliasShaped(parsed) ? parsed : null;
|
|
3744
|
+
} catch {
|
|
3745
|
+
return null;
|
|
3746
|
+
}
|
|
3747
|
+
}
|
|
3748
|
+
var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3749
|
+
function isAliasShaped(value) {
|
|
3750
|
+
if (!isRecord(value)) return false;
|
|
3751
|
+
const options = value.compilerOptions;
|
|
3752
|
+
if (options === void 0) return true;
|
|
3753
|
+
if (!isRecord(options)) return false;
|
|
3754
|
+
if (options.baseUrl !== void 0 && typeof options.baseUrl !== "string") return false;
|
|
3755
|
+
if (options.paths === void 0) return true;
|
|
3756
|
+
if (!isRecord(options.paths)) return false;
|
|
3757
|
+
return Object.values(options.paths).every(
|
|
3758
|
+
(targets) => Array.isArray(targets) && targets.every((target) => typeof target === "string")
|
|
3759
|
+
);
|
|
3760
|
+
}
|
|
3761
|
+
function unreadableConfigs(sources) {
|
|
3762
|
+
return sources.filter((source) => isProjectConfig(source.path) && readJsonc(source.content) === null).map((source) => source.path);
|
|
3763
|
+
}
|
|
3581
3764
|
function expand(specifier, aliases) {
|
|
3582
3765
|
const out = [];
|
|
3583
3766
|
for (const [pattern, targets] of aliases) {
|
|
@@ -3746,70 +3929,6 @@ function typeMember(content, literal) {
|
|
|
3746
3929
|
return { start: at, end: at, text: `${terminated ? "" : ";"} ${text}` };
|
|
3747
3930
|
}
|
|
3748
3931
|
|
|
3749
|
-
// src/declarations.ts
|
|
3750
|
-
var BINDING_ATTR = /data-bcms-(?:layout-)?field\s*=\s*["']([^"']+)["']/g;
|
|
3751
|
-
var PROPS_ATTR = /data-bcms-props\s*=\s*["']([^"']+)["']/g;
|
|
3752
|
-
var TEMPLATE_SCAN = /:?data-bcms-(?:layout-)?field\s*=\s*(?:\{\s*`([^`]+)`\s*\}|"\s*`([^`]+)`\s*")/g;
|
|
3753
|
-
var BINDINGS_SCAN = /bcmsBindings\s*=\s*\{\{[^}]*\}\}/g;
|
|
3754
|
-
var propsDeclarations = (value, at) => value.split(";").flatMap((entry) => {
|
|
3755
|
-
const [address, kind] = entry.split("|");
|
|
3756
|
-
if (!address) return [];
|
|
3757
|
-
const scope = address.startsWith("layout:") ? "layout" : "page";
|
|
3758
|
-
return [{ scope, path: stripLayoutPrefix(address), kind: kind ?? "", at, via: "props" }];
|
|
3759
|
-
});
|
|
3760
|
-
var propsPaths = (value) => propsDeclarations(value, 0).map((d) => ({ scope: d.scope, path: d.path }));
|
|
3761
|
-
var TEMPLATE_BINDING = /^:?data-bcms-(?:layout-)?field\s*=\s*(?:\{\s*`([^`]+)`\s*\}|"\s*`([^`]+)`\s*")$/;
|
|
3762
|
-
var shapeOfPath = (path) => path.replace(/\[(?:\d+|\$\{[^}]*\})\]/g, "[*]");
|
|
3763
|
-
function declarationsIn(roots, content) {
|
|
3764
|
-
const out = [];
|
|
3765
|
-
const visit = (node) => {
|
|
3766
|
-
if (node.type === "expr") {
|
|
3767
|
-
for (const child of node.children) visit(child);
|
|
3768
|
-
return;
|
|
3769
|
-
}
|
|
3770
|
-
if (node.type !== "element") return;
|
|
3771
|
-
const kind = node.attrs.find((a) => a.name === "data-bcms-kind")?.value ?? "";
|
|
3772
|
-
const at = node.attrInsertAt;
|
|
3773
|
-
for (const attr of node.attrs) {
|
|
3774
|
-
const name = attr.name.replace(/^:/, "");
|
|
3775
|
-
if (name === "data-bcms-field" || name === "data-bcms-layout-field") {
|
|
3776
|
-
const scope = name === "data-bcms-layout-field" ? "layout" : "page";
|
|
3777
|
-
const template = content.slice(attr.range.start, attr.range.end).match(TEMPLATE_BINDING);
|
|
3778
|
-
const templated = template?.[1] ?? template?.[2];
|
|
3779
|
-
if (templated) out.push({ scope, path: shapeOfPath(stripLayoutPrefix(templated)), kind, at, via: "field" });
|
|
3780
|
-
else if (attr.value) out.push({ scope, path: stripLayoutPrefix(attr.value), kind, at, via: "field" });
|
|
3781
|
-
} else if (attr.name === "data-bcms-props") {
|
|
3782
|
-
out.push(...propsDeclarations(attr.value, at));
|
|
3783
|
-
} else if (attr.name === "bcmsBindings") {
|
|
3784
|
-
for (const path of bindingsPaths(content.slice(attr.range.start, attr.range.end))) {
|
|
3785
|
-
out.push({ scope: "page", path, kind: "", at, via: "prop" });
|
|
3786
|
-
}
|
|
3787
|
-
}
|
|
3788
|
-
}
|
|
3789
|
-
for (const child of node.children) visit(child);
|
|
3790
|
-
};
|
|
3791
|
-
for (const root of roots) visit(root);
|
|
3792
|
-
return out;
|
|
3793
|
-
}
|
|
3794
|
-
var bindingsPaths = (text) => [...text.matchAll(/["']([^"']+)["']/g)].map((match) => match[1]);
|
|
3795
|
-
var scopedPath = (scope, path) => `${scope}::${path}`;
|
|
3796
|
-
var declaredInTree = (roots, content) => new Set(declarationsIn(roots, content).map((d) => scopedPath(d.scope, d.path)));
|
|
3797
|
-
function declaredByScan(content) {
|
|
3798
|
-
const out = /* @__PURE__ */ new Set();
|
|
3799
|
-
const add = (scope, path) => void out.add(scopedPath(scope, path));
|
|
3800
|
-
for (const match of content.matchAll(BINDING_ATTR)) {
|
|
3801
|
-
add(match[0].includes("layout-field") ? "layout" : "page", stripLayoutPrefix(match[1]));
|
|
3802
|
-
}
|
|
3803
|
-
for (const match of content.matchAll(TEMPLATE_SCAN)) {
|
|
3804
|
-
add(match[0].includes("layout-field") ? "layout" : "page", shapeOfPath(stripLayoutPrefix(match[1] ?? match[2])));
|
|
3805
|
-
}
|
|
3806
|
-
for (const match of content.matchAll(BINDINGS_SCAN)) for (const path of bindingsPaths(match[0])) add("page", path);
|
|
3807
|
-
for (const match of content.matchAll(PROPS_ATTR))
|
|
3808
|
-
for (const entry of propsPaths(match[1])) add(entry.scope, entry.path);
|
|
3809
|
-
return out;
|
|
3810
|
-
}
|
|
3811
|
-
var stripLayoutPrefix = (value) => value.startsWith("layout:") ? value.slice("layout:".length) : value;
|
|
3812
|
-
|
|
3813
3932
|
// src/converted.ts
|
|
3814
3933
|
var escapeRegExp = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3815
3934
|
function splitArrayPath(path) {
|
|
@@ -4643,7 +4762,7 @@ var ValidationError = class extends Error {
|
|
|
4643
4762
|
}
|
|
4644
4763
|
code;
|
|
4645
4764
|
};
|
|
4646
|
-
var
|
|
4765
|
+
var isRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4647
4766
|
var Check = class {
|
|
4648
4767
|
constructor(code) {
|
|
4649
4768
|
this.code = code;
|
|
@@ -4653,7 +4772,7 @@ var Check = class {
|
|
|
4653
4772
|
throw new ValidationError(this.code, `${where} ${why}.`);
|
|
4654
4773
|
}
|
|
4655
4774
|
record(value, where) {
|
|
4656
|
-
if (!
|
|
4775
|
+
if (!isRecord2(value)) this.fail(where, "is not an object");
|
|
4657
4776
|
return value;
|
|
4658
4777
|
}
|
|
4659
4778
|
array(value, where) {
|
|
@@ -5101,10 +5220,10 @@ var SectionInvariantError = class extends Error {
|
|
|
5101
5220
|
}
|
|
5102
5221
|
};
|
|
5103
5222
|
function assertSections(total, sections) {
|
|
5104
|
-
const sum = sections.extracted + sections.inlineOnly + sections.alreadyExtracted + sections.pending.length;
|
|
5223
|
+
const sum = sections.extracted + sections.inlineOnly + sections.alreadyExtracted + sections.registered + sections.pending.length;
|
|
5105
5224
|
if (sum !== total) {
|
|
5106
5225
|
throw new SectionInvariantError(
|
|
5107
|
-
`The receipt does not account for every section: ${total} planned but ${sections.extracted} extracted + ${sections.inlineOnly} inline-only + ${sections.alreadyExtracted} already extracted + ${sections.pending.length} pending = ${sum}.`
|
|
5226
|
+
`The receipt does not account for every section: ${total} planned but ${sections.extracted} extracted + ${sections.inlineOnly} inline-only + ${sections.alreadyExtracted} already extracted + ${sections.registered} registered + ${sections.pending.length} pending = ${sum}.`
|
|
5108
5227
|
);
|
|
5109
5228
|
}
|
|
5110
5229
|
return sections;
|
|
@@ -5114,16 +5233,28 @@ var REGISTRY_MARKER = "// @bettercms-ai/convert sections v1";
|
|
|
5114
5233
|
var COMPONENT_DIR = "src/components/bcms";
|
|
5115
5234
|
var SECTIONS_LIB = "src/lib/bcms-sections.ts";
|
|
5116
5235
|
var EXTRACTABLE = ["astro", "jsx"];
|
|
5236
|
+
var registryValue = (entry) => entry.member ? `${entry.name}.${entry.member}` : entry.name;
|
|
5237
|
+
function importLine(name, specifier, entry) {
|
|
5238
|
+
if (entry.kind === "namespace") return `import * as ${name} from "${specifier}";`;
|
|
5239
|
+
if (entry.kind === "named") {
|
|
5240
|
+
const exported = entry.imported ?? name;
|
|
5241
|
+
return `import { ${exported === name ? name : `${exported} as ${name}`} } from "${specifier}";`;
|
|
5242
|
+
}
|
|
5243
|
+
return `import ${name} from "${specifier}";`;
|
|
5244
|
+
}
|
|
5117
5245
|
async function componentizeSources(briefIn, planIn, sources, options) {
|
|
5118
5246
|
const pending = [];
|
|
5119
5247
|
let extracted = 0;
|
|
5120
5248
|
let inlineOnly = 0;
|
|
5121
5249
|
let alreadyExtracted = 0;
|
|
5250
|
+
let registered = 0;
|
|
5122
5251
|
let planPending = 0;
|
|
5123
5252
|
let total = 0;
|
|
5124
5253
|
const brief = readBrief(briefIn);
|
|
5125
5254
|
const plan2 = readPlan(planIn);
|
|
5126
5255
|
const contents = new Map(sources.map((s) => [s.path, s.content]));
|
|
5256
|
+
const fileSet = new Set(contents.keys());
|
|
5257
|
+
const aliases = aliasesFrom(sources);
|
|
5127
5258
|
const pend = (route, groupKey, reason, message) => void pending.push({ route, groupKey, reason, ...message ? { message } : {} });
|
|
5128
5259
|
const trees = /* @__PURE__ */ new Map();
|
|
5129
5260
|
const treeOf = async (file) => {
|
|
@@ -5149,6 +5280,7 @@ async function componentizeSources(briefIn, planIn, sources, options) {
|
|
|
5149
5280
|
};
|
|
5150
5281
|
const fresh = /* @__PURE__ */ new Set();
|
|
5151
5282
|
const registryConflicts = [];
|
|
5283
|
+
const registryUnreadable = [];
|
|
5152
5284
|
for (const dialect of EXTRACTABLE) {
|
|
5153
5285
|
const path = `${COMPONENT_DIR}/Sections.${dialect === "astro" ? "astro" : "tsx"}`;
|
|
5154
5286
|
const existing = contents.get(path);
|
|
@@ -5157,7 +5289,11 @@ async function componentizeSources(briefIn, planIn, sources, options) {
|
|
|
5157
5289
|
registryConflicts.push(path);
|
|
5158
5290
|
continue;
|
|
5159
5291
|
}
|
|
5160
|
-
const held = readRegistry(existing, dialect);
|
|
5292
|
+
const held = await readRegistry(existing, dialect, path, fileSet, aliases);
|
|
5293
|
+
if (held === null) {
|
|
5294
|
+
registryUnreadable.push(path);
|
|
5295
|
+
continue;
|
|
5296
|
+
}
|
|
5161
5297
|
componentsOf(dialect);
|
|
5162
5298
|
for (const [slug, component] of held.components) written.get(dialect).set(slug, component);
|
|
5163
5299
|
const order = shipped.get(dialect) ?? /* @__PURE__ */ new Map();
|
|
@@ -5167,6 +5303,7 @@ async function componentizeSources(briefIn, planIn, sources, options) {
|
|
|
5167
5303
|
const lib = contents.get(SECTIONS_LIB);
|
|
5168
5304
|
if (lib !== void 0 && !isGenerated(lib)) registryConflicts.push(SECTIONS_LIB);
|
|
5169
5305
|
const registryBlocked = registryConflicts.length > 0 && options?.overwriteHelper !== true;
|
|
5306
|
+
const registryUnread = registryUnreadable.length > 0;
|
|
5170
5307
|
for (const page of plan2.pages ?? []) {
|
|
5171
5308
|
const sections2 = (page.sections ?? []).filter((section) => {
|
|
5172
5309
|
if (section.pending) {
|
|
@@ -5177,6 +5314,7 @@ async function componentizeSources(briefIn, planIn, sources, options) {
|
|
|
5177
5314
|
});
|
|
5178
5315
|
total += sections2.length;
|
|
5179
5316
|
if (sections2.length === 0) continue;
|
|
5317
|
+
const pendingBefore = pending.length;
|
|
5180
5318
|
const briefPage = brief.pages.find((p) => p.route === page.route);
|
|
5181
5319
|
const pageSlug = briefPage?.slug ?? slugify(page.route === "/" ? "home" : page.route);
|
|
5182
5320
|
if (helperBlocked) {
|
|
@@ -5191,6 +5329,17 @@ async function componentizeSources(briefIn, planIn, sources, options) {
|
|
|
5191
5329
|
}
|
|
5192
5330
|
continue;
|
|
5193
5331
|
}
|
|
5332
|
+
if (registryUnread) {
|
|
5333
|
+
for (const section of sections2) {
|
|
5334
|
+
pend(
|
|
5335
|
+
page.route,
|
|
5336
|
+
section.groupKey,
|
|
5337
|
+
"REGISTRY_UNREADABLE",
|
|
5338
|
+
`${registryUnreadable.join(", ")} carries our marker but its REGISTRY/SHIPPED tables cannot be read back \u2014 rebuilding it would drop the components it names.`
|
|
5339
|
+
);
|
|
5340
|
+
}
|
|
5341
|
+
continue;
|
|
5342
|
+
}
|
|
5194
5343
|
const snapshotPath = `${CONTENT_DIR}/${pageSlug}.json`;
|
|
5195
5344
|
if (!snapshotUsable(contents.get(snapshotPath))) {
|
|
5196
5345
|
for (const section of sections2) {
|
|
@@ -5226,37 +5375,115 @@ async function componentizeSources(briefIn, planIn, sources, options) {
|
|
|
5226
5375
|
}
|
|
5227
5376
|
const live = found.placed;
|
|
5228
5377
|
if (live.length === 0) continue;
|
|
5378
|
+
const content = contents.get(file);
|
|
5379
|
+
const dialect = dialectOf(file, content);
|
|
5380
|
+
if (!dialect || !EXTRACTABLE.includes(dialect)) {
|
|
5381
|
+
for (const placed of live) {
|
|
5382
|
+
pend(page.route, placed.section.groupKey, "DIALECT_UNSUPPORTED", `${file} is ${dialect ?? "not a template"}.`);
|
|
5383
|
+
}
|
|
5384
|
+
continue;
|
|
5385
|
+
}
|
|
5386
|
+
const tree = await treeOf(file);
|
|
5387
|
+
if (!tree) {
|
|
5388
|
+
for (const placed of live) {
|
|
5389
|
+
pend(page.route, placed.section.groupKey, "NOT_IN_SOURCE", `${file} did not parse.`);
|
|
5390
|
+
}
|
|
5391
|
+
continue;
|
|
5392
|
+
}
|
|
5393
|
+
const parsed = tree.parsed;
|
|
5394
|
+
const importedFiles = /* @__PURE__ */ new Map();
|
|
5395
|
+
for (const [local, from] of importsIn(parsed, dialect)) {
|
|
5396
|
+
const resolved = resolveSpecifier(file, from.specifier, fileSet, aliases);
|
|
5397
|
+
if (resolved === null) continue;
|
|
5398
|
+
importedFiles.set(resolved, [
|
|
5399
|
+
...importedFiles.get(resolved) ?? [],
|
|
5400
|
+
{ local, kind: from.kind, imported: from.imported }
|
|
5401
|
+
]);
|
|
5402
|
+
}
|
|
5403
|
+
const bindingOf = (held) => {
|
|
5404
|
+
const bindings = importedFiles.get(held) ?? [];
|
|
5405
|
+
return bindings.find((binding) => calledIn(tree, binding)) ?? bindings[0];
|
|
5406
|
+
};
|
|
5229
5407
|
const placedHere = [];
|
|
5408
|
+
const importedSections = [];
|
|
5230
5409
|
for (const placed of live) {
|
|
5231
5410
|
const elements = placed.byFile.get(file);
|
|
5411
|
+
const alsoRendered = [...placed.byFile.keys()].filter((held2) => held2 !== file && importedFiles.has(held2));
|
|
5232
5412
|
if (elements && elements.length > 0) {
|
|
5413
|
+
if (alsoRendered.length > 0) {
|
|
5414
|
+
pend(
|
|
5415
|
+
page.route,
|
|
5416
|
+
placed.section.groupKey,
|
|
5417
|
+
"SECTION_ROOT_AMBIGUOUS",
|
|
5418
|
+
`rendered inline by ${file} AND by ${alsoRendered.join(", ")}, which it imports.`
|
|
5419
|
+
);
|
|
5420
|
+
continue;
|
|
5421
|
+
}
|
|
5233
5422
|
placedHere.push({ section: placed.section, elements });
|
|
5234
5423
|
continue;
|
|
5235
5424
|
}
|
|
5425
|
+
if (alsoRendered.length > 1) {
|
|
5426
|
+
pend(
|
|
5427
|
+
page.route,
|
|
5428
|
+
placed.section.groupKey,
|
|
5429
|
+
"SECTION_ROOT_AMBIGUOUS",
|
|
5430
|
+
`rendered by ${alsoRendered.join(" and ")}, both imported by ${file}.`
|
|
5431
|
+
);
|
|
5432
|
+
continue;
|
|
5433
|
+
}
|
|
5434
|
+
const only = alsoRendered[0] ?? [...placed.byFile.keys()][0];
|
|
5435
|
+
const held = bindingOf(only);
|
|
5436
|
+
if (held !== void 0 && dialectOf(only, contents.get(only) ?? "") === dialect) {
|
|
5437
|
+
importedSections.push({ section: placed.section, path: only, call: held.local });
|
|
5438
|
+
continue;
|
|
5439
|
+
}
|
|
5236
5440
|
pend(
|
|
5237
5441
|
page.route,
|
|
5238
5442
|
placed.section.groupKey,
|
|
5239
5443
|
"SECTION_ROOT_AMBIGUOUS",
|
|
5240
|
-
`rendered by ${[...placed.byFile.keys()].join(", ")}, not ${file}.`
|
|
5444
|
+
held === void 0 ? `rendered by ${[...placed.byFile.keys()].join(", ")}, which ${file} does not import.` : `rendered by ${only}, which is ${dialectOf(only, contents.get(only) ?? "") ?? "not a template"}, not ${dialect} like ${file}.`
|
|
5241
5445
|
);
|
|
5242
5446
|
}
|
|
5243
|
-
if (placedHere.length === 0) continue;
|
|
5244
|
-
const
|
|
5245
|
-
const
|
|
5246
|
-
|
|
5247
|
-
|
|
5248
|
-
|
|
5447
|
+
if (placedHere.length === 0 && importedSections.length === 0) continue;
|
|
5448
|
+
const extractable = componentsOf(dialect);
|
|
5449
|
+
const registeredHere = [];
|
|
5450
|
+
for (const held of importedSections) {
|
|
5451
|
+
const component = resolveComponent(plan2, held.section);
|
|
5452
|
+
const already = extractable.get(component.slug);
|
|
5453
|
+
if (already !== void 0 && already.path !== held.path) {
|
|
5454
|
+
pend(
|
|
5455
|
+
page.route,
|
|
5456
|
+
held.section.groupKey,
|
|
5457
|
+
"COMPONENT_CONFLICT",
|
|
5458
|
+
`the slug "${component.slug}" already names ${already.path}, not ${held.path}.`
|
|
5459
|
+
);
|
|
5460
|
+
continue;
|
|
5249
5461
|
}
|
|
5250
|
-
|
|
5251
|
-
|
|
5252
|
-
|
|
5253
|
-
|
|
5254
|
-
|
|
5255
|
-
|
|
5462
|
+
const binding = bindingOf(held.path);
|
|
5463
|
+
const member = binding.kind === "namespace" ? namespaceMember(tree, binding.local) : void 0;
|
|
5464
|
+
if (binding.kind === "namespace" && member === void 0) {
|
|
5465
|
+
pend(
|
|
5466
|
+
page.route,
|
|
5467
|
+
held.section.groupKey,
|
|
5468
|
+
"SECTION_ROOT_AMBIGUOUS",
|
|
5469
|
+
`${held.path} is imported as a namespace and ${file} never calls one of its components, so nothing names the export that renders it.`
|
|
5470
|
+
);
|
|
5471
|
+
continue;
|
|
5256
5472
|
}
|
|
5257
|
-
|
|
5473
|
+
extractable.set(component.slug, {
|
|
5474
|
+
name: component.name,
|
|
5475
|
+
path: held.path,
|
|
5476
|
+
kind: binding.kind,
|
|
5477
|
+
imported: binding.imported,
|
|
5478
|
+
...member ? { member } : {}
|
|
5479
|
+
});
|
|
5480
|
+
registered++;
|
|
5481
|
+
registeredHere.push({
|
|
5482
|
+
slug: component.slug,
|
|
5483
|
+
bind: held.section.groupKey,
|
|
5484
|
+
call: callSiteOf(tree, member ? `${binding.local}.${member}` : held.call)
|
|
5485
|
+
});
|
|
5258
5486
|
}
|
|
5259
|
-
const parsed = tree.parsed;
|
|
5260
5487
|
const roots = [];
|
|
5261
5488
|
for (const placed of placedHere) {
|
|
5262
5489
|
const root = lowestCommonAncestor(placed.elements);
|
|
@@ -5280,8 +5507,6 @@ async function componentizeSources(briefIn, planIn, sources, options) {
|
|
|
5280
5507
|
pend(page.route, resolved.section.groupKey, "SECTION_ROOT_AMBIGUOUS", "its root contains another section's.");
|
|
5281
5508
|
}
|
|
5282
5509
|
const candidates = roots.filter((r) => !nested.has(r)).sort((a, b) => a.root.start - b.root.start);
|
|
5283
|
-
if (candidates.length === 0) continue;
|
|
5284
|
-
const extractable = componentsOf(dialect);
|
|
5285
5510
|
const placeable = [];
|
|
5286
5511
|
for (const resolved of candidates) {
|
|
5287
5512
|
const path = `${COMPONENT_DIR}/${resolved.name}.${dialect === "astro" ? "astro" : "tsx"}`;
|
|
@@ -5304,7 +5529,7 @@ async function componentizeSources(briefIn, planIn, sources, options) {
|
|
|
5304
5529
|
);
|
|
5305
5530
|
continue;
|
|
5306
5531
|
}
|
|
5307
|
-
extractable.set(resolved.slug, { name: resolved.name, path });
|
|
5532
|
+
extractable.set(resolved.slug, { name: resolved.name, path, kind: "default", imported: null });
|
|
5308
5533
|
fresh.add(resolved.slug);
|
|
5309
5534
|
addFile(outFiles, contents, {
|
|
5310
5535
|
path,
|
|
@@ -5313,24 +5538,42 @@ async function componentizeSources(briefIn, planIn, sources, options) {
|
|
|
5313
5538
|
});
|
|
5314
5539
|
placeable.push(resolved);
|
|
5315
5540
|
}
|
|
5316
|
-
if (placeable.length === 0) continue;
|
|
5317
|
-
const
|
|
5541
|
+
if (placeable.length === 0 && registeredHere.length === 0) continue;
|
|
5542
|
+
const spans = [
|
|
5543
|
+
...placeable.map((r) => ({ slug: r.slug, bind: r.section.groupKey, root: r.root })),
|
|
5544
|
+
...registeredHere.map((r) => ({ slug: r.slug, bind: r.bind, root: r.call }))
|
|
5545
|
+
].sort((a, b) => (a.root?.start ?? Number.MAX_SAFE_INTEGER) - (b.root?.start ?? Number.MAX_SAFE_INTEGER));
|
|
5546
|
+
const known = spans.filter((s) => s.root !== null);
|
|
5547
|
+
const layout = runOf(known, parsed.roots, content);
|
|
5318
5548
|
if (layout === null) {
|
|
5319
5549
|
for (const resolved of placeable) {
|
|
5320
5550
|
pend(page.route, resolved.section.groupKey, "SECTION_NOT_CONTIGUOUS", "its roots share no container.");
|
|
5321
5551
|
}
|
|
5322
5552
|
continue;
|
|
5323
5553
|
}
|
|
5554
|
+
const wholePage = registeredHere.length === 0 || known.length === spans.length && pending.length === pendingBefore;
|
|
5555
|
+
const useRun = layout.contiguous && wholePage;
|
|
5324
5556
|
const order = shipped.get(dialect) ?? /* @__PURE__ */ new Map();
|
|
5325
5557
|
shipped.set(dialect, order);
|
|
5326
5558
|
order.set(
|
|
5327
5559
|
pageSlug,
|
|
5328
|
-
|
|
5560
|
+
spans.map((s) => ({ slug: s.slug, bind: s.bind }))
|
|
5329
5561
|
);
|
|
5330
|
-
|
|
5331
|
-
|
|
5332
|
-
|
|
5333
|
-
|
|
5562
|
+
if (useRun) {
|
|
5563
|
+
addFile(outFiles, contents, {
|
|
5564
|
+
path: file,
|
|
5565
|
+
operation: "modify",
|
|
5566
|
+
content: splicePageRun(file, content, dialect, parsed, known, pageSlug)
|
|
5567
|
+
});
|
|
5568
|
+
extracted += placeable.length;
|
|
5569
|
+
} else if (placeable.length > 0) {
|
|
5570
|
+
addFile(outFiles, contents, {
|
|
5571
|
+
path: file,
|
|
5572
|
+
operation: "modify",
|
|
5573
|
+
content: splicePageInline(file, content, dialect, parsed, placeable, pageSlug, extractable)
|
|
5574
|
+
});
|
|
5575
|
+
inlineOnly += placeable.length;
|
|
5576
|
+
}
|
|
5334
5577
|
}
|
|
5335
5578
|
const componentSlugs = [...written.values()].flatMap((held) => [...held.keys()]);
|
|
5336
5579
|
if (componentSlugs.length > 0) {
|
|
@@ -5352,7 +5595,7 @@ async function componentizeSources(briefIn, planIn, sources, options) {
|
|
|
5352
5595
|
emitHelper(outFiles, contents, helperVersion, options?.overwriteHelper);
|
|
5353
5596
|
emitStubs(outFiles, contents, pageSlugs);
|
|
5354
5597
|
}
|
|
5355
|
-
const sections = assertSections(total, { extracted, inlineOnly, alreadyExtracted, pending });
|
|
5598
|
+
const sections = assertSections(total, { extracted, inlineOnly, alreadyExtracted, registered, pending });
|
|
5356
5599
|
return {
|
|
5357
5600
|
files: [...outFiles.values()].sort((a, b) => a.path.localeCompare(b.path)),
|
|
5358
5601
|
receipt: {
|
|
@@ -5360,7 +5603,14 @@ async function componentizeSources(briefIn, planIn, sources, options) {
|
|
|
5360
5603
|
sections,
|
|
5361
5604
|
// What THIS run wrote a file for. A component an earlier run left is reused, not re-reported.
|
|
5362
5605
|
components: [...fresh].sort(),
|
|
5363
|
-
planPending
|
|
5606
|
+
planPending,
|
|
5607
|
+
notes: unreadableConfigs(sources).map(
|
|
5608
|
+
(path) => ({
|
|
5609
|
+
code: "TSCONFIG_UNREADABLE",
|
|
5610
|
+
file: path,
|
|
5611
|
+
message: `${path} is not JSON this package can read, so its \`paths\` aliases resolved to nothing.`
|
|
5612
|
+
})
|
|
5613
|
+
)
|
|
5364
5614
|
}
|
|
5365
5615
|
};
|
|
5366
5616
|
}
|
|
@@ -5373,29 +5623,138 @@ function alreadyOn(content, pageSlug, sections) {
|
|
|
5373
5623
|
}
|
|
5374
5624
|
return sections.map((section) => section.groupKey).filter((groupKey) => new RegExp(`bind=\\s*["']${groupKey.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}["']`).test(content));
|
|
5375
5625
|
}
|
|
5376
|
-
function readRegistry(content, dialect) {
|
|
5626
|
+
async function readRegistry(content, dialect, path, files, aliases) {
|
|
5377
5627
|
const components = /* @__PURE__ */ new Map();
|
|
5378
5628
|
const shipped = /* @__PURE__ */ new Map();
|
|
5379
|
-
const
|
|
5380
|
-
|
|
5381
|
-
|
|
5382
|
-
|
|
5383
|
-
|
|
5384
|
-
|
|
5385
|
-
|
|
5386
|
-
|
|
5387
|
-
|
|
5388
|
-
|
|
5389
|
-
|
|
5390
|
-
const table = content
|
|
5391
|
-
|
|
5629
|
+
const parsed = await parseFile4(dialect, content);
|
|
5630
|
+
if (parsed.error) return null;
|
|
5631
|
+
const imports = /* @__PURE__ */ new Map();
|
|
5632
|
+
for (const [local, from] of importsIn(parsed, dialect)) {
|
|
5633
|
+
if (!from.specifier.startsWith(".")) continue;
|
|
5634
|
+
const resolved = resolveSpecifier(path, from.specifier, files, aliases);
|
|
5635
|
+
if (resolved !== null) {
|
|
5636
|
+
imports.set(local, { name: local, path: resolved, kind: from.kind, imported: from.imported });
|
|
5637
|
+
}
|
|
5638
|
+
}
|
|
5639
|
+
const registry = blockOf(content, "REGISTRY");
|
|
5640
|
+
const table = blockOf(content, "SHIPPED");
|
|
5641
|
+
if (registry === null || table === null) return null;
|
|
5642
|
+
const registryRows = propertiesOf(registry);
|
|
5643
|
+
const shippedRows = propertiesOf(table);
|
|
5644
|
+
if (registryRows === null || shippedRows === null) return null;
|
|
5645
|
+
for (const row of registryRows) {
|
|
5646
|
+
const named = row.value.match(/^([A-Za-z_$][\w$]*)(?:\.([A-Za-z_$][\w$]*))?$/);
|
|
5647
|
+
const entry = named ? imports.get(named[1]) : void 0;
|
|
5648
|
+
if (!named || !entry) return null;
|
|
5649
|
+
components.set(row.key, named[2] === void 0 ? entry : { ...entry, member: named[2] });
|
|
5650
|
+
}
|
|
5651
|
+
for (const row of shippedRows) {
|
|
5392
5652
|
try {
|
|
5393
|
-
|
|
5653
|
+
const placements = JSON.parse(row.value);
|
|
5654
|
+
if (!Array.isArray(placements)) return null;
|
|
5655
|
+
shipped.set(row.key, placements);
|
|
5394
5656
|
} catch {
|
|
5657
|
+
return null;
|
|
5395
5658
|
}
|
|
5396
5659
|
}
|
|
5397
5660
|
return { components, shipped };
|
|
5398
5661
|
}
|
|
5662
|
+
function blockOf(content, name) {
|
|
5663
|
+
const declaration2 = content.indexOf(`const ${name}`);
|
|
5664
|
+
if (declaration2 < 0) return null;
|
|
5665
|
+
const open = content.indexOf("{", declaration2);
|
|
5666
|
+
if (open < 0) return null;
|
|
5667
|
+
let depth = 0;
|
|
5668
|
+
let at = open;
|
|
5669
|
+
while (at < content.length) {
|
|
5670
|
+
const skip = skipTrivia(content, at);
|
|
5671
|
+
if (skip >= 0) {
|
|
5672
|
+
at = skip;
|
|
5673
|
+
continue;
|
|
5674
|
+
}
|
|
5675
|
+
if (content[at] === "{") depth++;
|
|
5676
|
+
else if (content[at] === "}" && --depth === 0) return content.slice(open + 1, at);
|
|
5677
|
+
at++;
|
|
5678
|
+
}
|
|
5679
|
+
return null;
|
|
5680
|
+
}
|
|
5681
|
+
function skipTrivia(source, at) {
|
|
5682
|
+
const char = source[at];
|
|
5683
|
+
if (char === '"' || char === "'" || char === "`") {
|
|
5684
|
+
let cursor = at + 1;
|
|
5685
|
+
while (cursor < source.length && source[cursor] !== char) cursor += source[cursor] === "\\" ? 2 : 1;
|
|
5686
|
+
return Math.min(cursor + 1, source.length);
|
|
5687
|
+
}
|
|
5688
|
+
if (char === "/" && source[at + 1] === "/") {
|
|
5689
|
+
const line = source.indexOf("\n", at);
|
|
5690
|
+
return line < 0 ? source.length : line;
|
|
5691
|
+
}
|
|
5692
|
+
if (char === "/" && source[at + 1] === "*") {
|
|
5693
|
+
const close = source.indexOf("*/", at + 2);
|
|
5694
|
+
return close < 0 ? source.length : close + 2;
|
|
5695
|
+
}
|
|
5696
|
+
return -1;
|
|
5697
|
+
}
|
|
5698
|
+
function withoutComments(text) {
|
|
5699
|
+
let out = "";
|
|
5700
|
+
let at = 0;
|
|
5701
|
+
while (at < text.length) {
|
|
5702
|
+
const skip = skipTrivia(text, at);
|
|
5703
|
+
if (skip < 0) {
|
|
5704
|
+
out += text[at];
|
|
5705
|
+
at++;
|
|
5706
|
+
continue;
|
|
5707
|
+
}
|
|
5708
|
+
out += text[at] === '"' || text[at] === "'" || text[at] === "`" ? text.slice(at, skip) : "";
|
|
5709
|
+
at = skip;
|
|
5710
|
+
}
|
|
5711
|
+
return out;
|
|
5712
|
+
}
|
|
5713
|
+
function propertiesOf(block) {
|
|
5714
|
+
const out = [];
|
|
5715
|
+
const push = (text) => {
|
|
5716
|
+
const held = text.trim();
|
|
5717
|
+
if (held === "") return true;
|
|
5718
|
+
let depth2 = 0;
|
|
5719
|
+
for (let at = 0; at < held.length; ) {
|
|
5720
|
+
const skip = skipTrivia(held, at);
|
|
5721
|
+
if (skip >= 0) {
|
|
5722
|
+
at = skip;
|
|
5723
|
+
continue;
|
|
5724
|
+
}
|
|
5725
|
+
const char = held[at];
|
|
5726
|
+
if ("{[(".includes(char)) depth2++;
|
|
5727
|
+
else if ("}])".includes(char)) depth2--;
|
|
5728
|
+
else if (char === ":" && depth2 === 0) {
|
|
5729
|
+
const key = withoutComments(held.slice(0, at)).trim().replace(/^["'`]|["'`]$/g, "");
|
|
5730
|
+
const value = withoutComments(held.slice(at + 1)).trim();
|
|
5731
|
+
if (key === "" || value === "") return false;
|
|
5732
|
+
out.push({ key, value });
|
|
5733
|
+
return true;
|
|
5734
|
+
}
|
|
5735
|
+
at++;
|
|
5736
|
+
}
|
|
5737
|
+
return false;
|
|
5738
|
+
};
|
|
5739
|
+
let depth = 0;
|
|
5740
|
+
let start = 0;
|
|
5741
|
+
for (let at = 0; at < block.length; ) {
|
|
5742
|
+
const skip = skipTrivia(block, at);
|
|
5743
|
+
if (skip >= 0) {
|
|
5744
|
+
at = skip;
|
|
5745
|
+
continue;
|
|
5746
|
+
}
|
|
5747
|
+
const char = block[at];
|
|
5748
|
+
if ("{[(".includes(char)) depth++;
|
|
5749
|
+
else if ("}])".includes(char)) depth--;
|
|
5750
|
+
else if (char === "," && depth === 0) {
|
|
5751
|
+
if (!push(block.slice(start, at))) return null;
|
|
5752
|
+
start = at + 1;
|
|
5753
|
+
}
|
|
5754
|
+
at++;
|
|
5755
|
+
}
|
|
5756
|
+
return push(block.slice(start)) ? out : null;
|
|
5757
|
+
}
|
|
5399
5758
|
function snapshotUsable(existing) {
|
|
5400
5759
|
if (existing === void 0) return true;
|
|
5401
5760
|
try {
|
|
@@ -5480,7 +5839,22 @@ function lowestCommonAncestor(elements) {
|
|
|
5480
5839
|
}
|
|
5481
5840
|
return common[common.length - 1] ?? null;
|
|
5482
5841
|
}
|
|
5483
|
-
|
|
5842
|
+
var calledIn = (tree, binding) => [...tree.elements.values()].some(
|
|
5843
|
+
(placed) => binding.kind === "namespace" ? placed.node.tag.startsWith(`${binding.local}.`) : placed.node.tag === binding.local
|
|
5844
|
+
);
|
|
5845
|
+
function namespaceMember(tree, local) {
|
|
5846
|
+
const members = new Set(
|
|
5847
|
+
[...tree.elements.values()].map((placed) => placed.node.tag).filter((tag) => tag.startsWith(`${local}.`)).map((tag) => tag.slice(local.length + 1))
|
|
5848
|
+
);
|
|
5849
|
+
return members.size === 1 ? [...members][0] : void 0;
|
|
5850
|
+
}
|
|
5851
|
+
function callSiteOf(tree, local) {
|
|
5852
|
+
const calls = [...tree.elements.values()].map((placed) => placed.node).filter((node) => node.tag === local);
|
|
5853
|
+
const only = calls.length === 1 ? calls[0] : null;
|
|
5854
|
+
return only !== null && only.attrs.length === 0 ? only : null;
|
|
5855
|
+
}
|
|
5856
|
+
function runOf(placeable, roots, content) {
|
|
5857
|
+
if (placeable.length === 0) return null;
|
|
5484
5858
|
const parents = placeable.map((r) => parentOf(r.root, roots));
|
|
5485
5859
|
if (parents.some((p) => p === void 0)) return null;
|
|
5486
5860
|
const [first, ...rest] = parents;
|
|
@@ -5490,9 +5864,14 @@ function runOf(placeable, roots) {
|
|
|
5490
5864
|
);
|
|
5491
5865
|
const indices = placeable.map((r) => siblings.indexOf(r.root)).sort((a, b) => a - b);
|
|
5492
5866
|
if (indices.some((at) => at < 0)) return null;
|
|
5493
|
-
const
|
|
5494
|
-
|
|
5867
|
+
const consecutive2 = indices.every((at, i) => i === 0 || at === indices[i - 1] + 1);
|
|
5868
|
+
const ordered = [...placeable].sort((a, b) => a.root.start - b.root.start);
|
|
5869
|
+
const clean = ordered.every(
|
|
5870
|
+
(span, at) => at === 0 || isTrivia(content.slice(ordered[at - 1].root.end, span.root.start))
|
|
5871
|
+
);
|
|
5872
|
+
return { contiguous: consecutive2 && clean };
|
|
5495
5873
|
}
|
|
5874
|
+
var isTrivia = (between) => between.replace(/<!--[\s\S]*?-->/g, "").replace(/\{\s*\/\*[\s\S]*?\*\/\s*\}/g, "").trim() === "";
|
|
5496
5875
|
function parentOf(target, roots) {
|
|
5497
5876
|
if (roots.some((node) => node === target)) return null;
|
|
5498
5877
|
const search = (nodes, parent) => {
|
|
@@ -5712,9 +6091,9 @@ function registryFile(dialect, path, written, shipped) {
|
|
|
5712
6091
|
const entries = [...written].sort(([a], [b]) => a.localeCompare(b));
|
|
5713
6092
|
const imports = entries.map(([, component]) => {
|
|
5714
6093
|
const specifier = relativeImport(path, component.path);
|
|
5715
|
-
return
|
|
6094
|
+
return importLine(component.name, dialect === "astro" ? specifier : specifier.replace(/\.tsx?$/, ""), component);
|
|
5716
6095
|
}).join("\n");
|
|
5717
|
-
const registry = entries.map(([slug, component]) => ` ${JSON.stringify(slug)}: ${component
|
|
6096
|
+
const registry = entries.map(([slug, component]) => ` ${JSON.stringify(slug)}: ${registryValue(component)},`).join("\n");
|
|
5718
6097
|
const shippedTable = [...shipped].sort(([a], [b]) => a.localeCompare(b)).map(([page, list]) => ` ${JSON.stringify(page)}: ${JSON.stringify(list)},`).join("\n");
|
|
5719
6098
|
const lib = relativeImport(path, SECTIONS_LIB).replace(/\.tsx?$/, "");
|
|
5720
6099
|
const registryType = dialect === "astro" ? "Record<string, unknown>" : "Record<string, (props: BcmsSectionProps) => JSX.Element | null>";
|
|
@@ -5822,17 +6201,24 @@ function splicePageInline(file, content, dialect, parsed, placeable, pageSlug, w
|
|
|
5822
6201
|
const snapshot = names.get("pageSnapshot");
|
|
5823
6202
|
const source = new MagicString3(content);
|
|
5824
6203
|
for (const resolved of placeable) {
|
|
6204
|
+
const component = written.get(resolved.slug);
|
|
6205
|
+
const tag = component.member ? `${names.get(resolved.slug)}.${component.member}` : names.get(resolved.slug);
|
|
5825
6206
|
source.overwrite(
|
|
5826
6207
|
resolved.root.start,
|
|
5827
6208
|
resolved.root.end,
|
|
5828
|
-
`<${
|
|
6209
|
+
`<${tag} bind=${JSON.stringify(resolved.section.groupKey)} page={${snapshot}(${JSON.stringify(pageSlug)})} />`
|
|
5829
6210
|
);
|
|
5830
6211
|
}
|
|
5831
6212
|
const lib = relativeImport(file, SECTIONS_LIB).replace(/\.tsx?$/, "");
|
|
5832
6213
|
const imports = [
|
|
5833
6214
|
...wanted.map(({ key }) => {
|
|
5834
|
-
const
|
|
5835
|
-
|
|
6215
|
+
const component = written.get(key);
|
|
6216
|
+
const specifier = relativeImport(file, component.path);
|
|
6217
|
+
return importLine(
|
|
6218
|
+
names.get(key),
|
|
6219
|
+
dialect === "astro" ? specifier : specifier.replace(/\.tsx?$/, ""),
|
|
6220
|
+
component
|
|
6221
|
+
);
|
|
5836
6222
|
}),
|
|
5837
6223
|
`import { pageSnapshot${snapshot === "pageSnapshot" ? "" : ` as ${snapshot}`} } from "${lib}";`
|
|
5838
6224
|
];
|
|
@@ -6005,28 +6391,78 @@ async function convertSources(briefIn, sources, options) {
|
|
|
6005
6391
|
);
|
|
6006
6392
|
}
|
|
6007
6393
|
let declaredOnly = 0;
|
|
6394
|
+
const declaredRows = [];
|
|
6395
|
+
const briefRoutes = new Set(brief.pages.map((page) => page.route));
|
|
6396
|
+
const declaredRow = (target, readsFromCms, file) => {
|
|
6397
|
+
declaredRows.push({
|
|
6398
|
+
route: target.route,
|
|
6399
|
+
scope: target.scope,
|
|
6400
|
+
path: target.path,
|
|
6401
|
+
kind: target.kind,
|
|
6402
|
+
...file ? { file } : {},
|
|
6403
|
+
readsFromCms
|
|
6404
|
+
});
|
|
6405
|
+
};
|
|
6008
6406
|
const witnessed = async (target) => {
|
|
6009
6407
|
for (const source of sources) {
|
|
6010
6408
|
const parsed = await parseOf(source.path);
|
|
6011
6409
|
const dialect = dialectOf(source.path, source.content);
|
|
6012
6410
|
if (!parsed || !dialect) continue;
|
|
6013
|
-
if (convertedHere(source.content, parsed, dialect, target, source.path))
|
|
6411
|
+
if (convertedHere(source.content, parsed, dialect, target, source.path) && attributable(target, source.path)) {
|
|
6412
|
+
return source.path;
|
|
6413
|
+
}
|
|
6014
6414
|
}
|
|
6015
|
-
return
|
|
6415
|
+
return null;
|
|
6016
6416
|
};
|
|
6017
6417
|
const locatedByKey = /* @__PURE__ */ new Map();
|
|
6018
6418
|
for (const hit of located) {
|
|
6019
6419
|
const key = keyOf(hit.route, hit.scope ?? "page", hit.path);
|
|
6020
6420
|
if (!locatedByKey.has(key)) locatedByKey.set(key, hit);
|
|
6021
6421
|
}
|
|
6422
|
+
const sharingPath = /* @__PURE__ */ new Map();
|
|
6423
|
+
for (const [key, hit] of locatedByKey) {
|
|
6424
|
+
const held = targets.get(key);
|
|
6425
|
+
if (!held) continue;
|
|
6426
|
+
const id = scopedPath(held.scope, held.path);
|
|
6427
|
+
sharingPath.set(id, [...sharingPath.get(id) ?? [], { key, files: hit.files }]);
|
|
6428
|
+
}
|
|
6429
|
+
const claimedByAnother = (target, file) => (sharingPath.get(scopedPath(target.scope, target.path)) ?? []).some(
|
|
6430
|
+
(other) => other.key !== target.key && other.files.includes(file)
|
|
6431
|
+
);
|
|
6432
|
+
const attributable = (target, file, claimed) => {
|
|
6433
|
+
if (target.scope === "layout") return true;
|
|
6434
|
+
const serves = routeOfFile(file);
|
|
6435
|
+
if (serves !== null && serves !== target.route && briefRoutes.has(serves)) return false;
|
|
6436
|
+
if (serves === target.route && pageFilesFor(target.route, contents.keys()).length !== 1) return false;
|
|
6437
|
+
return claimed !== true;
|
|
6438
|
+
};
|
|
6439
|
+
const declaredByHand = (target, within) => {
|
|
6440
|
+
const candidates = within ?? (target.scope === "layout" ? sources.map((s) => s.path) : pageFilesFor(target.route, contents.keys()));
|
|
6441
|
+
for (const file of candidates) {
|
|
6442
|
+
if (!covers(declarations.get(file), target)) continue;
|
|
6443
|
+
if (attributable(target, file, within !== void 0 && claimedByAnother(target, file))) return file;
|
|
6444
|
+
}
|
|
6445
|
+
return null;
|
|
6446
|
+
};
|
|
6022
6447
|
const missed = /* @__PURE__ */ new Set();
|
|
6023
6448
|
for (const miss of unlocated) {
|
|
6024
6449
|
const key = keyOf(miss.route, miss.scope ?? "page", miss.path);
|
|
6025
6450
|
const target = targets.get(key);
|
|
6026
6451
|
if (!target || locatedByKey.has(key) || missed.has(key)) continue;
|
|
6027
6452
|
missed.add(key);
|
|
6028
|
-
|
|
6029
|
-
|
|
6453
|
+
const witness = await witnessed(target);
|
|
6454
|
+
if (witness !== null) {
|
|
6455
|
+
declaredOnly++;
|
|
6456
|
+
declaredRow(target, true, witness);
|
|
6457
|
+
continue;
|
|
6458
|
+
}
|
|
6459
|
+
const byHand = declaredByHand(target);
|
|
6460
|
+
if (byHand !== null) {
|
|
6461
|
+
declaredOnly++;
|
|
6462
|
+
declaredRow(target, false, byHand);
|
|
6463
|
+
continue;
|
|
6464
|
+
}
|
|
6465
|
+
pend(target, miss.reason === "no-original" ? "NO_ORIGINAL" : "NOT_IN_SOURCE");
|
|
6030
6466
|
}
|
|
6031
6467
|
const byFile = /* @__PURE__ */ new Map();
|
|
6032
6468
|
for (const [key, hit] of locatedByKey) {
|
|
@@ -6084,8 +6520,21 @@ async function convertSources(briefIn, sources, options) {
|
|
|
6084
6520
|
if (worst) {
|
|
6085
6521
|
const file = hit.files[outcomes.indexOf(worst)];
|
|
6086
6522
|
pend(target, worst, file);
|
|
6087
|
-
} else if (outcomes.every((o) => o === "declared"))
|
|
6088
|
-
|
|
6523
|
+
} else if (outcomes.every((o) => o === "declared")) {
|
|
6524
|
+
const witness = await witnessed(target);
|
|
6525
|
+
const byHand = witness === null ? declaredByHand(target, hit.files) : null;
|
|
6526
|
+
if (witness === null && byHand === null) {
|
|
6527
|
+
pend(
|
|
6528
|
+
target,
|
|
6529
|
+
"AMBIGUOUS_LITERAL",
|
|
6530
|
+
hit.files[0],
|
|
6531
|
+
`${hit.files.join(", ")} already declares ${target.path}, and nothing there says it is ${target.route}'s.`
|
|
6532
|
+
);
|
|
6533
|
+
continue;
|
|
6534
|
+
}
|
|
6535
|
+
alreadyDeclared++;
|
|
6536
|
+
declaredRow(target, witness !== null, witness ?? byHand);
|
|
6537
|
+
} else rewritten++;
|
|
6089
6538
|
}
|
|
6090
6539
|
for (const [file, splices] of [...componentEdits].sort(([a], [b]) => a.localeCompare(b))) {
|
|
6091
6540
|
const source = new MagicString4(contents.get(file));
|
|
@@ -6111,12 +6560,27 @@ async function convertSources(briefIn, sources, options) {
|
|
|
6111
6560
|
emitStubs2(dialects, snapshotSlugs, contents, outFiles);
|
|
6112
6561
|
const receipt = assertReceipt({
|
|
6113
6562
|
briefDigest: digest,
|
|
6114
|
-
paths: {
|
|
6563
|
+
paths: {
|
|
6564
|
+
declared: targets.size,
|
|
6565
|
+
rewritten,
|
|
6566
|
+
alreadyDeclared,
|
|
6567
|
+
declarations: declaredRows.sort(
|
|
6568
|
+
(a, b) => a.route.localeCompare(b.route) || a.scope.localeCompare(b.scope) || a.path.localeCompare(b.path)
|
|
6569
|
+
),
|
|
6570
|
+
pending
|
|
6571
|
+
},
|
|
6115
6572
|
occurrences: { located: occurrencesLocated, rewritten: occurrencesRewritten },
|
|
6116
6573
|
files: receiptFiles,
|
|
6117
6574
|
helpers,
|
|
6118
6575
|
helperUpgraded,
|
|
6119
|
-
dynamicBindings
|
|
6576
|
+
dynamicBindings,
|
|
6577
|
+
notes: unreadableConfigs(sources).map(
|
|
6578
|
+
(file) => ({
|
|
6579
|
+
code: "TSCONFIG_UNREADABLE",
|
|
6580
|
+
file,
|
|
6581
|
+
message: `${file} is not JSON this package can read, so its \`paths\` aliases resolved to nothing.`
|
|
6582
|
+
})
|
|
6583
|
+
)
|
|
6120
6584
|
});
|
|
6121
6585
|
return { files: outFiles.sort((a, b) => a.path.localeCompare(b.path)), receipt };
|
|
6122
6586
|
}
|
|
@@ -6384,14 +6848,12 @@ async function plan(file, content, dialect, targets, sites, importAt, outcomes,
|
|
|
6384
6848
|
looped.add(member.key);
|
|
6385
6849
|
outcomes.set(member.key, "rewritten");
|
|
6386
6850
|
}
|
|
6387
|
-
for (const
|
|
6851
|
+
for (const declaration2 of plan2.declarations) {
|
|
6388
6852
|
dynamic.push({
|
|
6389
6853
|
file,
|
|
6390
6854
|
prop: null,
|
|
6391
|
-
path:
|
|
6392
|
-
|
|
6393
|
-
// described a binding the file does not contain, which is what the proposer looks for.
|
|
6394
|
-
callSites: [{ file, literal: `${arrayPath}[\${${plan2.names.index}}].${leaf}` }]
|
|
6855
|
+
path: declaration2.path,
|
|
6856
|
+
callSites: [{ file, literal: declaration2.literal }]
|
|
6395
6857
|
});
|
|
6396
6858
|
}
|
|
6397
6859
|
rewrites.push({
|
|
@@ -6748,14 +7210,14 @@ ${rewritten} of ${declared} paths bound (${alreadyDeclared} already declared, ${
|
|
|
6748
7210
|
}
|
|
6749
7211
|
}
|
|
6750
7212
|
function reportSections(files, receipt, dryRun) {
|
|
6751
|
-
const { extracted, inlineOnly, alreadyExtracted, pending } = receipt.sections;
|
|
7213
|
+
const { extracted, inlineOnly, alreadyExtracted, registered, pending } = receipt.sections;
|
|
6752
7214
|
for (const file of files) {
|
|
6753
7215
|
process.stdout.write(`${dryRun ? "would " : ""}${file.operation} ${file.path}
|
|
6754
7216
|
`);
|
|
6755
7217
|
}
|
|
6756
7218
|
process.stdout.write(
|
|
6757
7219
|
`
|
|
6758
|
-
${extracted} sections extracted (${inlineOnly} inline-only, ${alreadyExtracted} already extracted, ${pending.length} pending)
|
|
7220
|
+
${extracted} sections extracted (${registered} registered, ${inlineOnly} inline-only, ${alreadyExtracted} already extracted, ${pending.length} pending)
|
|
6759
7221
|
`
|
|
6760
7222
|
);
|
|
6761
7223
|
for (const section of pending) {
|