203 lines
4.8 KiB
JavaScript
203 lines
4.8 KiB
JavaScript
#!/usr/bin/env node
|
|
import { spawn, spawnSync } from "node:child_process";
|
|
import {
|
|
copyFileSync,
|
|
existsSync,
|
|
mkdirSync,
|
|
readFileSync,
|
|
writeFileSync,
|
|
} from "node:fs";
|
|
import path from "node:path";
|
|
|
|
const cwd = process.cwd();
|
|
const pascalDir = path.resolve(
|
|
cwd,
|
|
process.env.PASCAL_EDITOR_DIR || ".pascal-editor"
|
|
);
|
|
const repoUrl =
|
|
process.env.PASCAL_EDITOR_REPO || "https://github.com/pascalorg/editor.git";
|
|
const repoRef = process.env.PASCAL_EDITOR_REF || "main";
|
|
const port = process.env.PASCAL_EDITOR_PORT || "3002";
|
|
|
|
function run(command, args, options = {}) {
|
|
const result = spawnSync(command, args, {
|
|
cwd,
|
|
stdio: "inherit",
|
|
...options,
|
|
});
|
|
|
|
if (result.status !== 0) {
|
|
process.exit(result.status ?? 1);
|
|
}
|
|
}
|
|
|
|
function commandExists(command) {
|
|
const result = spawnSync(command, ["--version"], { stdio: "ignore" });
|
|
return result.status === 0;
|
|
}
|
|
|
|
function patchNestedNextRoot() {
|
|
const configPath = path.join(pascalDir, "apps/editor/next.config.ts");
|
|
if (!existsSync(configPath)) {
|
|
return;
|
|
}
|
|
|
|
let config = readFileSync(configPath, "utf8");
|
|
if (!config.includes("import path from 'node:path'")) {
|
|
config = config.replace(
|
|
"import type { NextConfig } from 'next'\n",
|
|
"import path from 'node:path'\nimport type { NextConfig } from 'next'\n"
|
|
);
|
|
}
|
|
|
|
if (!config.includes("root: path.resolve(process.cwd(), '../..')")) {
|
|
config = config.replace(
|
|
" turbopack: {\n",
|
|
" turbopack: {\n root: path.resolve(process.cwd(), '../..'),\n"
|
|
);
|
|
}
|
|
|
|
writeFileSync(configPath, config, "utf8");
|
|
}
|
|
|
|
function ensureSparseCheckout() {
|
|
run(
|
|
"git",
|
|
[
|
|
"-C",
|
|
pascalDir,
|
|
"sparse-checkout",
|
|
"set",
|
|
"apps/editor",
|
|
"packages",
|
|
"tooling",
|
|
"styles",
|
|
],
|
|
{ cwd }
|
|
);
|
|
}
|
|
|
|
function patchCssImports() {
|
|
const source = path.join(pascalDir, "styles/elevation.css");
|
|
const targetDir = path.join(pascalDir, "apps/editor/styles");
|
|
const target = path.join(targetDir, "elevation.css");
|
|
const globalsPath = path.join(pascalDir, "apps/editor/app/globals.css");
|
|
|
|
if (existsSync(source)) {
|
|
mkdirSync(targetDir, { recursive: true });
|
|
copyFileSync(source, target);
|
|
}
|
|
|
|
if (!existsSync(globalsPath)) {
|
|
return;
|
|
}
|
|
|
|
const globals = readFileSync(globalsPath, "utf8");
|
|
const patched = globals.replace(
|
|
'../../../styles/elevation.css',
|
|
'../styles/elevation.css'
|
|
);
|
|
if (patched !== globals) {
|
|
writeFileSync(globalsPath, patched, "utf8");
|
|
}
|
|
}
|
|
|
|
function runPackageScript(packageManager, packageDir, scriptName) {
|
|
if (packageManager === "bun") {
|
|
run("bun", ["--cwd", packageDir, "run", scriptName], { cwd: pascalDir });
|
|
return;
|
|
}
|
|
|
|
run("npm", ["--prefix", packageDir, "run", scriptName], { cwd: pascalDir });
|
|
}
|
|
|
|
function ensureBuiltWorkspacePackages(packageManager) {
|
|
const requiredBuilds = [
|
|
["packages/core", "dist/index.js"],
|
|
["packages/viewer", "dist/index.js"],
|
|
["packages/nodes", "dist/index.js"],
|
|
["packages/mcp", "dist/index.js"],
|
|
];
|
|
|
|
for (const [packageDir, distFile] of requiredBuilds) {
|
|
if (existsSync(path.join(pascalDir, packageDir, distFile))) {
|
|
continue;
|
|
}
|
|
runPackageScript(packageManager, packageDir, "build");
|
|
}
|
|
}
|
|
|
|
if (!existsSync(pascalDir)) {
|
|
mkdirSync(path.dirname(pascalDir), { recursive: true });
|
|
run("git", [
|
|
"clone",
|
|
"--depth",
|
|
"1",
|
|
"--filter=blob:none",
|
|
"--sparse",
|
|
"--branch",
|
|
repoRef,
|
|
repoUrl,
|
|
pascalDir,
|
|
]);
|
|
} else if (!existsSync(path.join(pascalDir, ".git"))) {
|
|
console.error(
|
|
`${pascalDir} already exists but is not a git checkout. Move it away or set PASCAL_EDITOR_DIR.`
|
|
);
|
|
process.exit(1);
|
|
}
|
|
|
|
ensureSparseCheckout();
|
|
patchCssImports();
|
|
|
|
const envLocalPath = path.join(pascalDir, ".env.local");
|
|
if (!existsSync(envLocalPath)) {
|
|
writeFileSync(envLocalPath, `PORT=${port}\n`, "utf8");
|
|
}
|
|
|
|
patchNestedNextRoot();
|
|
|
|
const hasBun = commandExists("bun");
|
|
const hasNpm = commandExists("npm");
|
|
const hasNodeModules = existsSync(path.join(pascalDir, "node_modules"));
|
|
|
|
if (!hasBun && !hasNpm) {
|
|
console.error("Pascal Editor needs Bun or npm to install dependencies.");
|
|
process.exit(1);
|
|
}
|
|
|
|
if (!hasNodeModules) {
|
|
if (hasBun) {
|
|
run("bun", ["install"], { cwd: pascalDir });
|
|
} else {
|
|
run("npm", ["install"], { cwd: pascalDir });
|
|
}
|
|
}
|
|
|
|
const packageManager = hasBun ? "bun" : "npm";
|
|
ensureBuiltWorkspacePackages(packageManager);
|
|
|
|
const command = hasBun ? "bun" : "npm";
|
|
const args = hasBun
|
|
? ["--cwd", "apps/editor", "run", "dev"]
|
|
: ["--prefix", "apps/editor", "run", "dev"];
|
|
|
|
console.log(`Starting self-hosted Pascal Editor on http://localhost:${port}`);
|
|
|
|
const child = spawn(command, args, {
|
|
cwd: pascalDir,
|
|
stdio: "inherit",
|
|
env: {
|
|
...process.env,
|
|
PORT: port,
|
|
},
|
|
});
|
|
|
|
child.on("exit", (code, signal) => {
|
|
if (signal) {
|
|
process.kill(process.pid, signal);
|
|
return;
|
|
}
|
|
process.exit(code ?? 0);
|
|
});
|