@bettercms-ai/convert 0.14.0 → 0.15.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 +6 -0
- package/dist/cli.js +55 -4
- package/dist/cli.js.map +1 -1
- package/dist/index.js +54 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# @bettercms-ai/convert
|
|
2
2
|
|
|
3
|
+
## 0.15.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 0ddfbdd: `--forms` now sees a form built from components. A component tag handed a `name` or `id` (`<TextInput name="firstName" />`) is the control; a tag handed neither (`<EmailFooterInput />`) is matched by the controls in its own imported file, which are never written. Before, such a form was reported `FORM_NOT_IN_SOURCE` although its fields were all there. A component's file is found by RESOLVING its import — a relative path, or one of the project's own tsconfig `paths` aliases — so a bare package specifier reads no local file that merely shares its last segment, and the receipt notes any field whose marker went unwritten because its control lives in an imported component.
|
|
8
|
+
|
|
3
9
|
## 0.14.0
|
|
4
10
|
|
|
5
11
|
### Minor Changes
|
package/dist/cli.js
CHANGED
|
@@ -6391,9 +6391,11 @@ function* elementsIn(nodes) {
|
|
|
6391
6391
|
var childElements = (node) => node.children.flatMap(
|
|
6392
6392
|
(child) => child.type === "element" ? [child] : child.type === "expr" ? childElements(child) : []
|
|
6393
6393
|
);
|
|
6394
|
-
|
|
6394
|
+
var isComponentTag = (dialect, tag) => dialect !== "html" && /^[A-Z]/.test(tag);
|
|
6395
|
+
function candidateOf(file, dialect, form, imported) {
|
|
6395
6396
|
const controls = /* @__PURE__ */ new Map();
|
|
6396
6397
|
const wrapper = /* @__PURE__ */ new Map();
|
|
6398
|
+
const foreign = /* @__PURE__ */ new Set();
|
|
6397
6399
|
const all = [];
|
|
6398
6400
|
const walk = (parent) => {
|
|
6399
6401
|
const own = [];
|
|
@@ -6401,6 +6403,17 @@ function candidateOf(file, dialect, form) {
|
|
|
6401
6403
|
if (CONTROLS.has(child.tag.toLowerCase())) {
|
|
6402
6404
|
own.push(child);
|
|
6403
6405
|
all.push(child);
|
|
6406
|
+
} else if (isComponentTag(dialect, child.tag)) {
|
|
6407
|
+
const inFile = attrOf(child, "name") ? [] : imported.get(child.tag) ?? [];
|
|
6408
|
+
if (inFile.length) {
|
|
6409
|
+
for (const control of inFile) {
|
|
6410
|
+
all.push(control);
|
|
6411
|
+
foreign.add(control);
|
|
6412
|
+
}
|
|
6413
|
+
} else if (attrOf(child, "name") ?? attrOf(child, "id")) {
|
|
6414
|
+
own.push(child);
|
|
6415
|
+
all.push(child);
|
|
6416
|
+
}
|
|
6404
6417
|
}
|
|
6405
6418
|
walk(child);
|
|
6406
6419
|
}
|
|
@@ -6412,10 +6425,32 @@ function candidateOf(file, dialect, form) {
|
|
|
6412
6425
|
if (name && !controls.has(name)) controls.set(name, control);
|
|
6413
6426
|
}
|
|
6414
6427
|
for (const control of all) {
|
|
6428
|
+
if (foreign.has(control)) continue;
|
|
6415
6429
|
const id = attrOf(control, "id")?.value;
|
|
6416
6430
|
if (id && !controls.has(id)) controls.set(id, control);
|
|
6417
6431
|
}
|
|
6418
|
-
return { file, dialect, el: form, controls, wrapper };
|
|
6432
|
+
return { file, dialect, el: form, controls, wrapper, foreign };
|
|
6433
|
+
}
|
|
6434
|
+
async function importedControls(source, parsed, dialect, project, cache) {
|
|
6435
|
+
const out = /* @__PURE__ */ new Map();
|
|
6436
|
+
for (const [local, { specifier }] of importsIn(parsed, dialect)) {
|
|
6437
|
+
const path = resolveSpecifier(source.path, specifier, project.files, project.aliases);
|
|
6438
|
+
const child = path === null || path === source.path ? void 0 : project.byPath.get(path);
|
|
6439
|
+
if (!child) continue;
|
|
6440
|
+
let controls = cache.get(child.path);
|
|
6441
|
+
if (!controls) {
|
|
6442
|
+
controls = (async () => {
|
|
6443
|
+
const own = dialectOf(child.path, child.content);
|
|
6444
|
+
if (!own || !WIRABLE.includes(own)) return [];
|
|
6445
|
+
const file = await parseFile4(own, child.content);
|
|
6446
|
+
return file.error ? [] : [...elementsIn(file.roots)].filter((el) => CONTROLS.has(el.tag.toLowerCase()));
|
|
6447
|
+
})();
|
|
6448
|
+
cache.set(child.path, controls);
|
|
6449
|
+
}
|
|
6450
|
+
const found = await controls;
|
|
6451
|
+
if (found.length) out.set(local, found);
|
|
6452
|
+
}
|
|
6453
|
+
return out;
|
|
6419
6454
|
}
|
|
6420
6455
|
var hasMessage = (form) => [...elementsIn([form])].some((el) => (attrOf(el, "class") ?? attrOf(el, "classname"))?.value.includes("bcms-form-msg") ?? false);
|
|
6421
6456
|
function wire(source, candidate, form) {
|
|
@@ -6434,6 +6469,7 @@ function wire(source, candidate, form) {
|
|
|
6434
6469
|
source.appendLeft(el.attrInsertAt, ` ${inserts.join(" ")}`);
|
|
6435
6470
|
for (const field of form.fields) {
|
|
6436
6471
|
const control = candidate.controls.get(field.key);
|
|
6472
|
+
if (candidate.foreign.has(control)) continue;
|
|
6437
6473
|
const host = candidate.wrapper.get(control) ?? control;
|
|
6438
6474
|
source.appendLeft(host.attrInsertAt, ` data-bcms-form-field="${escapeAttr(field.key)}"`);
|
|
6439
6475
|
const name = attrOf(control, "name");
|
|
@@ -6452,6 +6488,12 @@ async function wireForms(briefIn, sources) {
|
|
|
6452
6488
|
const forms = brief.forms ?? [];
|
|
6453
6489
|
const candidates = [];
|
|
6454
6490
|
const unreadable = [];
|
|
6491
|
+
const componentFiles = /* @__PURE__ */ new Map();
|
|
6492
|
+
const project = {
|
|
6493
|
+
byPath: new Map(sources.map((s) => [s.path, s])),
|
|
6494
|
+
files: new Set(sources.map((s) => s.path)),
|
|
6495
|
+
aliases: aliasesFrom(sources)
|
|
6496
|
+
};
|
|
6455
6497
|
for (const source of sources) {
|
|
6456
6498
|
if (!/<form[\s/>]/i.test(source.content)) continue;
|
|
6457
6499
|
const dialect = dialectOf(source.path, source.content);
|
|
@@ -6472,8 +6514,9 @@ async function wireForms(briefIn, sources) {
|
|
|
6472
6514
|
});
|
|
6473
6515
|
continue;
|
|
6474
6516
|
}
|
|
6517
|
+
const imported = dialect === "html" ? /* @__PURE__ */ new Map() : await importedControls(source, parsed, dialect, project, componentFiles);
|
|
6475
6518
|
for (const el of elementsIn(parsed.roots)) {
|
|
6476
|
-
if (el.tag.toLowerCase() === "form") candidates.push(candidateOf(source.path, dialect, el));
|
|
6519
|
+
if (el.tag.toLowerCase() === "form") candidates.push(candidateOf(source.path, dialect, el, imported));
|
|
6477
6520
|
}
|
|
6478
6521
|
}
|
|
6479
6522
|
const holds = (c, f) => f.fields.filter((field) => c.controls.has(field.key)).length;
|
|
@@ -6546,6 +6589,14 @@ ${indent}${scriptFor(last.candidate.dialect)}`);
|
|
|
6546
6589
|
files.push({ path, operation: "modify", content: source.toString() });
|
|
6547
6590
|
}
|
|
6548
6591
|
const notes = onSite.filter(({ form }) => form.status === "draft").map(({ form }) => `publish form ${form.name} in the Forms tab \u2014 a draft form rejects every submission with 403.`);
|
|
6592
|
+
for (const { form, candidate } of matched) {
|
|
6593
|
+
const keys = form.fields.filter((field) => candidate.foreign.has(candidate.controls.get(field.key))).map((field) => field.key);
|
|
6594
|
+
if (keys.length > 0) {
|
|
6595
|
+
notes.push(
|
|
6596
|
+
`form ${form.name}: ${keys.join(", ")} matched a control inside an imported component, so no data-bcms-form-field marker was written for ${keys.length === 1 ? "it" : "them"}.`
|
|
6597
|
+
);
|
|
6598
|
+
}
|
|
6599
|
+
}
|
|
6549
6600
|
return {
|
|
6550
6601
|
files,
|
|
6551
6602
|
receipt: {
|
|
@@ -9638,7 +9689,7 @@ function emitStubs2(dialects, slugs, contents, out) {
|
|
|
9638
9689
|
// package.json
|
|
9639
9690
|
var package_default = {
|
|
9640
9691
|
name: "@bettercms-ai/convert",
|
|
9641
|
-
version: "0.
|
|
9692
|
+
version: "0.15.0",
|
|
9642
9693
|
type: "module",
|
|
9643
9694
|
description: "Deterministic codemod that turns an imported site's text-matched bindings into declared ones \u2014 parser offsets in, one magic-string pass out, plus a receipt of everything it could not do.",
|
|
9644
9695
|
bin: {
|