@zeltjs/cli 0.0.1
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/dist/cli.d.ts +1 -0
- package/dist/cli.js +303 -0
- package/dist/cli.js.map +1 -0
- package/dist/config/index.d.ts +2 -0
- package/dist/config/index.js +3 -0
- package/dist/config-sfn4XGtd.js +7 -0
- package/dist/config-sfn4XGtd.js.map +1 -0
- package/dist/index-BjAqm820.d.ts +1692 -0
- package/dist/index-BjAqm820.d.ts.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +3 -0
- package/dist/loader-BhQ9yc4i.js +29 -0
- package/dist/loader-BhQ9yc4i.js.map +1 -0
- package/package.json +53 -0
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { t as loadZeltConfig } from "./loader-BhQ9yc4i.js";
|
|
3
|
+
import { defineCommand, runMain } from "citty";
|
|
4
|
+
import consola from "consola";
|
|
5
|
+
import { ResultAsync, errAsync, okAsync } from "neverthrow";
|
|
6
|
+
import { match } from "ts-pattern";
|
|
7
|
+
import { spawn } from "node:child_process";
|
|
8
|
+
import { resolve } from "node:path";
|
|
9
|
+
import { watch } from "chokidar";
|
|
10
|
+
//#region src/builders/tsdown.ts
|
|
11
|
+
const buildArgs = (config) => {
|
|
12
|
+
const args = [];
|
|
13
|
+
if (config.entry !== void 0) args.push("--entry", config.entry);
|
|
14
|
+
if (config.outDir !== void 0) args.push("--out-dir", config.outDir);
|
|
15
|
+
if (config.format !== void 0) args.push("--format", config.format);
|
|
16
|
+
if (config.platform !== void 0) args.push("--platform", config.platform);
|
|
17
|
+
if (config.external === true) args.push("--deps.never-bundle", "*");
|
|
18
|
+
args.push("--clean");
|
|
19
|
+
args.push("--no-config");
|
|
20
|
+
return args;
|
|
21
|
+
};
|
|
22
|
+
const runTsdownBuild = (options) => {
|
|
23
|
+
const { cwd, config } = options;
|
|
24
|
+
const args = buildArgs(config);
|
|
25
|
+
consola.info(`Running tsdown in ${cwd}`);
|
|
26
|
+
consola.debug(`tsdown ${args.join(" ")}`);
|
|
27
|
+
const tsdownBin = resolve(cwd, "node_modules/.bin/tsdown");
|
|
28
|
+
return ResultAsync.fromPromise(new Promise((resolvePromise, rejectPromise) => {
|
|
29
|
+
const child = spawn(tsdownBin, args, {
|
|
30
|
+
cwd,
|
|
31
|
+
stdio: "inherit"
|
|
32
|
+
});
|
|
33
|
+
child.on("close", (code) => {
|
|
34
|
+
resolvePromise(code ?? 0);
|
|
35
|
+
});
|
|
36
|
+
child.on("error", (err) => {
|
|
37
|
+
rejectPromise(err);
|
|
38
|
+
});
|
|
39
|
+
}), () => ({
|
|
40
|
+
type: "BUILD_FAILED",
|
|
41
|
+
exitCode: 1
|
|
42
|
+
})).andThen((exitCode) => {
|
|
43
|
+
if (exitCode !== 0) return errAsync({
|
|
44
|
+
type: "BUILD_FAILED",
|
|
45
|
+
exitCode
|
|
46
|
+
});
|
|
47
|
+
return okAsync(void 0);
|
|
48
|
+
});
|
|
49
|
+
};
|
|
50
|
+
//#endregion
|
|
51
|
+
//#region src/commands/build.ts
|
|
52
|
+
const resolveBuildConfig = (args, buildConfig) => ({
|
|
53
|
+
...buildConfig,
|
|
54
|
+
entry: args.entry ?? buildConfig?.entry,
|
|
55
|
+
outDir: args.outDir ?? buildConfig?.outDir
|
|
56
|
+
});
|
|
57
|
+
const runBuild = (cwd, typedArgs) => {
|
|
58
|
+
const configFile = typedArgs.config;
|
|
59
|
+
return loadZeltConfig(configFile !== void 0 ? {
|
|
60
|
+
cwd,
|
|
61
|
+
configFile
|
|
62
|
+
} : { cwd }).andThen((config) => {
|
|
63
|
+
const buildConfig = resolveBuildConfig(typedArgs, config.build);
|
|
64
|
+
if (buildConfig.entry === void 0) return errAsync({ type: "NO_ENTRY" });
|
|
65
|
+
consola.start("Building...");
|
|
66
|
+
return runTsdownBuild({
|
|
67
|
+
cwd,
|
|
68
|
+
config: buildConfig
|
|
69
|
+
}).map(() => {
|
|
70
|
+
consola.success("Build completed");
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
};
|
|
74
|
+
const buildCommand = defineCommand({
|
|
75
|
+
meta: {
|
|
76
|
+
name: "build",
|
|
77
|
+
description: "Build the application using tsdown"
|
|
78
|
+
},
|
|
79
|
+
args: {
|
|
80
|
+
config: {
|
|
81
|
+
type: "string",
|
|
82
|
+
alias: "c",
|
|
83
|
+
description: "Path to zelt.config.ts"
|
|
84
|
+
},
|
|
85
|
+
entry: {
|
|
86
|
+
type: "string",
|
|
87
|
+
alias: "e",
|
|
88
|
+
description: "Entry file (overrides config)"
|
|
89
|
+
},
|
|
90
|
+
outDir: {
|
|
91
|
+
type: "string",
|
|
92
|
+
alias: "o",
|
|
93
|
+
description: "Output directory (overrides config)"
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
async run({ args }) {
|
|
97
|
+
(await runBuild(globalThis.process.cwd(), args)).match(() => {}, (error) => match(error).with({ type: "CONFIG_LOAD_FAILED" }, () => {
|
|
98
|
+
consola.error("Failed to load config");
|
|
99
|
+
}).with({ type: "NO_ENTRY" }, () => {
|
|
100
|
+
consola.error("No entry file specified. Use --entry or set build.entry in zelt.config.ts");
|
|
101
|
+
}).with({ type: "BUILD_FAILED" }, () => {
|
|
102
|
+
consola.error("Build failed");
|
|
103
|
+
}).exhaustive());
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
//#endregion
|
|
107
|
+
//#region src/dev-server/watcher.ts
|
|
108
|
+
const createWatcher = (options) => {
|
|
109
|
+
const { cwd, patterns, ignore, debounceMs, onChange } = options;
|
|
110
|
+
let debounceTimer;
|
|
111
|
+
const watcher = watch(patterns, {
|
|
112
|
+
cwd,
|
|
113
|
+
ignored: ignore,
|
|
114
|
+
ignoreInitial: true,
|
|
115
|
+
persistent: true
|
|
116
|
+
});
|
|
117
|
+
watcher.on("all", (_event, _path) => {
|
|
118
|
+
if (debounceTimer !== void 0) clearTimeout(debounceTimer);
|
|
119
|
+
debounceTimer = setTimeout(() => {
|
|
120
|
+
debounceTimer = void 0;
|
|
121
|
+
onChange();
|
|
122
|
+
}, debounceMs);
|
|
123
|
+
});
|
|
124
|
+
return { close: async () => {
|
|
125
|
+
if (debounceTimer !== void 0) clearTimeout(debounceTimer);
|
|
126
|
+
await watcher.close();
|
|
127
|
+
} };
|
|
128
|
+
};
|
|
129
|
+
//#endregion
|
|
130
|
+
//#region src/dev-server/server.ts
|
|
131
|
+
const DEFAULT_WATCH_PATTERNS = ["./src/**/*.ts"];
|
|
132
|
+
const DEFAULT_IGNORE_PATTERNS = [
|
|
133
|
+
"**/*.test.ts",
|
|
134
|
+
"**/*.spec.ts",
|
|
135
|
+
"**/dist/**",
|
|
136
|
+
"**/node_modules/**"
|
|
137
|
+
];
|
|
138
|
+
const KILL_TIMEOUT_MS = 3e3;
|
|
139
|
+
const killProcess = (child) => {
|
|
140
|
+
return new Promise((resolve) => {
|
|
141
|
+
if (child.killed || child.exitCode !== null) {
|
|
142
|
+
resolve();
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
const forceKillTimer = setTimeout(() => {
|
|
146
|
+
if (!child.killed && child.exitCode === null) {
|
|
147
|
+
consola.warn("Process did not exit gracefully, forcing kill...");
|
|
148
|
+
child.kill("SIGKILL");
|
|
149
|
+
}
|
|
150
|
+
}, KILL_TIMEOUT_MS);
|
|
151
|
+
child.once("exit", () => {
|
|
152
|
+
clearTimeout(forceKillTimer);
|
|
153
|
+
resolve();
|
|
154
|
+
});
|
|
155
|
+
child.kill("SIGTERM");
|
|
156
|
+
});
|
|
157
|
+
};
|
|
158
|
+
const startProcess = (cwd, entry) => {
|
|
159
|
+
consola.info(`Starting: tsx ${entry}`);
|
|
160
|
+
const child = spawn("npx", ["tsx", entry], {
|
|
161
|
+
cwd,
|
|
162
|
+
stdio: "inherit"
|
|
163
|
+
});
|
|
164
|
+
child.on("error", (err) => {
|
|
165
|
+
consola.error("Failed to start process:", err.message);
|
|
166
|
+
});
|
|
167
|
+
child.on("exit", (code, signal) => {
|
|
168
|
+
if (signal !== null) consola.info(`Process terminated by signal: ${signal}`);
|
|
169
|
+
else if (code !== 0 && code !== null) consola.error(`Process exited with code: ${code}`);
|
|
170
|
+
});
|
|
171
|
+
return child;
|
|
172
|
+
};
|
|
173
|
+
const createShutdownHandler = (state) => {
|
|
174
|
+
return async () => {
|
|
175
|
+
if (state.isShuttingDown) return;
|
|
176
|
+
state.isShuttingDown = true;
|
|
177
|
+
consola.info("Shutting down dev server...");
|
|
178
|
+
if (state.watcher !== void 0) await state.watcher.close();
|
|
179
|
+
if (state.childProcess !== void 0) await killProcess(state.childProcess);
|
|
180
|
+
};
|
|
181
|
+
};
|
|
182
|
+
const createRestartHandler = (state, cwd, entry) => {
|
|
183
|
+
return async () => {
|
|
184
|
+
if (state.isShuttingDown) return;
|
|
185
|
+
consola.info("File changed, restarting...");
|
|
186
|
+
if (state.childProcess !== void 0) await killProcess(state.childProcess);
|
|
187
|
+
state.childProcess = startProcess(cwd, entry);
|
|
188
|
+
};
|
|
189
|
+
};
|
|
190
|
+
const registerSignalHandlers = (onSignal) => {
|
|
191
|
+
const handler = () => {
|
|
192
|
+
onSignal();
|
|
193
|
+
};
|
|
194
|
+
globalThis.process.on("SIGINT", handler);
|
|
195
|
+
globalThis.process.on("SIGTERM", handler);
|
|
196
|
+
return () => {
|
|
197
|
+
globalThis.process.off("SIGINT", handler);
|
|
198
|
+
globalThis.process.off("SIGTERM", handler);
|
|
199
|
+
};
|
|
200
|
+
};
|
|
201
|
+
const startDevServer = async (options) => {
|
|
202
|
+
const { cwd, config } = options;
|
|
203
|
+
const state = {
|
|
204
|
+
childProcess: void 0,
|
|
205
|
+
watcher: void 0,
|
|
206
|
+
isShuttingDown: false
|
|
207
|
+
};
|
|
208
|
+
const watchPatterns = config.watch ?? DEFAULT_WATCH_PATTERNS;
|
|
209
|
+
const ignorePatterns = config.ignore ?? DEFAULT_IGNORE_PATTERNS;
|
|
210
|
+
const debounceMs = config.debounceMs ?? 300;
|
|
211
|
+
const shutdown = createShutdownHandler(state);
|
|
212
|
+
const restart = createRestartHandler(state, cwd, config.entry);
|
|
213
|
+
registerSignalHandlers(shutdown);
|
|
214
|
+
state.watcher = createWatcher({
|
|
215
|
+
cwd,
|
|
216
|
+
patterns: watchPatterns,
|
|
217
|
+
ignore: ignorePatterns,
|
|
218
|
+
debounceMs,
|
|
219
|
+
onChange: () => {
|
|
220
|
+
restart();
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
state.childProcess = startProcess(cwd, config.entry);
|
|
224
|
+
consola.success(`Dev server started. Watching for changes...`);
|
|
225
|
+
consola.info(` Entry: ${config.entry}`);
|
|
226
|
+
consola.info(` Watch: ${watchPatterns.join(", ")}`);
|
|
227
|
+
consola.info(` Ignore: ${ignorePatterns.join(", ")}`);
|
|
228
|
+
return new Promise(() => {});
|
|
229
|
+
};
|
|
230
|
+
//#endregion
|
|
231
|
+
//#region src/commands/dev.ts
|
|
232
|
+
const resolveDevConfig = (args, devConfig) => {
|
|
233
|
+
const entry = args.entry ?? devConfig?.entry;
|
|
234
|
+
const port = args.port !== void 0 ? Number.parseInt(args.port, 10) : devConfig?.port;
|
|
235
|
+
return {
|
|
236
|
+
...devConfig,
|
|
237
|
+
entry,
|
|
238
|
+
port
|
|
239
|
+
};
|
|
240
|
+
};
|
|
241
|
+
const runDev = (cwd, typedArgs) => {
|
|
242
|
+
const configFile = typedArgs.config;
|
|
243
|
+
return loadZeltConfig(configFile !== void 0 ? {
|
|
244
|
+
cwd,
|
|
245
|
+
configFile
|
|
246
|
+
} : { cwd }).andThen((config) => {
|
|
247
|
+
const devConfig = resolveDevConfig(typedArgs, config.dev);
|
|
248
|
+
if (devConfig.entry === void 0) return errAsync({ type: "NO_ENTRY" });
|
|
249
|
+
return ResultAsync.fromSafePromise(startDevServer({
|
|
250
|
+
cwd,
|
|
251
|
+
config: {
|
|
252
|
+
...devConfig,
|
|
253
|
+
entry: devConfig.entry
|
|
254
|
+
}
|
|
255
|
+
}));
|
|
256
|
+
});
|
|
257
|
+
};
|
|
258
|
+
//#endregion
|
|
259
|
+
//#region src/cli.ts
|
|
260
|
+
runMain(defineCommand({
|
|
261
|
+
meta: {
|
|
262
|
+
name: "zelt",
|
|
263
|
+
version: "0.0.1",
|
|
264
|
+
description: "Zelt Framework CLI"
|
|
265
|
+
},
|
|
266
|
+
subCommands: {
|
|
267
|
+
build: buildCommand,
|
|
268
|
+
dev: defineCommand({
|
|
269
|
+
meta: {
|
|
270
|
+
name: "dev",
|
|
271
|
+
description: "Start development server with file watching"
|
|
272
|
+
},
|
|
273
|
+
args: {
|
|
274
|
+
config: {
|
|
275
|
+
type: "string",
|
|
276
|
+
alias: "c",
|
|
277
|
+
description: "Path to zelt.config.ts"
|
|
278
|
+
},
|
|
279
|
+
entry: {
|
|
280
|
+
type: "string",
|
|
281
|
+
alias: "e",
|
|
282
|
+
description: "Entry file (overrides config)"
|
|
283
|
+
},
|
|
284
|
+
port: {
|
|
285
|
+
type: "string",
|
|
286
|
+
alias: "p",
|
|
287
|
+
description: "Port to listen on (overrides config)"
|
|
288
|
+
}
|
|
289
|
+
},
|
|
290
|
+
async run({ args }) {
|
|
291
|
+
(await runDev(globalThis.process.cwd(), args)).match(() => {}, (error) => match(error).with({ type: "CONFIG_LOAD_FAILED" }, () => {
|
|
292
|
+
consola.error("Failed to load config");
|
|
293
|
+
}).with({ type: "NO_ENTRY" }, () => {
|
|
294
|
+
consola.error("No entry file specified. Use --entry or set dev.entry in zelt.config.ts");
|
|
295
|
+
}).exhaustive());
|
|
296
|
+
}
|
|
297
|
+
})
|
|
298
|
+
}
|
|
299
|
+
}));
|
|
300
|
+
//#endregion
|
|
301
|
+
export {};
|
|
302
|
+
|
|
303
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","names":["typedArgs","typedArgs"],"sources":["../src/builders/tsdown.ts","../src/commands/build.ts","../src/dev-server/watcher.ts","../src/dev-server/server.ts","../src/commands/dev.ts","../src/commands/main.ts","../src/cli.ts"],"sourcesContent":["import { spawn } from 'node:child_process';\nimport { resolve } from 'node:path';\n\nimport consola from 'consola';\nimport { errAsync, okAsync, ResultAsync } from 'neverthrow';\n\nimport type { BuildConfig } from '../config/schema';\n\nexport type BuildOptions = {\n readonly cwd: string;\n readonly config: BuildConfig;\n};\n\nexport type BuildError = { type: 'BUILD_FAILED'; exitCode: number };\n\nconst buildArgs = (config: BuildConfig): string[] => {\n const args: string[] = [];\n\n if (config.entry !== undefined) {\n args.push('--entry', config.entry);\n }\n\n if (config.outDir !== undefined) {\n args.push('--out-dir', config.outDir);\n }\n\n if (config.format !== undefined) {\n args.push('--format', config.format);\n }\n\n if (config.platform !== undefined) {\n args.push('--platform', config.platform);\n }\n\n if (config.external === true) {\n args.push('--deps.never-bundle', '*');\n }\n\n args.push('--clean');\n args.push('--no-config');\n\n return args;\n};\n\nexport const runTsdownBuild = (options: BuildOptions): ResultAsync<void, BuildError> => {\n const { cwd, config } = options;\n const args = buildArgs(config);\n\n consola.info(`Running tsdown in ${cwd}`);\n consola.debug(`tsdown ${args.join(' ')}`);\n\n const tsdownBin = resolve(cwd, 'node_modules/.bin/tsdown');\n\n return ResultAsync.fromPromise(\n new Promise<number>((resolvePromise, rejectPromise) => {\n const child = spawn(tsdownBin, args, {\n cwd,\n stdio: 'inherit',\n });\n\n child.on('close', (code) => {\n resolvePromise(code ?? 0);\n });\n\n child.on('error', (err) => {\n rejectPromise(err);\n });\n }),\n () => ({ type: 'BUILD_FAILED' as const, exitCode: 1 }),\n ).andThen((exitCode) => {\n if (exitCode !== 0) {\n return errAsync({ type: 'BUILD_FAILED' as const, exitCode });\n }\n return okAsync(undefined);\n });\n};\n","import { defineCommand } from 'citty';\nimport consola from 'consola';\nimport { errAsync, type ResultAsync } from 'neverthrow';\nimport { match } from 'ts-pattern';\n\nimport { type BuildError, runTsdownBuild } from '../builders/tsdown';\nimport { type ConfigLoadError, loadZeltConfig } from '../config/loader';\nimport type { BuildConfig } from '../config/schema';\n\ntype BuildArgs = {\n readonly config?: string;\n readonly entry?: string;\n readonly outDir?: string;\n};\n\ntype RunBuildError = ConfigLoadError | BuildError | { type: 'NO_ENTRY' };\n\nconst resolveBuildConfig = (args: BuildArgs, buildConfig: BuildConfig | undefined) => ({\n ...buildConfig,\n entry: args.entry ?? buildConfig?.entry,\n outDir: args.outDir ?? buildConfig?.outDir,\n});\n\nconst runBuild = (cwd: string, typedArgs: BuildArgs): ResultAsync<void, RunBuildError> => {\n const configFile = typedArgs.config;\n\n return loadZeltConfig(configFile !== undefined ? { cwd, configFile } : { cwd }).andThen(\n (config) => {\n const buildConfig = resolveBuildConfig(typedArgs, config.build);\n\n if (buildConfig.entry === undefined) {\n return errAsync({ type: 'NO_ENTRY' as const });\n }\n\n consola.start('Building...');\n\n return runTsdownBuild({ cwd, config: buildConfig }).map(() => {\n consola.success('Build completed');\n return undefined;\n });\n },\n );\n};\n\nexport const buildCommand = defineCommand({\n meta: {\n name: 'build',\n description: 'Build the application using tsdown',\n },\n args: {\n config: {\n type: 'string',\n alias: 'c',\n description: 'Path to zelt.config.ts',\n },\n entry: {\n type: 'string',\n alias: 'e',\n description: 'Entry file (overrides config)',\n },\n outDir: {\n type: 'string',\n alias: 'o',\n description: 'Output directory (overrides config)',\n },\n },\n async run({ args }) {\n const cwd = globalThis.process.cwd();\n const typedArgs: BuildArgs = args;\n\n const result = await runBuild(cwd, typedArgs);\n\n result.match(\n () => {},\n (error) =>\n match(error)\n .with({ type: 'CONFIG_LOAD_FAILED' }, () => {\n consola.error('Failed to load config');\n })\n .with({ type: 'NO_ENTRY' }, () => {\n consola.error(\n 'No entry file specified. Use --entry or set build.entry in zelt.config.ts',\n );\n })\n .with({ type: 'BUILD_FAILED' }, () => {\n consola.error('Build failed');\n })\n .exhaustive(),\n );\n },\n});\n","import { watch } from 'chokidar';\n\nexport type WatcherOptions = {\n readonly cwd: string;\n readonly patterns: string[];\n readonly ignore: string[];\n readonly debounceMs: number;\n readonly onChange: () => void;\n};\n\nexport type WatcherHandle = {\n readonly close: () => Promise<void>;\n};\n\nexport const createWatcher = (options: WatcherOptions): WatcherHandle => {\n const { cwd, patterns, ignore, debounceMs, onChange } = options;\n\n let debounceTimer: ReturnType<typeof setTimeout> | undefined;\n\n const watcher = watch(patterns, {\n cwd,\n ignored: ignore,\n ignoreInitial: true,\n persistent: true,\n });\n\n watcher.on('all', (_event, _path) => {\n if (debounceTimer !== undefined) {\n clearTimeout(debounceTimer);\n }\n\n debounceTimer = setTimeout(() => {\n debounceTimer = undefined;\n onChange();\n }, debounceMs);\n });\n\n return {\n close: async () => {\n if (debounceTimer !== undefined) {\n clearTimeout(debounceTimer);\n }\n await watcher.close();\n },\n };\n};\n","import { type ChildProcess, spawn } from 'node:child_process';\n\nimport consola from 'consola';\n\nimport type { DevConfig } from '../config/schema';\n\nimport { createWatcher, type WatcherHandle } from './watcher';\n\nexport type DevServerOptions = {\n readonly cwd: string;\n readonly config: DevConfig & { entry: string };\n};\n\ntype DevServerState = {\n childProcess: ChildProcess | undefined;\n watcher: WatcherHandle | undefined;\n isShuttingDown: boolean;\n};\n\nconst DEFAULT_WATCH_PATTERNS = ['./src/**/*.ts'];\nconst DEFAULT_IGNORE_PATTERNS = [\n '**/*.test.ts',\n '**/*.spec.ts',\n '**/dist/**',\n '**/node_modules/**',\n];\nconst KILL_TIMEOUT_MS = 3000;\n\nconst killProcess = (child: ChildProcess): Promise<void> => {\n return new Promise((resolve) => {\n if (child.killed || child.exitCode !== null) {\n resolve();\n return;\n }\n\n const forceKillTimer = setTimeout(() => {\n if (!child.killed && child.exitCode === null) {\n consola.warn('Process did not exit gracefully, forcing kill...');\n child.kill('SIGKILL');\n }\n }, KILL_TIMEOUT_MS);\n\n child.once('exit', () => {\n clearTimeout(forceKillTimer);\n resolve();\n });\n\n child.kill('SIGTERM');\n });\n};\n\nconst startProcess = (cwd: string, entry: string): ChildProcess => {\n consola.info(`Starting: tsx ${entry}`);\n\n const child = spawn('npx', ['tsx', entry], {\n cwd,\n stdio: 'inherit',\n });\n\n child.on('error', (err) => {\n consola.error('Failed to start process:', err.message);\n });\n\n child.on('exit', (code, signal) => {\n if (signal !== null) {\n consola.info(`Process terminated by signal: ${signal}`);\n } else if (code !== 0 && code !== null) {\n consola.error(`Process exited with code: ${code}`);\n }\n });\n\n return child;\n};\n\nconst createShutdownHandler = (state: DevServerState) => {\n return async (): Promise<void> => {\n if (state.isShuttingDown) {\n return;\n }\n\n state.isShuttingDown = true;\n consola.info('Shutting down dev server...');\n\n if (state.watcher !== undefined) {\n await state.watcher.close();\n }\n\n if (state.childProcess !== undefined) {\n await killProcess(state.childProcess);\n }\n };\n};\n\nconst createRestartHandler = (state: DevServerState, cwd: string, entry: string) => {\n return async (): Promise<void> => {\n if (state.isShuttingDown) {\n return;\n }\n\n consola.info('File changed, restarting...');\n\n if (state.childProcess !== undefined) {\n await killProcess(state.childProcess);\n }\n\n state.childProcess = startProcess(cwd, entry);\n };\n};\n\ntype SignalHandler = () => void;\n\nconst registerSignalHandlers = (onSignal: () => Promise<void>): SignalHandler => {\n const handler = (): void => {\n void onSignal();\n };\n\n globalThis.process.on('SIGINT', handler);\n globalThis.process.on('SIGTERM', handler);\n\n return () => {\n globalThis.process.off('SIGINT', handler);\n globalThis.process.off('SIGTERM', handler);\n };\n};\n\nexport const startDevServer = async (options: DevServerOptions): Promise<void> => {\n const { cwd, config } = options;\n\n const state: DevServerState = {\n childProcess: undefined,\n watcher: undefined,\n isShuttingDown: false,\n };\n\n const watchPatterns = config.watch ?? DEFAULT_WATCH_PATTERNS;\n const ignorePatterns = config.ignore ?? DEFAULT_IGNORE_PATTERNS;\n const debounceMs = config.debounceMs ?? 300;\n\n const shutdown = createShutdownHandler(state);\n const restart = createRestartHandler(state, cwd, config.entry);\n\n registerSignalHandlers(shutdown);\n\n state.watcher = createWatcher({\n cwd,\n patterns: watchPatterns,\n ignore: ignorePatterns,\n debounceMs,\n onChange: () => {\n void restart();\n },\n });\n\n state.childProcess = startProcess(cwd, config.entry);\n\n consola.success(`Dev server started. Watching for changes...`);\n consola.info(` Entry: ${config.entry}`);\n consola.info(` Watch: ${watchPatterns.join(', ')}`);\n consola.info(` Ignore: ${ignorePatterns.join(', ')}`);\n\n return new Promise(() => {\n // Keep the process running until signal received\n });\n};\n","import { defineCommand } from 'citty';\nimport consola from 'consola';\nimport { errAsync, ResultAsync } from 'neverthrow';\nimport { match } from 'ts-pattern';\n\nimport { type ConfigLoadError, loadZeltConfig } from '../config/loader';\nimport type { DevConfig } from '../config/schema';\nimport { startDevServer } from '../dev-server/server';\n\ntype DevArgs = {\n readonly config?: string;\n readonly entry?: string;\n readonly port?: string;\n};\n\ntype DevError = ConfigLoadError | { type: 'NO_ENTRY' };\n\nconst resolveDevConfig = (args: DevArgs, devConfig: DevConfig | undefined) => {\n const entry = args.entry ?? devConfig?.entry;\n const port = args.port !== undefined ? Number.parseInt(args.port, 10) : devConfig?.port;\n\n return {\n ...devConfig,\n entry,\n port,\n };\n};\n\nconst runDev = (cwd: string, typedArgs: DevArgs): ResultAsync<void, DevError> => {\n const configFile = typedArgs.config;\n\n return loadZeltConfig(configFile !== undefined ? { cwd, configFile } : { cwd }).andThen(\n (config) => {\n const devConfig = resolveDevConfig(typedArgs, config.dev);\n\n if (devConfig.entry === undefined) {\n return errAsync({ type: 'NO_ENTRY' as const });\n }\n\n return ResultAsync.fromSafePromise(\n startDevServer({ cwd, config: { ...devConfig, entry: devConfig.entry } }),\n );\n },\n );\n};\n\nexport const devCommand = defineCommand({\n meta: {\n name: 'dev',\n description: 'Start development server with file watching',\n },\n args: {\n config: {\n type: 'string',\n alias: 'c',\n description: 'Path to zelt.config.ts',\n },\n entry: {\n type: 'string',\n alias: 'e',\n description: 'Entry file (overrides config)',\n },\n port: {\n type: 'string',\n alias: 'p',\n description: 'Port to listen on (overrides config)',\n },\n },\n async run({ args }) {\n const cwd = globalThis.process.cwd();\n const typedArgs: DevArgs = args;\n\n const result = await runDev(cwd, typedArgs);\n\n result.match(\n () => {},\n (error) =>\n match(error)\n .with({ type: 'CONFIG_LOAD_FAILED' }, () => {\n consola.error('Failed to load config');\n })\n .with({ type: 'NO_ENTRY' }, () => {\n consola.error(\n 'No entry file specified. Use --entry or set dev.entry in zelt.config.ts',\n );\n })\n .exhaustive(),\n );\n },\n});\n","import { defineCommand } from 'citty';\n\nimport { buildCommand } from './build';\nimport { devCommand } from './dev';\n\nexport const mainCommand = defineCommand({\n meta: {\n name: 'zelt',\n version: '0.0.1',\n description: 'Zelt Framework CLI',\n },\n subCommands: {\n build: buildCommand,\n dev: devCommand,\n },\n});\n","#!/usr/bin/env node\nimport { runMain } from 'citty';\n\nimport { mainCommand } from './commands/main';\n\nvoid runMain(mainCommand);\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { a as DevConfig, i as BuildConfig, n as loadZeltConfig, o as OpenApiConfig, r as defineConfig, s as ZeltConfig, t as LoadConfigOptions } from "../index-BjAqm820.js";
|
|
2
|
+
export { BuildConfig, DevConfig, LoadConfigOptions, OpenApiConfig, ZeltConfig, defineConfig, loadZeltConfig };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-sfn4XGtd.js","names":[],"sources":["../src/config/define-config.ts"],"sourcesContent":["import type { ZeltConfig } from './schema';\n\nexport const defineConfig = <T extends ZeltConfig>(config: T): T => config;\n"],"mappings":";;AAEA,MAAa,gBAAsC,WAAiB"}
|