@multiplatform.one/cli 7.10.0 → 7.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/README.md +121 -111
- package/bin/createMultiplatformApp.mjs +39 -37
- package/lib/bin/multiplatformOne.mjs +65 -75
- package/lib/commands/addApp.mjs +78 -0
- package/lib/commands/adoptApp.mjs +11 -7
- package/lib/commands/doctypeTypes.mjs +148 -0
- package/lib/commands/e2e.mjs +2 -2
- package/lib/commands/init.mjs +142 -459
- package/lib/commands/merge.mjs +359 -0
- package/lib/commands/pieces.mjs +236 -0
- package/lib/commands/provenance.mjs +108 -0
- package/lib/commands/scaffold.mjs +105 -0
- package/lib/commands/updateApp.mjs +211 -528
- package/lib/source.json +5 -0
- package/lib/source.mjs +63 -0
- package/package.json +7 -7
- package/scripts/frappe-bootstrap.sh +29 -3
- package/scripts/frappe-dev.sh +1 -2
- package/scripts/frappe-helpers.sh +50 -2
- package/scripts/frappe.sh +5 -0
- package/scripts/scaffold.sh +937 -0
- package/scripts/stamp-source.mjs +51 -0
- package/scripts/stamp-source.spec.ts +86 -0
- package/src/bin/multiplatformOne.ts +116 -226
- package/src/commands/addApp.ts +102 -0
- package/src/commands/adoptApp.spec.ts +5 -1
- package/src/commands/adoptApp.ts +15 -10
- package/src/commands/doctypeTypes.spec.ts +155 -0
- package/src/commands/doctypeTypes.ts +214 -0
- package/src/commands/init.spec.ts +66 -0
- package/src/commands/init.ts +201 -643
- package/src/commands/merge.spec.ts +81 -0
- package/src/commands/merge.ts +411 -0
- package/src/commands/pieces.spec.ts +62 -0
- package/src/commands/pieces.ts +340 -0
- package/src/commands/provenance.spec.ts +92 -0
- package/src/commands/provenance.ts +169 -0
- package/src/commands/scaffold.ts +131 -0
- package/src/commands/updateApp.spec.ts +540 -331
- package/src/commands/updateApp.ts +255 -668
- package/src/source.spec.ts +45 -0
- package/src/source.ts +88 -0
- package/templates/AGENTS.md +161 -0
- package/templates/README.md +62 -0
- package/templates/pieces/frappe/universal/README.md.partial +7 -32
- package/templates/pieces/frappe/universal/env.example.partial +3 -3
- package/templates/pieces/frappe-bench/universal/README.md.partial +28 -0
- package/templates/pieces/{frappe → frappe-bench}/universal/docker/compose.frappe.yaml +2 -2
- package/templates/pieces/tauri/universal/README.md.partial +7 -5
- package/templates/pieces/tauri/universal/apps/__NAME__/src-tauri/src/dev.rs +463 -0
- package/templates/pieces/tauri/universal/apps/__NAME__/src-tauri/src/lib.rs +6 -0
- package/templates/pieces/tauri/universal/apps/__NAME__/src-tauri/tauri.conf.json +2 -1
- package/templates/pieces/webext/universal/apps/__NAME__/package.json.partial +1 -0
- package/templates/pieces/webext/universal/apps/__NAME__/vite.config.webext.ts +6 -2
- package/types/bin/multiplatformOne.d.ts.map +1 -1
- package/types/commands/addApp.d.ts +20 -0
- package/types/commands/addApp.d.ts.map +1 -0
- package/types/commands/adoptApp.d.ts +4 -3
- package/types/commands/adoptApp.d.ts.map +1 -1
- package/types/commands/doctypeTypes.d.ts +40 -0
- package/types/commands/doctypeTypes.d.ts.map +1 -0
- package/types/commands/init.d.ts +30 -13
- package/types/commands/init.d.ts.map +1 -1
- package/types/commands/merge.d.ts +54 -0
- package/types/commands/merge.d.ts.map +1 -0
- package/types/commands/pieces.d.ts +54 -0
- package/types/commands/pieces.d.ts.map +1 -0
- package/types/commands/provenance.d.ts +52 -0
- package/types/commands/provenance.d.ts.map +1 -0
- package/types/commands/scaffold.d.ts +43 -0
- package/types/commands/scaffold.d.ts.map +1 -0
- package/types/commands/updateApp.d.ts +19 -27
- package/types/commands/updateApp.d.ts.map +1 -1
- package/types/source.d.ts +35 -0
- package/types/source.d.ts.map +1 -0
- package/lib/commands/initApp.mjs +0 -431
- package/lib/generateVscode.mjs +0 -184
- package/scripts/clone.sh +0 -17
- package/scripts/update.sh +0 -46
- package/src/commands/initApp.spec.ts +0 -720
- package/src/commands/initApp.ts +0 -706
- package/src/generateVscode.ts +0 -238
- package/templates/app/AGENTS.md +0 -142
- package/templates/app/README.md +0 -62
- package/templates/app/apps/__NAME__/index.html +0 -36
- package/templates/app/apps/__NAME__/package.json +0 -31
- package/templates/app/apps/__NAME__/public/fonts/inter-400.woff2 +0 -0
- package/templates/app/apps/__NAME__/public/fonts/inter-700.woff2 +0 -0
- package/templates/app/apps/__NAME__/src/App.tsx +0 -9
- package/templates/app/apps/__NAME__/src/main.tsx +0 -14
- package/templates/app/apps/__NAME__/tsconfig.json +0 -8
- package/templates/app/apps/__NAME__/vite.config.ts +0 -17
- package/templates/app/features/__NAME__/package.json +0 -34
- package/templates/app/features/__NAME__/src/HomeScreen.tsx +0 -70
- package/templates/app/features/__NAME__/src/index.ts +0 -1
- package/templates/app/features/__NAME__/tsconfig.json +0 -5
- package/templates/app/gitignore +0 -9
- package/templates/app/npmrc +0 -2
- package/templates/app/oxlintrc.json +0 -39
- package/templates/app/package.json +0 -38
- package/templates/app/packages/config/config.json +0 -4
- package/templates/app/packages/config/index.ts +0 -5
- package/templates/app/packages/config/package.json +0 -17
- package/templates/app/packages/config/tsconfig.json +0 -5
- package/templates/app/pnpm-workspace.yaml +0 -4
- package/templates/app/tsconfig.base.json +0 -16
- package/templates/universal/AGENTS.md +0 -142
- package/templates/universal/README.md +0 -97
- package/templates/universal/apps/__NAME__/app.config.js +0 -31
- package/templates/universal/apps/__NAME__/config/tamagui.config.ts +0 -4
- package/templates/universal/apps/__NAME__/package.json +0 -62
- package/templates/universal/apps/__NAME__/polyfills.native.ts +0 -23
- package/templates/universal/apps/__NAME__/polyfills.ts +0 -3
- package/templates/universal/apps/__NAME__/public/fonts/inter-400.woff2 +0 -0
- package/templates/universal/apps/__NAME__/public/fonts/inter-700.woff2 +0 -0
- package/templates/universal/apps/__NAME__/routes/_layout.tsx +0 -22
- package/templates/universal/apps/__NAME__/routes/_layout.web.tsx +0 -21
- package/templates/universal/apps/__NAME__/routes/about.tsx +0 -3
- package/templates/universal/apps/__NAME__/routes/index.tsx +0 -3
- package/templates/universal/apps/__NAME__/src/app.ts +0 -10
- package/templates/universal/apps/__NAME__/tamagui.css +0 -3
- package/templates/universal/apps/__NAME__/tsconfig.json +0 -8
- package/templates/universal/apps/__NAME__/types.d.ts +0 -9
- package/templates/universal/apps/__NAME__/vite.config.ts +0 -20
- package/templates/universal/features/__NAME__/package.json +0 -35
- package/templates/universal/features/__NAME__/src/AboutScreen.tsx +0 -27
- package/templates/universal/features/__NAME__/src/AppLayout.tsx +0 -50
- package/templates/universal/features/__NAME__/src/ContactForm.spec.tsx +0 -22
- package/templates/universal/features/__NAME__/src/ContactForm.tsx +0 -55
- package/templates/universal/features/__NAME__/src/HomeScreen.tsx +0 -40
- package/templates/universal/features/__NAME__/src/index.ts +0 -4
- package/templates/universal/features/__NAME__/src/screens.spec.ts +0 -12
- package/templates/universal/features/__NAME__/tsconfig.json +0 -5
- package/templates/universal/features/__NAME__/vitest.config.mjs +0 -7
- package/templates/universal/gitignore +0 -14
- package/templates/universal/npmrc +0 -3
- package/templates/universal/oxlintrc.json +0 -39
- package/templates/universal/package.json +0 -51
- package/templates/universal/packages/config/config.json +0 -4
- package/templates/universal/packages/config/index.ts +0 -5
- package/templates/universal/packages/config/package.json +0 -17
- package/templates/universal/packages/config/tsconfig.json +0 -5
- package/templates/universal/packages/i18n/en/common.json +0 -30
- package/templates/universal/packages/i18n/es/common.json +0 -30
- package/templates/universal/packages/i18n/i18n.d.ts +0 -16
- package/templates/universal/packages/i18n/index.ts +0 -26
- package/templates/universal/packages/i18n/package.json +0 -20
- package/templates/universal/packages/i18n/resources.ts +0 -13
- package/templates/universal/packages/i18n/tsconfig.json +0 -5
- package/templates/universal/packages/themes/accent.ts +0 -32
- package/templates/universal/packages/themes/base.ts +0 -50
- package/templates/universal/packages/themes/fonts.ts +0 -8
- package/templates/universal/packages/themes/index.ts +0 -33
- package/templates/universal/packages/themes/package.json +0 -23
- package/templates/universal/packages/themes/tamagui.config.ts +0 -14
- package/templates/universal/packages/themes/tsconfig.json +0 -5
- package/templates/universal/pnpm-workspace.yaml +0 -4
- package/templates/universal/tsconfig.base.json +0 -21
- package/templates/universal/types/env.d.ts +0 -9
- package/types/commands/initApp.d.ts +0 -114
- package/types/commands/initApp.d.ts.map +0 -1
- package/types/generateVscode.d.ts +0 -7
- package/types/generateVscode.d.ts.map +0 -1
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { dirname, join, resolve } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
|
|
5
|
+
//#region src/commands/provenance.ts
|
|
6
|
+
const PROVENANCE_FILE = ".mpo.json";
|
|
7
|
+
function validateName(name) {
|
|
8
|
+
const trimmed = name.trim();
|
|
9
|
+
if (!trimmed) throw new Error("Project name is required");
|
|
10
|
+
if (!/^[a-z][a-z0-9-]*$/.test(trimmed)) throw new Error(`Invalid project name "${trimmed}". Use lowercase letters, numbers, and hyphens (e.g. my-app).`);
|
|
11
|
+
return trimmed;
|
|
12
|
+
}
|
|
13
|
+
/** Root package.json name with any @scope/ prefix stripped (adopt derives the project name from it). */
|
|
14
|
+
function packageJsonName(projectDir) {
|
|
15
|
+
try {
|
|
16
|
+
return JSON.parse(readFileSync(join(projectDir, "package.json"), "utf-8")).name?.replace(/^@[^/]+\//u, "");
|
|
17
|
+
} catch {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function cliRoot() {
|
|
22
|
+
return resolve(dirname(fileURLToPath(import.meta.url)), "../..");
|
|
23
|
+
}
|
|
24
|
+
function cliVersion() {
|
|
25
|
+
try {
|
|
26
|
+
return JSON.parse(readFileSync(join(cliRoot(), "package.json"), "utf-8")).version;
|
|
27
|
+
} catch {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/** `^x.y.z` for a bare version; explicit ranges pass through. */
|
|
32
|
+
function mpoRange(explicit, fallbackVersion = cliVersion()) {
|
|
33
|
+
if (explicit) return explicit.startsWith("^") || explicit.startsWith("~") || explicit === "*" ? explicit : `^${explicit}`;
|
|
34
|
+
return fallbackVersion ? `^${fallbackVersion}` : "^0.0.0";
|
|
35
|
+
}
|
|
36
|
+
function writeProvenance(targetDir, provenance) {
|
|
37
|
+
const pieces = [...provenance.pieces].sort();
|
|
38
|
+
const record = provenance.source ? {
|
|
39
|
+
cliVersion: provenance.cliVersion,
|
|
40
|
+
source: provenance.source,
|
|
41
|
+
apps: provenance.apps,
|
|
42
|
+
services: [...provenance.services].sort(),
|
|
43
|
+
pieces
|
|
44
|
+
} : {
|
|
45
|
+
template: provenance.template ?? "none",
|
|
46
|
+
cliVersion: provenance.cliVersion,
|
|
47
|
+
name: provenance.name,
|
|
48
|
+
mpoVersion: provenance.mpoVersion ?? `^${provenance.cliVersion}`,
|
|
49
|
+
pieces,
|
|
50
|
+
...provenance.reconciled === false ? { reconciled: false } : {}
|
|
51
|
+
};
|
|
52
|
+
writeFileSync(join(targetDir, PROVENANCE_FILE), `${JSON.stringify(record, null, 2)}\n`);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Reads both shapes: the clone-derived record ({cliVersion, source, apps,
|
|
56
|
+
* services, pieces}) and the older {template, name} record written by
|
|
57
|
+
* `mpo adopt` and the retired template scaffolder.
|
|
58
|
+
*/
|
|
59
|
+
function readProvenance(projectDir) {
|
|
60
|
+
const file = join(projectDir, PROVENANCE_FILE);
|
|
61
|
+
if (!existsSync(file)) return void 0;
|
|
62
|
+
let raw;
|
|
63
|
+
try {
|
|
64
|
+
raw = JSON.parse(readFileSync(file, "utf-8"));
|
|
65
|
+
} catch {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
if (typeof raw.cliVersion !== "string") return void 0;
|
|
69
|
+
const strings = (value) => Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
|
|
70
|
+
const pieces = strings(raw.pieces).sort();
|
|
71
|
+
const source = raw.source;
|
|
72
|
+
if (source && typeof source.sha === "string") return {
|
|
73
|
+
cliVersion: raw.cliVersion,
|
|
74
|
+
source: {
|
|
75
|
+
sha: source.sha,
|
|
76
|
+
...typeof source.url === "string" ? { url: source.url } : {}
|
|
77
|
+
},
|
|
78
|
+
apps: strings(raw.apps),
|
|
79
|
+
services: strings(raw.services).sort(),
|
|
80
|
+
pieces
|
|
81
|
+
};
|
|
82
|
+
const template = raw.template;
|
|
83
|
+
if (template !== "none" && template !== "universal" && template !== "app") {
|
|
84
|
+
if (Array.isArray(raw.apps)) return {
|
|
85
|
+
cliVersion: raw.cliVersion,
|
|
86
|
+
apps: strings(raw.apps),
|
|
87
|
+
services: strings(raw.services).sort(),
|
|
88
|
+
pieces,
|
|
89
|
+
template: "universal",
|
|
90
|
+
name: strings(raw.apps)[0]
|
|
91
|
+
};
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
if (typeof raw.name !== "string") return void 0;
|
|
95
|
+
return {
|
|
96
|
+
cliVersion: raw.cliVersion,
|
|
97
|
+
apps: template === "none" ? [] : [raw.name],
|
|
98
|
+
services: [],
|
|
99
|
+
pieces,
|
|
100
|
+
template,
|
|
101
|
+
name: raw.name,
|
|
102
|
+
mpoVersion: typeof raw.mpoVersion === "string" ? raw.mpoVersion : `^${raw.cliVersion}`,
|
|
103
|
+
...raw.reconciled === false ? { reconciled: false } : {}
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
//#endregion
|
|
108
|
+
export { PROVENANCE_FILE, cliRoot, cliVersion, mpoRange, packageJsonName, readProvenance, validateName, writeProvenance };
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { cliRoot, readProvenance } from "./provenance.mjs";
|
|
2
|
+
import { mkdtempSync, rmSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import spawn from "nano-spawn";
|
|
5
|
+
import { tmpdir } from "node:os";
|
|
6
|
+
|
|
7
|
+
//#region src/commands/scaffold.ts
|
|
8
|
+
/** The scaffold itself: POSIX sh, runs standalone. The TS commands only call it. */
|
|
9
|
+
function scaffoldScript() {
|
|
10
|
+
return join(cliRoot(), "scripts/scaffold.sh");
|
|
11
|
+
}
|
|
12
|
+
var ScaffoldError = class extends Error {
|
|
13
|
+
constructor(message, request) {
|
|
14
|
+
super(message);
|
|
15
|
+
this.request = request;
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
/** --into keeps every path the target already had; name them, since mpo update will not touch them. */
|
|
19
|
+
function reportKept(stdout) {
|
|
20
|
+
const prefix = "skipped (exists): ";
|
|
21
|
+
const kept = stdout.split("\n").filter((line) => line.startsWith(prefix)).map((line) => line.slice(18));
|
|
22
|
+
if (!kept.length) return;
|
|
23
|
+
console.log(`\nKept ${kept.length} path(s) already here, pinned in .updateignore:`);
|
|
24
|
+
for (const path of kept) console.log(` ${path}`);
|
|
25
|
+
}
|
|
26
|
+
/** Run scaffold.sh and return the provenance it wrote. */
|
|
27
|
+
async function runScaffold(request) {
|
|
28
|
+
const args = [scaffoldScript()];
|
|
29
|
+
for (const app of request.apps) args.push("--app", app);
|
|
30
|
+
for (const service of request.services) args.push("--service", service);
|
|
31
|
+
if (request.mpoVersion) args.push("--mpo-version", request.mpoVersion);
|
|
32
|
+
if (request.into) args.push("--into");
|
|
33
|
+
if (request.sourceUrl) args.push("--source-url", request.sourceUrl);
|
|
34
|
+
if (request.name) args.push("--name", request.name);
|
|
35
|
+
args.push("--", request.source, request.ref, request.target);
|
|
36
|
+
let stdout = "";
|
|
37
|
+
try {
|
|
38
|
+
stdout = (await spawn("sh", args, { stdio: request.verbose ? "inherit" : [
|
|
39
|
+
"ignore",
|
|
40
|
+
"pipe",
|
|
41
|
+
"pipe"
|
|
42
|
+
] })).stdout;
|
|
43
|
+
} catch (err) {
|
|
44
|
+
throw new ScaffoldError(((err.stderr ?? "").trim().split("\n").filter(Boolean).pop() ?? err.message).replace(/^scaffold: /, ""), request);
|
|
45
|
+
}
|
|
46
|
+
if (request.into && !request.verbose) reportKept(stdout);
|
|
47
|
+
const provenance = readProvenance(request.target);
|
|
48
|
+
if (!provenance?.source) throw new ScaffoldError(`scaffold.sh wrote no provenance into ${request.target}`, request);
|
|
49
|
+
return provenance;
|
|
50
|
+
}
|
|
51
|
+
/** A scaffold in a temp dir (merge baselines). */
|
|
52
|
+
async function scaffoldToTemp(request) {
|
|
53
|
+
const parent = mkdtempSync(join(tmpdir(), "mpo-scaffold-"));
|
|
54
|
+
const dir = join(parent, "project");
|
|
55
|
+
const cleanup = () => rmSync(parent, {
|
|
56
|
+
recursive: true,
|
|
57
|
+
force: true
|
|
58
|
+
});
|
|
59
|
+
try {
|
|
60
|
+
return {
|
|
61
|
+
dir,
|
|
62
|
+
provenance: await runScaffold({
|
|
63
|
+
...request,
|
|
64
|
+
target: dir
|
|
65
|
+
}),
|
|
66
|
+
cleanup
|
|
67
|
+
};
|
|
68
|
+
} catch (err) {
|
|
69
|
+
cleanup();
|
|
70
|
+
throw err;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* One subtree of the monorepo at a ref, extracted into `dest` (the piece
|
|
75
|
+
* templates of an older CLI version, for adopted-project merge bases).
|
|
76
|
+
*/
|
|
77
|
+
async function archiveSubtree(source, ref, subtree, dest) {
|
|
78
|
+
await spawn("sh", [
|
|
79
|
+
"-c",
|
|
80
|
+
[
|
|
81
|
+
"set -eu",
|
|
82
|
+
"SOURCE=\"$1\"; REF=\"$2\"; SUBTREE=\"$3\"; DEST=\"$4\"",
|
|
83
|
+
"if [ -d \"$SOURCE\" ]; then REPO=\"$SOURCE\"; else",
|
|
84
|
+
" REPO=\"$(mktemp -d \"${TMPDIR:-/tmp}/mpo-archive.XXXXXX\")\"",
|
|
85
|
+
" trap 'rm -rf \"$REPO\"' EXIT",
|
|
86
|
+
" git clone -q --depth 1 --no-checkout --branch \"$REF\" \"$SOURCE\" \"$REPO\"",
|
|
87
|
+
" REF=HEAD",
|
|
88
|
+
"fi",
|
|
89
|
+
"mkdir -p \"$DEST\"",
|
|
90
|
+
"git -C \"$REPO\" archive --format=tar \"$REF\" \"$SUBTREE\" | tar -xf - -C \"$DEST\""
|
|
91
|
+
].join("\n"),
|
|
92
|
+
"sh",
|
|
93
|
+
source,
|
|
94
|
+
ref,
|
|
95
|
+
subtree,
|
|
96
|
+
dest
|
|
97
|
+
], { stdio: [
|
|
98
|
+
"ignore",
|
|
99
|
+
"ignore",
|
|
100
|
+
"pipe"
|
|
101
|
+
] });
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
//#endregion
|
|
105
|
+
export { ScaffoldError, archiveSubtree, runScaffold, scaffoldScript, scaffoldToTemp };
|