@bettercms-ai/convert 0.24.0 → 0.25.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 +16 -0
- package/dist/cli.js +89 -12
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +32 -2
- package/dist/index.js +64 -5
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# @bettercms-ai/convert
|
|
2
2
|
|
|
3
|
+
## 0.25.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 832e08a: A converted repository whose `build` runs checks before the build (`astro check && astro build`, `tsc --noEmit && vite build`, `npm run lint && next build`) gets a `build:bcms` script beside it with the same build minus those checks, `prebuild`/`postbuild` folded in. BetterCMS builds with `build:bcms` when a project declares one, so a deploy no longer pays for the project's CI checks; `build` is left unchanged. Every writing run adds it once (a repository that already has one is never touched), and only for a plain `&&` chain. Exported as `bcmsBuildScript`.
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- c6fd790: The codemod never walks into a directory holding its own `.git` (a git worktree, submodule or vendored clone), so a tool's worktree copy of the repo is no longer converted alongside the real source.
|
|
12
|
+
|
|
13
|
+
## 0.24.1
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- 15e446a: Helper v13: a repository image path (`@/images/blog/post-1.avif`, `~/…`, `../…`, `/src/…`) is never rendered as a value; the template's own imported picture shows instead. Converted sites get it on their next BetterCMS build through the helper upgrade.
|
|
18
|
+
|
|
3
19
|
## 0.24.0
|
|
4
20
|
|
|
5
21
|
### Minor Changes
|
package/dist/cli.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
// src/cli.ts
|
|
4
4
|
import { execFileSync } from "child_process";
|
|
5
|
+
import { existsSync } from "fs";
|
|
5
6
|
import { readdir, readFile, writeFile, mkdir, stat } from "fs/promises";
|
|
6
7
|
import { dirname, join as join2, relative, resolve, sep } from "path";
|
|
7
8
|
|
|
@@ -4190,7 +4191,7 @@ async function bindImages(ctx, targets) {
|
|
|
4190
4191
|
|
|
4191
4192
|
// src/helper.ts
|
|
4192
4193
|
import { createHash as createHash2 } from "crypto";
|
|
4193
|
-
var HELPER_VERSION =
|
|
4194
|
+
var HELPER_VERSION = 13;
|
|
4194
4195
|
var HEADER = "// @bettercms-ai/convert helper v";
|
|
4195
4196
|
var HELPER_PATH = Object.fromEntries(
|
|
4196
4197
|
Object.keys(DIALECT_RULES).map((d) => [d, DIALECT_RULES[d].helper])
|
|
@@ -4236,9 +4237,16 @@ function readPath(root: unknown, path: string): unknown {
|
|
|
4236
4237
|
return cursor;
|
|
4237
4238
|
}
|
|
4238
4239
|
|
|
4240
|
+
/**
|
|
4241
|
+
* A repository image path \u2014 \`@/images/x.avif\`, \`~/assets/x.png\`, \`../assets/x.jpg\`, \`/src/x.png\`.
|
|
4242
|
+
* The bundler resolves one at build and nothing else can, so as a value it is never rendered: the
|
|
4243
|
+
* template's own fallback (the picture the build already imported) shows instead of a broken image.
|
|
4244
|
+
*/
|
|
4245
|
+
const REPO_IMAGE_PATH = /^(?:@[\\w-]*|~|\\.{1,2}|\\/?src)\\/[^\\s?#"'<>]*\\.(?:avif|png|jpe?g|webp|gif|svg|bmp|ico|tiff?|jxl|heic)(?:[?#]\\S*)?$/i;
|
|
4246
|
+
|
|
4239
4247
|
/** A stored value as a template renders it: richtext is its html, an image is its url. */
|
|
4240
4248
|
function render(value: unknown): string | undefined {
|
|
4241
|
-
if (typeof value === "string") return value;
|
|
4249
|
+
if (typeof value === "string") return REPO_IMAGE_PATH.test(value.trim()) ? undefined : value;
|
|
4242
4250
|
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
4243
4251
|
if (isRecord(value)) {
|
|
4244
4252
|
if (typeof value.html === "string") return value.html;
|
|
@@ -4732,7 +4740,8 @@ var HISTORICAL = {
|
|
|
4732
4740
|
8: "484e72852d2b496e016a1f2a2b1a77bb993f8a163b290781522d6114b6519bb9",
|
|
4733
4741
|
9: "d6441db2ff4578c3c5d4b7d461f3374b89247ef6ba9e0d535791e840d803e4f3",
|
|
4734
4742
|
10: "ffcb59862972b15a67c5951e9f3b94ce5b8b50345e6aac2bfa5789cfc3136910",
|
|
4735
|
-
11: "ceb2a932d4c2761a5045ff35032e0b45130a0b5034547ff37579c72c9ce3594e"
|
|
4743
|
+
11: "ceb2a932d4c2761a5045ff35032e0b45130a0b5034547ff37579c72c9ce3594e",
|
|
4744
|
+
12: "10f71724484c84af12aa3eb90db44bf6acbf71fcf8ddff5b6361c1190ba16528"
|
|
4736
4745
|
},
|
|
4737
4746
|
"src/lib/bcms-content.ts": {
|
|
4738
4747
|
1: "ae72ae14d706943d481c880d70da5789b4816ba1ba319a10fbc63ded4d0b42f2",
|
|
@@ -4745,7 +4754,8 @@ var HISTORICAL = {
|
|
|
4745
4754
|
8: "1a6f669d76d42effe77f082436e9d21c0efa6fc499e919e3d116bc3a27a7f3d5",
|
|
4746
4755
|
9: "eee9fb1635ae7d6f8f33676a1f390600ca24a62ee992775252273c73a011c494",
|
|
4747
4756
|
10: "35bb7c0e30f5c41fe68e52259ec4764de6de2734064fa0e1521f3338eef0a09e",
|
|
4748
|
-
11: "818784f2088150d64d91b42eac944dc9503f104d32a0e7a18c753d2982a5adc0"
|
|
4757
|
+
11: "818784f2088150d64d91b42eac944dc9503f104d32a0e7a18c753d2982a5adc0",
|
|
4758
|
+
12: "79dafc525a541feae55ada5dbe2ea966cac82acd741a4b41d61fe9e0cdfaa208"
|
|
4749
4759
|
},
|
|
4750
4760
|
"composables/bcms-content.ts": {
|
|
4751
4761
|
1: "c272412532efed7db64b6cf313b2bed4291f9951430412289c8a588b7f565407",
|
|
@@ -4758,7 +4768,8 @@ var HISTORICAL = {
|
|
|
4758
4768
|
8: "484e72852d2b496e016a1f2a2b1a77bb993f8a163b290781522d6114b6519bb9",
|
|
4759
4769
|
9: "d6441db2ff4578c3c5d4b7d461f3374b89247ef6ba9e0d535791e840d803e4f3",
|
|
4760
4770
|
10: "ffcb59862972b15a67c5951e9f3b94ce5b8b50345e6aac2bfa5789cfc3136910",
|
|
4761
|
-
11: "ceb2a932d4c2761a5045ff35032e0b45130a0b5034547ff37579c72c9ce3594e"
|
|
4771
|
+
11: "ceb2a932d4c2761a5045ff35032e0b45130a0b5034547ff37579c72c9ce3594e",
|
|
4772
|
+
12: "10f71724484c84af12aa3eb90db44bf6acbf71fcf8ddff5b6361c1190ba16528"
|
|
4762
4773
|
}
|
|
4763
4774
|
};
|
|
4764
4775
|
var sha256 = (value) => createHash2("sha256").update(value, "utf8").digest("hex");
|
|
@@ -7654,6 +7665,54 @@ function moduleScope(parsed, content) {
|
|
|
7654
7665
|
return out;
|
|
7655
7666
|
}
|
|
7656
7667
|
|
|
7668
|
+
// src/build-script.ts
|
|
7669
|
+
var CHECK = /^(?:npx\s+|pnpm\s+(?:exec\s+)?|yarn\s+|bunx\s+)?(?:astro\s+check|svelte-check|vue-tsc|tsc(?:\s|$)|eslint|next\s+lint|biome\s+(?:check|lint|ci)|prettier\s+(?:--check|-c)\b|stylelint|oxlint)/;
|
|
7670
|
+
var RUN_CHECK = /^(?:npm\s+run|pnpm(?:\s+run)?|yarn(?:\s+run)?|bun\s+run)\s+(?:lint|typecheck|type-check|check|check:types|types|format:check|test)(?::[\w-]+)?\s*$/;
|
|
7671
|
+
var UNSAFE = /;|\|\||\||(?:^|[^&])&(?:[^&]|$)|\$\(|`|\n/;
|
|
7672
|
+
var isCheck = (step) => CHECK.test(step) || RUN_CHECK.test(step);
|
|
7673
|
+
function steps(script) {
|
|
7674
|
+
if (UNSAFE.test(script)) return null;
|
|
7675
|
+
const out = script.split("&&").map((s) => s.trim());
|
|
7676
|
+
return out.some((s) => s === "") ? null : out;
|
|
7677
|
+
}
|
|
7678
|
+
function bcmsBuildScript(packageJson) {
|
|
7679
|
+
let pkg;
|
|
7680
|
+
try {
|
|
7681
|
+
pkg = JSON.parse(packageJson);
|
|
7682
|
+
} catch {
|
|
7683
|
+
return null;
|
|
7684
|
+
}
|
|
7685
|
+
const scripts = pkg?.scripts;
|
|
7686
|
+
if (!scripts || typeof scripts !== "object" || "build:bcms" in scripts) return null;
|
|
7687
|
+
const build = scripts.build;
|
|
7688
|
+
if (typeof build !== "string") return null;
|
|
7689
|
+
const parts = [];
|
|
7690
|
+
for (const name of ["prebuild", "build", "postbuild"]) {
|
|
7691
|
+
const value = scripts[name];
|
|
7692
|
+
if (value === void 0) continue;
|
|
7693
|
+
if (typeof value !== "string") return null;
|
|
7694
|
+
const s = steps(value);
|
|
7695
|
+
if (!s) return null;
|
|
7696
|
+
parts.push(s);
|
|
7697
|
+
}
|
|
7698
|
+
const all = parts.flat();
|
|
7699
|
+
const dropped = all.filter(isCheck);
|
|
7700
|
+
const kept = all.filter((s) => !isCheck(s));
|
|
7701
|
+
if (dropped.length === 0 || kept.length === 0) return null;
|
|
7702
|
+
const script = kept.join(" && ");
|
|
7703
|
+
const next = {};
|
|
7704
|
+
for (const [key, value] of Object.entries(scripts)) {
|
|
7705
|
+
next[key] = value;
|
|
7706
|
+
if (key === "build") next["build:bcms"] = script;
|
|
7707
|
+
}
|
|
7708
|
+
const indent = /^[ \t]+(?=")/m.exec(packageJson)?.[0] ?? " ";
|
|
7709
|
+
const eol = packageJson.includes("\r\n") ? "\r\n" : "\n";
|
|
7710
|
+
let content = JSON.stringify({ ...pkg, scripts: next }, null, indent);
|
|
7711
|
+
if (eol !== "\n") content = content.replace(/\n/g, eol);
|
|
7712
|
+
if (/\r?\n$/.test(packageJson)) content += eol;
|
|
7713
|
+
return { content, script, dropped };
|
|
7714
|
+
}
|
|
7715
|
+
|
|
7657
7716
|
// src/componentize.ts
|
|
7658
7717
|
import MagicString5 from "magic-string";
|
|
7659
7718
|
var SectionInvariantError = class extends Error {
|
|
@@ -10774,7 +10833,7 @@ function styleEdits(before, after) {
|
|
|
10774
10833
|
// package.json
|
|
10775
10834
|
var package_default = {
|
|
10776
10835
|
name: "@bettercms-ai/convert",
|
|
10777
|
-
version: "0.
|
|
10836
|
+
version: "0.25.0",
|
|
10778
10837
|
type: "module",
|
|
10779
10838
|
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.",
|
|
10780
10839
|
bin: {
|
|
@@ -10951,7 +11010,7 @@ async function readTree(root, verbose) {
|
|
|
10951
11010
|
const full = join2(dir, entry.name);
|
|
10952
11011
|
const rel = relative(root, full).split(sep).join("/");
|
|
10953
11012
|
if (entry.isDirectory()) {
|
|
10954
|
-
if (isSourceCandidate(`${rel}/x.html`)) await walk(full);
|
|
11013
|
+
if (isSourceCandidate(`${rel}/x.html`) && !existsSync(join2(full, ".git"))) await walk(full);
|
|
10955
11014
|
continue;
|
|
10956
11015
|
}
|
|
10957
11016
|
if (!entry.isFile() || !isSourceCandidate(rel)) continue;
|
|
@@ -11132,6 +11191,21 @@ async function verifyStyles(root, base, verbose) {
|
|
|
11132
11191
|
);
|
|
11133
11192
|
return 1;
|
|
11134
11193
|
}
|
|
11194
|
+
async function addBcmsBuild(root, dryRun) {
|
|
11195
|
+
let packageJson;
|
|
11196
|
+
try {
|
|
11197
|
+
packageJson = await readFile(join2(root, "package.json"), "utf-8");
|
|
11198
|
+
} catch {
|
|
11199
|
+
return;
|
|
11200
|
+
}
|
|
11201
|
+
const added = bcmsBuildScript(packageJson);
|
|
11202
|
+
if (!added) return;
|
|
11203
|
+
if (!dryRun) await writeFile(join2(root, "package.json"), added.content, "utf-8");
|
|
11204
|
+
process.stderr.write(
|
|
11205
|
+
`package.json: ${dryRun ? "would add" : "added"} "build:bcms": "${added.script}" \u2014 BetterCMS builds with it, without ${added.dropped.join(", ")}; "build" is unchanged.
|
|
11206
|
+
`
|
|
11207
|
+
);
|
|
11208
|
+
}
|
|
11135
11209
|
async function main() {
|
|
11136
11210
|
const args = parseArgs(process.argv.slice(2));
|
|
11137
11211
|
if (args.help) {
|
|
@@ -11163,6 +11237,7 @@ async function main() {
|
|
|
11163
11237
|
await writeFile(target, file.content, "utf-8");
|
|
11164
11238
|
}
|
|
11165
11239
|
}
|
|
11240
|
+
await addBcmsBuild(root2, args.dryRun);
|
|
11166
11241
|
if (args.receipt) await writeFile(resolve(args.receipt), `${JSON.stringify(receipt2, null, 2)}
|
|
11167
11242
|
`, "utf-8");
|
|
11168
11243
|
reportUpgrade(files2, receipt2, args.dryRun);
|
|
@@ -11190,12 +11265,14 @@ async function main() {
|
|
|
11190
11265
|
if (args.verbose) process.stderr.write(`read ${sources.length} candidate files under ${root}
|
|
11191
11266
|
`);
|
|
11192
11267
|
const written = async (files2) => {
|
|
11193
|
-
if (args.dryRun)
|
|
11194
|
-
|
|
11195
|
-
|
|
11196
|
-
|
|
11197
|
-
|
|
11268
|
+
if (!args.dryRun) {
|
|
11269
|
+
for (const file of files2) {
|
|
11270
|
+
const target = under(root, file.path);
|
|
11271
|
+
await mkdir(dirname(target), { recursive: true });
|
|
11272
|
+
await writeFile(target, file.content, "utf-8");
|
|
11273
|
+
}
|
|
11198
11274
|
}
|
|
11275
|
+
await addBcmsBuild(root, args.dryRun);
|
|
11199
11276
|
};
|
|
11200
11277
|
const saveReceipt = async (receipt2) => {
|
|
11201
11278
|
if (!args.receipt) return;
|