create-raredays-app 0.1.3 → 0.1.4
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.
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// Merge per-module build-script approvals into a template's pnpm-workspace.yaml.
|
|
2
|
+
//
|
|
3
|
+
// pnpm 11 blocks dependency build scripts by default and only honors approvals
|
|
4
|
+
// declared as `allowBuilds` in pnpm-workspace.yaml (the package.json `pnpm`
|
|
5
|
+
// field and .npmrc are ignored). Each scaffold fragment (module or vendor) may
|
|
6
|
+
// declare its own `allowBuilds` map in module.json; the scaffolder unions those
|
|
7
|
+
// onto the template's base so a generated app pre-approves exactly the build
|
|
8
|
+
// scripts its selected modules need — no matter which modules are chosen.
|
|
9
|
+
//
|
|
10
|
+
// Pure string transform over the template's pnpm-workspace.yaml: parse the
|
|
11
|
+
// existing ` <pkg>: true|false` entries, union the fragment-contributed ones
|
|
12
|
+
// (later wins, so a fragment can also opt a build OUT with `false`), and
|
|
13
|
+
// re-emit a sorted block while preserving the file's header comment. We avoid a
|
|
14
|
+
// YAML parser dependency on purpose — the block is a flat name->boolean map.
|
|
15
|
+
|
|
16
|
+
const ENTRY = /^ {2}["']?([^"':\s]+)["']?:\s*(true|false)\s*$/gm;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @param {string} yamlSource - the template's pnpm-workspace.yaml contents
|
|
20
|
+
* @param {Record<string, boolean>} extra - build approvals contributed by selected fragments
|
|
21
|
+
* @returns {string} the rewritten pnpm-workspace.yaml contents
|
|
22
|
+
*/
|
|
23
|
+
export function mergeAllowBuilds(yamlSource, extra) {
|
|
24
|
+
const merged = {};
|
|
25
|
+
ENTRY.lastIndex = 0;
|
|
26
|
+
let match;
|
|
27
|
+
while ((match = ENTRY.exec(yamlSource)) !== null) {
|
|
28
|
+
merged[match[1]] = match[2] === "true";
|
|
29
|
+
}
|
|
30
|
+
for (const [name, value] of Object.entries(extra)) {
|
|
31
|
+
merged[name] = value === true || value === "true";
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Preserve everything before `allowBuilds:` (the header comment block).
|
|
35
|
+
const marker = yamlSource.indexOf("allowBuilds:");
|
|
36
|
+
const header = marker > 0 ? yamlSource.slice(0, marker) : "";
|
|
37
|
+
|
|
38
|
+
const lines = Object.keys(merged)
|
|
39
|
+
.sort()
|
|
40
|
+
.map((name) => {
|
|
41
|
+
// Quote names that aren't bare identifiers (e.g. scoped "@sentry/cli").
|
|
42
|
+
const key = /^[a-zA-Z0-9_-]+$/.test(name) ? name : `"${name}"`;
|
|
43
|
+
return ` ${key}: ${merged[name] ? "true" : "false"}`;
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
return `${header}allowBuilds:\n${lines.join("\n")}\n`;
|
|
47
|
+
}
|
package/bin/index.js
CHANGED
|
@@ -7,6 +7,8 @@ import { fileURLToPath } from "node:url";
|
|
|
7
7
|
import { parseArgs } from "node:util";
|
|
8
8
|
import * as p from "@clack/prompts";
|
|
9
9
|
|
|
10
|
+
import { mergeAllowBuilds } from "./compose-allow-builds.mjs";
|
|
11
|
+
|
|
10
12
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
11
13
|
const packageRoot = resolve(__dirname, "..");
|
|
12
14
|
const templatesDir = resolve(packageRoot, "templates");
|
|
@@ -520,6 +522,7 @@ async function scaffold(opts) {
|
|
|
520
522
|
// Load + apply selected fragments. Static templates don't have a
|
|
521
523
|
// composition root, so skip module composition entirely there.
|
|
522
524
|
const collectedDeps = {};
|
|
525
|
+
const collectedBuilds = {};
|
|
523
526
|
const envVars = [];
|
|
524
527
|
const vendorMocks = [];
|
|
525
528
|
if (opts.template !== "static" && opts.selectedModules.length > 0) {
|
|
@@ -528,6 +531,7 @@ async function scaffold(opts) {
|
|
|
528
531
|
|
|
529
532
|
for (const f of valid) {
|
|
530
533
|
Object.assign(collectedDeps, f.deps ?? {});
|
|
534
|
+
Object.assign(collectedBuilds, f.allowBuilds ?? {});
|
|
531
535
|
if (f.filesDir) await cp(f.filesDir, targetDir, { recursive: true });
|
|
532
536
|
}
|
|
533
537
|
|
|
@@ -537,6 +541,7 @@ async function scaffold(opts) {
|
|
|
537
541
|
const vendor = f?.vendors?.find((v) => v.key === vendorKey);
|
|
538
542
|
if (!vendor) continue;
|
|
539
543
|
Object.assign(collectedDeps, vendor.deps ?? {});
|
|
544
|
+
Object.assign(collectedBuilds, vendor.allowBuilds ?? {});
|
|
540
545
|
for (const v of vendor.env ?? []) envVars.push(v);
|
|
541
546
|
if (vendor.mocks) {
|
|
542
547
|
vendorMocks.push(vendor.mocks);
|
|
@@ -550,6 +555,16 @@ async function scaffold(opts) {
|
|
|
550
555
|
await writeFile(runtimePath, composeRuntime(source, valid));
|
|
551
556
|
}
|
|
552
557
|
|
|
558
|
+
// Union module/vendor build-script approvals onto the template's
|
|
559
|
+
// pnpm-workspace.yaml so the generated app pre-approves exactly what its
|
|
560
|
+
// selected modules need under pnpm 11. No-op when no fragment declares any.
|
|
561
|
+
if (Object.keys(collectedBuilds).length > 0) {
|
|
562
|
+
const wsPath = resolve(targetDir, "pnpm-workspace.yaml");
|
|
563
|
+
if (existsSync(wsPath)) {
|
|
564
|
+
await writeFile(wsPath, mergeAllowBuilds(await readFile(wsPath, "utf8"), collectedBuilds));
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
|
|
553
568
|
// Compose mocks/handlers.ts for any template that ships it (full-stack + client).
|
|
554
569
|
if (opts.template !== "static") {
|
|
555
570
|
const handlersPath = resolve(targetDir, "mocks/handlers.ts");
|
package/package.json
CHANGED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# pnpm 11 blocks dependency build scripts by default, and its pre-run deps
|
|
2
|
+
# check then aborts every pnpm command (install/build/exec) with
|
|
3
|
+
# ERR_PNPM_IGNORED_BUILDS. Pre-approve the builds this app actually needs so a
|
|
4
|
+
# fresh scaffold works out of the box. (In pnpm 11 `allowBuilds` replaced
|
|
5
|
+
# `onlyBuiltDependencies`; values are booleans, not a list.)
|
|
6
|
+
allowBuilds:
|
|
7
|
+
esbuild: true
|
|
8
|
+
msw: true
|
|
9
|
+
sharp: true
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# pnpm 11 blocks dependency build scripts by default, and its pre-run deps
|
|
2
|
+
# check then aborts every pnpm command (install/build/exec) with
|
|
3
|
+
# ERR_PNPM_IGNORED_BUILDS. Pre-approve the builds this app actually needs so a
|
|
4
|
+
# fresh scaffold works out of the box. (In pnpm 11 `allowBuilds` replaced
|
|
5
|
+
# `onlyBuiltDependencies`; values are booleans, not a list.)
|
|
6
|
+
allowBuilds:
|
|
7
|
+
esbuild: true
|
|
8
|
+
msw: true
|
|
9
|
+
sharp: true
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# pnpm 11 blocks dependency build scripts by default, and its pre-run deps
|
|
2
|
+
# check then aborts every pnpm command (install/build/exec) with
|
|
3
|
+
# ERR_PNPM_IGNORED_BUILDS. Pre-approve the builds this app actually needs so a
|
|
4
|
+
# fresh scaffold works out of the box. (In pnpm 11 `allowBuilds` replaced
|
|
5
|
+
# `onlyBuiltDependencies`; values are booleans, not a list.)
|
|
6
|
+
allowBuilds:
|
|
7
|
+
esbuild: true
|
|
8
|
+
sharp: true
|