create-zfb 0.1.0-next.6 → 0.1.0-next.61
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/README.md +2 -0
- package/bin/create-zfb.mjs +99 -0
- package/package.json +5 -2
package/README.md
CHANGED
|
@@ -11,3 +11,5 @@ npm create zfb@latest my-site
|
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
This creates a new project directory `my-site/` bootstrapped from the built-in `basic-blog` template. For full documentation, configuration options, and CLI reference, see the [`@takazudo/zfb` docs](https://takazudomodular.com/pj/zudo-front-builder/).
|
|
14
|
+
|
|
15
|
+
> **pnpm 11 note:** pnpm 11's `minimumReleaseAge` may install a previous release of `create-zfb` within ~48h of any new release. If `create-zfb` warns about a stale install at startup, re-run with `pnpm create zfb@latest --config.minimumReleaseAge=0` or `npm create zfb@latest`.
|
package/bin/create-zfb.mjs
CHANGED
|
@@ -1,13 +1,112 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { spawnSync } from "node:child_process";
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
|
+
import { constants as osConstants } from "node:os";
|
|
4
5
|
import { dirname, join } from "node:path";
|
|
5
6
|
|
|
6
7
|
const require = createRequire(import.meta.url);
|
|
7
8
|
|
|
9
|
+
// Returns -1 if a < b, 0 if a === b, 1 if a > b.
|
|
10
|
+
// Handles prerelease suffixes: 0.1.0-next.6 < 0.1.0-next.8 < 0.1.0
|
|
11
|
+
function compareSemver(a, b) {
|
|
12
|
+
const splitRelease = (v) => {
|
|
13
|
+
// Drop SemVer build metadata (`+...`) before splitting — it is ignored
|
|
14
|
+
// for precedence and would otherwise yield NaN numeric parts.
|
|
15
|
+
const [main, pre] = v.split("+")[0].split(/-(.+)/, 2);
|
|
16
|
+
return { parts: main.split(".").map(Number), pre: pre ?? null };
|
|
17
|
+
};
|
|
18
|
+
const ra = splitRelease(a);
|
|
19
|
+
const rb = splitRelease(b);
|
|
20
|
+
for (let i = 0; i < Math.max(ra.parts.length, rb.parts.length); i++) {
|
|
21
|
+
const pa = ra.parts[i] ?? 0;
|
|
22
|
+
const pb = rb.parts[i] ?? 0;
|
|
23
|
+
if (pa !== pb) return pa < pb ? -1 : 1;
|
|
24
|
+
}
|
|
25
|
+
// same numeric parts — prerelease is less than no prerelease (semver rule)
|
|
26
|
+
if (ra.pre !== null && rb.pre === null) return -1;
|
|
27
|
+
if (ra.pre === null && rb.pre !== null) return 1;
|
|
28
|
+
if (ra.pre !== null && rb.pre !== null) {
|
|
29
|
+
// Compare dot-separated prerelease identifiers per semver: numeric
|
|
30
|
+
// identifiers compare numerically (so next.9 < next.10), numeric ranks
|
|
31
|
+
// below alphanumeric, and a shorter prefix ranks lower. Plain string
|
|
32
|
+
// `<`/`>` would order next.10 before next.9 lexicographically.
|
|
33
|
+
const sa = ra.pre.split(".");
|
|
34
|
+
const sb = rb.pre.split(".");
|
|
35
|
+
for (let i = 0; i < Math.max(sa.length, sb.length); i++) {
|
|
36
|
+
if (sa[i] === undefined) return -1;
|
|
37
|
+
if (sb[i] === undefined) return 1;
|
|
38
|
+
const na = /^\d+$/.test(sa[i]);
|
|
39
|
+
const nb = /^\d+$/.test(sb[i]);
|
|
40
|
+
if (na && nb) {
|
|
41
|
+
const da = Number(sa[i]);
|
|
42
|
+
const db = Number(sb[i]);
|
|
43
|
+
if (da !== db) return da < db ? -1 : 1;
|
|
44
|
+
} else if (na !== nb) {
|
|
45
|
+
return na ? -1 : 1;
|
|
46
|
+
} else if (sa[i] !== sb[i]) {
|
|
47
|
+
return sa[i] < sb[i] ? -1 : 1;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return 0;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
try {
|
|
55
|
+
const ownPkg = require("../package.json");
|
|
56
|
+
const version = ownPkg.version;
|
|
57
|
+
const controller = new AbortController();
|
|
58
|
+
const timer = setTimeout(() => controller.abort(), 1500);
|
|
59
|
+
let res;
|
|
60
|
+
try {
|
|
61
|
+
res = await fetch("https://registry.npmjs.org/create-zfb/latest", {
|
|
62
|
+
signal: controller.signal,
|
|
63
|
+
headers: {
|
|
64
|
+
"User-Agent": `create-zfb/${version}`,
|
|
65
|
+
Accept: "application/json",
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
if (res.ok) {
|
|
69
|
+
const data = await res.json();
|
|
70
|
+
const latest = data?.version;
|
|
71
|
+
if (typeof latest === "string" && typeof version === "string") {
|
|
72
|
+
if (compareSemver(version, latest) < 0) {
|
|
73
|
+
process.stderr.write(
|
|
74
|
+
`[create-zfb] You are running create-zfb@${version} but @latest is ${latest}.\n` +
|
|
75
|
+
`[create-zfb] pnpm 11's minimumReleaseAge may have downgraded the install.\n` +
|
|
76
|
+
`[create-zfb] Re-run with: pnpm create zfb@latest --config.minimumReleaseAge=0\n` +
|
|
77
|
+
`[create-zfb] Or use: npm create zfb@latest\n`,
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
} finally {
|
|
83
|
+
// Keep the abort signal armed across both the header and body reads.
|
|
84
|
+
// Only cancel the timer once the body has been fully consumed (or on
|
|
85
|
+
// any error path), so a proxy that stalls after headers cannot hang
|
|
86
|
+
// the scaffolder indefinitely.
|
|
87
|
+
clearTimeout(timer);
|
|
88
|
+
}
|
|
89
|
+
} catch {
|
|
90
|
+
// silently skip on any error: network failure, timeout (AbortError), parse error, etc.
|
|
91
|
+
}
|
|
92
|
+
|
|
8
93
|
const zfbPkgJson = require.resolve("@takazudo/zfb/package.json");
|
|
9
94
|
const zfbBin = join(dirname(zfbPkgJson), "bin", "zfb.mjs");
|
|
10
95
|
|
|
11
96
|
const args = ["new", ...process.argv.slice(2)];
|
|
12
97
|
const result = spawnSync(process.execPath, [zfbBin, ...args], { stdio: "inherit" });
|
|
98
|
+
if (result.signal) {
|
|
99
|
+
// Re-raise the child's termination signal on ourselves so the caller sees
|
|
100
|
+
// the real cause of death (e.g. WIFSIGNALED), not a plain exit code 1.
|
|
101
|
+
// Mirrors the wrapper behaviour in packages/zfb/bin/zfb.mjs.
|
|
102
|
+
try {
|
|
103
|
+
process.kill(process.pid, result.signal);
|
|
104
|
+
} catch {
|
|
105
|
+
// Signal cannot be re-raised on this platform (Windows emulation).
|
|
106
|
+
}
|
|
107
|
+
// Reached only if the re-raised signal did not terminate us — fall back
|
|
108
|
+
// to the shell's 128+n convention for death-by-signal.
|
|
109
|
+
const signum = osConstants.signals[result.signal];
|
|
110
|
+
process.exit(signum ? 128 + signum : 1);
|
|
111
|
+
}
|
|
13
112
|
process.exit(result.status ?? 1);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-zfb",
|
|
3
|
-
"version": "0.1.0-next.
|
|
3
|
+
"version": "0.1.0-next.61",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Scaffold a new zfb static-site project: `npm create zfb@latest my-site`",
|
|
@@ -31,7 +31,10 @@
|
|
|
31
31
|
"CHANGELOG.md",
|
|
32
32
|
"LICENSE"
|
|
33
33
|
],
|
|
34
|
+
"engines": {
|
|
35
|
+
"node": ">=18"
|
|
36
|
+
},
|
|
34
37
|
"dependencies": {
|
|
35
|
-
"@takazudo/zfb": "0.1.0-next.
|
|
38
|
+
"@takazudo/zfb": "0.1.0-next.61"
|
|
36
39
|
}
|
|
37
40
|
}
|