|
1 | 1 | import path from "path"; |
2 | 2 | import fs from "fs"; |
3 | 3 |
|
4 | | -async function main() { |
5 | | - const root = path.resolve(import.meta.dir, ".."); |
6 | | - const out = path.join(root, ".build"); |
7 | | - |
8 | | - fs.rmSync(out, { recursive: true, force: true }); |
9 | | - |
10 | | - // Compile all source files in one shot. `packages: "external"` keeps npm |
11 | | - // deps and self-referencing @spader/dotllm/* imports as bare specifiers. |
12 | | - const sources = Array.from(new Bun.Glob("src/**/*.ts").scanSync(root)); |
13 | | - const result = await Bun.build({ |
14 | | - entrypoints: sources.map(f => path.join(root, f)), |
15 | | - outdir: out, |
16 | | - root, |
17 | | - target: "bun", |
18 | | - packages: "external", |
19 | | - }); |
20 | | - |
21 | | - if (!result.success) { |
22 | | - for (const log of result.logs) console.error(log); |
23 | | - process.exit(1); |
24 | | - } |
| 4 | +export namespace Build { |
| 5 | + type Opt = { |
| 6 | + root?: string; |
| 7 | + out?: string; |
| 8 | + pack?: string; |
| 9 | + }; |
25 | 10 |
|
26 | | - // Ensure CLI entry point is executable |
27 | | - fs.chmodSync(path.join(out, "src/cli/index.js"), 0o755); |
28 | | - |
29 | | - // Generate a publish-ready package.json with JS paths |
30 | | - const pkg = await Bun.file(path.join(root, "package.json")).json(); |
31 | | - pkg.bin = { dotllm: "src/cli/index.js" }; |
32 | | - pkg.exports = { |
33 | | - "./cli": "./src/cli/index.js", |
34 | | - "./cli/*": "./src/cli/*.js", |
35 | | - "./core": "./src/core/index.js", |
36 | | - "./core/*": "./src/core/*.js", |
| 11 | + type Result = { |
| 12 | + files: number; |
| 13 | + out: string; |
| 14 | + tar: string; |
37 | 15 | }; |
38 | | - pkg.files = ["src/**/*.js", "README.md"]; |
39 | | - delete pkg.scripts; |
40 | | - delete pkg.devDependencies; |
41 | | - await Bun.write(path.join(out, "package.json"), JSON.stringify(pkg, null, 2) + "\n"); |
42 | | - |
43 | | - fs.copyFileSync(path.join(root, "README.md"), path.join(out, "README.md")); |
44 | | - |
45 | | - // Create npm tarball |
46 | | - const pack = Bun.spawnSync(["npm", "pack"], { cwd: out, stdout: "pipe", stderr: "pipe" }); |
47 | | - if (pack.exitCode !== 0) { |
48 | | - console.error(pack.stderr.toString()); |
49 | | - process.exit(1); |
| 16 | + |
| 17 | + export async function build(opt: Opt = {}): Promise<Result> { |
| 18 | + const root = opt.root ?? path.resolve(import.meta.dir, ".."); |
| 19 | + const out = opt.out ?? path.join(root, ".build"); |
| 20 | + const packDir = opt.pack ?? out; |
| 21 | + |
| 22 | + fs.rmSync(out, { recursive: true, force: true }); |
| 23 | + fs.mkdirSync(packDir, { recursive: true }); |
| 24 | + |
| 25 | + const src = Array.from(new Bun.Glob("src/**/*.ts").scanSync(root)); |
| 26 | + const res = await Bun.build({ |
| 27 | + entrypoints: src.map(f => path.join(root, f)), |
| 28 | + outdir: out, |
| 29 | + root, |
| 30 | + target: "bun", |
| 31 | + packages: "external", |
| 32 | + }); |
| 33 | + |
| 34 | + if (!res.success) { |
| 35 | + for (const log of res.logs) console.error(log); |
| 36 | + return Promise.reject(new Error("build failed")); |
| 37 | + } |
| 38 | + |
| 39 | + fs.chmodSync(path.join(out, "src/cli/index.js"), 0o755); |
| 40 | + |
| 41 | + const raw = await Bun.file(path.join(root, "package.json")).json() as Record<string, unknown>; |
| 42 | + raw.bin = { dotllm: "src/cli/index.js" }; |
| 43 | + raw.exports = { |
| 44 | + "./cli": "./src/cli/index.js", |
| 45 | + "./cli/*": "./src/cli/*.js", |
| 46 | + "./core": "./src/core/index.js", |
| 47 | + "./core/*": "./src/core/*.js", |
| 48 | + }; |
| 49 | + raw.files = ["src/**/*.js", "README.md"]; |
| 50 | + delete raw.scripts; |
| 51 | + delete raw.devDependencies; |
| 52 | + delete raw.imports; |
| 53 | + await Bun.write(path.join(out, "package.json"), JSON.stringify(raw, null, 2) + "\n"); |
| 54 | + |
| 55 | + fs.copyFileSync(path.join(root, "README.md"), path.join(out, "README.md")); |
| 56 | + |
| 57 | + const pack = Bun.spawnSync(["npm", "pack", "--json", "--pack-destination", packDir], { |
| 58 | + cwd: out, |
| 59 | + stdout: "pipe", |
| 60 | + stderr: "pipe", |
| 61 | + }); |
| 62 | + if (pack.exitCode !== 0) { |
| 63 | + return Promise.reject(new Error(pack.stderr.toString() || "npm pack failed")); |
| 64 | + } |
| 65 | + |
| 66 | + const json = JSON.parse(pack.stdout.toString()) as { filename?: string }[]; |
| 67 | + const file = json[0]?.filename ?? ""; |
| 68 | + if (file.length === 0) { |
| 69 | + return Promise.reject(new Error("npm pack did not return filename")); |
| 70 | + } |
| 71 | + |
| 72 | + return { |
| 73 | + files: src.length, |
| 74 | + out, |
| 75 | + tar: path.join(packDir, file), |
| 76 | + }; |
50 | 77 | } |
51 | 78 |
|
52 | | - console.log(`${sources.length} files compiled`); |
53 | | - console.log(`.build/${pack.stdout.toString().trim()}`); |
| 79 | + export async function main(): Promise<void> { |
| 80 | + } |
54 | 81 | } |
55 | 82 |
|
56 | | -main(); |
| 83 | +if (import.meta.main) { |
| 84 | + const res = await Build.build(); |
| 85 | + const root = path.resolve(import.meta.dir, ".."); |
| 86 | + const rel = path.relative(root, res.tar); |
| 87 | + console.log(`${res.files} files compiled`); |
| 88 | + console.log(rel); |
| 89 | +} |
0 commit comments