@seedcord/cli 0.0.1 → 0.1.0-next.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 +1 -1
- package/bin/seedcord.mjs +22 -0
- package/dist/Hmr-BXZ-LFe5.d.mts +33 -0
- package/dist/api/vite-hmr.d.mts +33 -0
- package/dist/api/vite-hmr.mjs +1 -0
- package/dist/cli.d.mts +1 -0
- package/dist/cli.mjs +1905 -4148
- package/dist/cli.mjs.map +1 -1
- package/dist/index.d.mts +73 -0
- package/dist/index.mjs +2 -717
- package/dist/src-CCX-T6t_.mjs +20 -0
- package/dist/src-CCX-T6t_.mjs.map +1 -0
- package/package.json +48 -28
- package/dist/cli.d.ts +0 -2
- package/dist/index.d.ts +0 -207
- package/dist/index.mjs.map +0 -1
package/dist/index.mjs
CHANGED
|
@@ -1,718 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { SeedcordError, SeedcordErrorCode, isSeedcordError } from '@seedcord/services';
|
|
3
|
-
import { dirname, resolve, isAbsolute, relative, join, extname, basename } from 'path';
|
|
4
|
-
import { existsSync } from 'fs';
|
|
5
|
-
import { pathToFileURL } from 'url';
|
|
6
|
-
import { createJiti } from 'jiti';
|
|
7
|
-
import { tsImport } from 'tsx/esm/api';
|
|
8
|
-
import { mkdir, writeFile, readdir, readFile } from 'fs/promises';
|
|
9
|
-
import { build } from 'tsup';
|
|
10
|
-
import ts2 from 'typescript';
|
|
1
|
+
import { n as SEEDCORD_CONFIG_FILENAMES, r as defineConfig, t as version } from "./src-CCX-T6t_.mjs";
|
|
11
2
|
|
|
12
|
-
|
|
13
|
-
var __defProp = Object.defineProperty;
|
|
14
|
-
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
15
|
-
|
|
16
|
-
// src/utils/resolveDefaultExport.ts
|
|
17
|
-
function resolveDefaultExport(moduleExport) {
|
|
18
|
-
let current = moduleExport;
|
|
19
|
-
const visited = /* @__PURE__ */ new Set();
|
|
20
|
-
while (isObjectWithDefault(current) && !visited.has(current)) {
|
|
21
|
-
visited.add(current);
|
|
22
|
-
current = current.default;
|
|
23
|
-
}
|
|
24
|
-
return current;
|
|
25
|
-
}
|
|
26
|
-
__name(resolveDefaultExport, "resolveDefaultExport");
|
|
27
|
-
function isObjectWithDefault(value) {
|
|
28
|
-
return Boolean(value && typeof value === "object" && "default" in value);
|
|
29
|
-
}
|
|
30
|
-
__name(isObjectWithDefault, "isObjectWithDefault");
|
|
31
|
-
|
|
32
|
-
// src/runtime/SeedcordInstanceLoader.ts
|
|
33
|
-
var SeedcordInstanceLoader = class {
|
|
34
|
-
static {
|
|
35
|
-
__name(this, "SeedcordInstanceLoader");
|
|
36
|
-
}
|
|
37
|
-
modules;
|
|
38
|
-
logger;
|
|
39
|
-
constructor(modules, logger) {
|
|
40
|
-
this.modules = modules;
|
|
41
|
-
this.logger = logger;
|
|
42
|
-
}
|
|
43
|
-
async load(instancePath) {
|
|
44
|
-
const loadedModule = await this.modules.importModule(instancePath);
|
|
45
|
-
const exported = resolveDefaultExport(loadedModule);
|
|
46
|
-
const instance = await Promise.resolve(exported);
|
|
47
|
-
if (!this.isSeedcordLike(instance)) {
|
|
48
|
-
throw new SeedcordError(SeedcordErrorCode.CliInstanceInvalid);
|
|
49
|
-
}
|
|
50
|
-
this.logger.info(`Loaded Seedcord instance from ${instancePath}`);
|
|
51
|
-
return instance;
|
|
52
|
-
}
|
|
53
|
-
isSeedcordLike(candidate) {
|
|
54
|
-
return Boolean(candidate) && typeof candidate.start === "function";
|
|
55
|
-
}
|
|
56
|
-
};
|
|
57
|
-
var ConfigLoader = class {
|
|
58
|
-
static {
|
|
59
|
-
__name(this, "ConfigLoader");
|
|
60
|
-
}
|
|
61
|
-
modules;
|
|
62
|
-
logger;
|
|
63
|
-
constructor(modules, logger) {
|
|
64
|
-
this.modules = modules;
|
|
65
|
-
this.logger = logger;
|
|
66
|
-
}
|
|
67
|
-
async load(configPath) {
|
|
68
|
-
const loadedModule = await this.modules.importModule(configPath);
|
|
69
|
-
const rawExport = resolveDefaultExport(loadedModule);
|
|
70
|
-
const config = await this.unwrapConfig(rawExport);
|
|
71
|
-
const configDir = dirname(configPath);
|
|
72
|
-
const root = resolve(configDir, config.root ?? ".");
|
|
73
|
-
const instance = this.resolveWithinRoot(root, config.instance);
|
|
74
|
-
const entry = this.resolveWithinRoot(root, config.entry);
|
|
75
|
-
this.assertEntryWithinRoot(root, entry);
|
|
76
|
-
const build = this.resolveBuildOptions(configDir, config.build);
|
|
77
|
-
this.logger.info(`Loaded configuration from ${configPath}`);
|
|
78
|
-
this.logger.debug(`Resolved root: ${root}`);
|
|
79
|
-
this.logger.debug(`Resolved instance: ${instance}`);
|
|
80
|
-
this.logger.debug(`Resolved entry: ${entry}`);
|
|
81
|
-
this.logger.debug(`Resolved build outDir: ${build.outDir}`);
|
|
82
|
-
if (build.tsconfig) this.logger.debug(`Resolved build tsconfig: ${build.tsconfig}`);
|
|
83
|
-
this.logger.debug(`Resolved bootstrap: ${build.bootstrap}`);
|
|
84
|
-
return {
|
|
85
|
-
instance,
|
|
86
|
-
root,
|
|
87
|
-
configFile: configPath,
|
|
88
|
-
entry,
|
|
89
|
-
build
|
|
90
|
-
};
|
|
91
|
-
}
|
|
92
|
-
// eslint-disable-next-line complexity
|
|
93
|
-
async unwrapConfig(raw) {
|
|
94
|
-
const resolved = await Promise.resolve(raw);
|
|
95
|
-
if (!resolved || typeof resolved !== "object") {
|
|
96
|
-
throw new SeedcordError(SeedcordErrorCode.CliConfigInvalidExport);
|
|
97
|
-
}
|
|
98
|
-
const cfg = resolved;
|
|
99
|
-
if (!cfg.instance || typeof cfg.instance !== "string") {
|
|
100
|
-
throw new SeedcordError(SeedcordErrorCode.CliConfigMissingInstance);
|
|
101
|
-
}
|
|
102
|
-
if (!cfg.entry || typeof cfg.entry !== "string") {
|
|
103
|
-
throw new SeedcordError(SeedcordErrorCode.CliConfigMissingEntry);
|
|
104
|
-
}
|
|
105
|
-
if (typeof cfg.root !== "undefined" && typeof cfg.root !== "string") {
|
|
106
|
-
throw new SeedcordError(SeedcordErrorCode.CliConfigInvalidRoot);
|
|
107
|
-
}
|
|
108
|
-
if (typeof cfg.build !== "undefined" && typeof cfg.build !== "object") {
|
|
109
|
-
throw new SeedcordError(SeedcordErrorCode.CliConfigInvalidBuild);
|
|
110
|
-
}
|
|
111
|
-
if (cfg.build) {
|
|
112
|
-
const { outDir, tsconfig, bootstrap } = cfg.build;
|
|
113
|
-
if (typeof outDir !== "undefined" && typeof outDir !== "string") {
|
|
114
|
-
throw new SeedcordError(SeedcordErrorCode.CliConfigInvalidBuildOutDir);
|
|
115
|
-
}
|
|
116
|
-
if (typeof tsconfig !== "undefined" && typeof tsconfig !== "string") {
|
|
117
|
-
throw new SeedcordError(SeedcordErrorCode.CliConfigInvalidBuildTsconfig);
|
|
118
|
-
}
|
|
119
|
-
if (typeof bootstrap !== "undefined" && typeof bootstrap !== "string") {
|
|
120
|
-
throw new SeedcordError(SeedcordErrorCode.CliConfigInvalidBuildBootstrap);
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
const normalized = {
|
|
124
|
-
instance: cfg.instance,
|
|
125
|
-
entry: cfg.entry
|
|
126
|
-
};
|
|
127
|
-
if (typeof cfg.root === "string") normalized.root = cfg.root;
|
|
128
|
-
if (cfg.build) normalized.build = cfg.build;
|
|
129
|
-
return normalized;
|
|
130
|
-
}
|
|
131
|
-
resolveWithinRoot(root, target) {
|
|
132
|
-
if (isAbsolute(target)) return target;
|
|
133
|
-
return resolve(root, target);
|
|
134
|
-
}
|
|
135
|
-
assertEntryWithinRoot(root, entry) {
|
|
136
|
-
const relativePath = relative(root, entry);
|
|
137
|
-
if (relativePath.startsWith("..") || isAbsolute(relativePath)) {
|
|
138
|
-
throw new SeedcordError(SeedcordErrorCode.CliConfigEntryOutsideRoot, [
|
|
139
|
-
entry,
|
|
140
|
-
root
|
|
141
|
-
]);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
resolveBuildOptions(configDir, build) {
|
|
145
|
-
const outDir = resolve(configDir, build?.outDir ?? "dist");
|
|
146
|
-
const bootstrapValue = build?.bootstrap;
|
|
147
|
-
const bootstrap = bootstrapValue ? this.resolveBootstrap(outDir, bootstrapValue) : resolve(outDir, "index.mjs");
|
|
148
|
-
const tsconfig = build?.tsconfig ? resolve(configDir, build.tsconfig) : void 0;
|
|
149
|
-
const resolvedBuild = tsconfig ? {
|
|
150
|
-
outDir,
|
|
151
|
-
bootstrap,
|
|
152
|
-
tsconfig
|
|
153
|
-
} : {
|
|
154
|
-
outDir,
|
|
155
|
-
bootstrap
|
|
156
|
-
};
|
|
157
|
-
return resolvedBuild;
|
|
158
|
-
}
|
|
159
|
-
resolveBootstrap(outDir, bootstrap) {
|
|
160
|
-
if (isAbsolute(bootstrap)) return bootstrap;
|
|
161
|
-
return resolve(outDir, bootstrap);
|
|
162
|
-
}
|
|
163
|
-
};
|
|
164
|
-
|
|
165
|
-
// src/config/schema.ts
|
|
166
|
-
var SEEDCORD_CONFIG_FILENAMES = [
|
|
167
|
-
"seedcord.config.ts",
|
|
168
|
-
"seedcord.config.mts"
|
|
169
|
-
];
|
|
170
|
-
function defineConfig(config) {
|
|
171
|
-
return config;
|
|
172
|
-
}
|
|
173
|
-
__name(defineConfig, "defineConfig");
|
|
174
|
-
|
|
175
|
-
// src/config/ConfigLocator.ts
|
|
176
|
-
var ConfigLocator = class {
|
|
177
|
-
static {
|
|
178
|
-
__name(this, "ConfigLocator");
|
|
179
|
-
}
|
|
180
|
-
logger;
|
|
181
|
-
constructor(logger) {
|
|
182
|
-
this.logger = logger;
|
|
183
|
-
}
|
|
184
|
-
locate(baseDir = process.cwd()) {
|
|
185
|
-
const normalizedBase = resolve(baseDir);
|
|
186
|
-
for (const candidate of SEEDCORD_CONFIG_FILENAMES) {
|
|
187
|
-
const fullPath = join(normalizedBase, candidate);
|
|
188
|
-
if (existsSync(fullPath)) {
|
|
189
|
-
this.logger.debug(`Found config at ${fullPath}`);
|
|
190
|
-
return fullPath;
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
throw new SeedcordError(SeedcordErrorCode.CliConfigNotFound, [
|
|
194
|
-
normalizedBase,
|
|
195
|
-
SEEDCORD_CONFIG_FILENAMES
|
|
196
|
-
]);
|
|
197
|
-
}
|
|
198
|
-
};
|
|
199
|
-
var TS_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
200
|
-
".ts",
|
|
201
|
-
".tsx",
|
|
202
|
-
".mts",
|
|
203
|
-
".cts"
|
|
204
|
-
]);
|
|
205
|
-
var RuntimeModuleLoader = class {
|
|
206
|
-
static {
|
|
207
|
-
__name(this, "RuntimeModuleLoader");
|
|
208
|
-
}
|
|
209
|
-
options;
|
|
210
|
-
jiti = createJiti(import.meta.url, {
|
|
211
|
-
cache: false,
|
|
212
|
-
interopDefault: true,
|
|
213
|
-
extensions: [
|
|
214
|
-
".ts",
|
|
215
|
-
".tsx",
|
|
216
|
-
".mts",
|
|
217
|
-
".cts",
|
|
218
|
-
".js",
|
|
219
|
-
".mjs",
|
|
220
|
-
".cjs"
|
|
221
|
-
]
|
|
222
|
-
});
|
|
223
|
-
constructor(options = {}) {
|
|
224
|
-
this.options = options;
|
|
225
|
-
}
|
|
226
|
-
async importModule(entryPath) {
|
|
227
|
-
const normalized = resolve(entryPath);
|
|
228
|
-
if (!existsSync(normalized)) {
|
|
229
|
-
throw new SeedcordError(SeedcordErrorCode.CliEntryNotFound, [
|
|
230
|
-
normalized
|
|
231
|
-
]);
|
|
232
|
-
}
|
|
233
|
-
if (this.shouldUseTsx(normalized)) {
|
|
234
|
-
return this.importWithTsx(normalized);
|
|
235
|
-
}
|
|
236
|
-
return this.importWithNode(normalized);
|
|
237
|
-
}
|
|
238
|
-
shouldUseTsx(filePath) {
|
|
239
|
-
if (this.options.forceTsx) return true;
|
|
240
|
-
return TS_EXTENSIONS.has(extname(filePath).toLowerCase());
|
|
241
|
-
}
|
|
242
|
-
async importWithTsx(entryPath) {
|
|
243
|
-
const specifier = pathToFileURL(entryPath).href;
|
|
244
|
-
const tsconfig = this.resolveTsconfig(entryPath);
|
|
245
|
-
try {
|
|
246
|
-
return await tsImport(specifier, {
|
|
247
|
-
parentURL: import.meta.url,
|
|
248
|
-
tsconfig
|
|
249
|
-
});
|
|
250
|
-
} catch (error) {
|
|
251
|
-
const reason = error instanceof Error ? error.message : "Unknown tsx error";
|
|
252
|
-
throw new SeedcordError(SeedcordErrorCode.CliTsxImportFailed, [
|
|
253
|
-
entryPath,
|
|
254
|
-
reason
|
|
255
|
-
]);
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
async importWithNode(entryPath) {
|
|
259
|
-
const specifier = pathToFileURL(entryPath).href;
|
|
260
|
-
try {
|
|
261
|
-
return await import(specifier);
|
|
262
|
-
} catch (nativeError) {
|
|
263
|
-
try {
|
|
264
|
-
return await this.jiti.import(entryPath);
|
|
265
|
-
} catch (fallbackError) {
|
|
266
|
-
const nativeReason = nativeError instanceof Error ? nativeError.message : "Unknown ESM import error";
|
|
267
|
-
const fallbackReason = fallbackError instanceof Error ? fallbackError.message : "Unknown jiti error";
|
|
268
|
-
throw new SeedcordError(SeedcordErrorCode.CliImportFailed, [
|
|
269
|
-
entryPath,
|
|
270
|
-
nativeReason,
|
|
271
|
-
fallbackReason
|
|
272
|
-
]);
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
resolveTsconfig(entryPath) {
|
|
277
|
-
if (typeof this.options.tsconfig !== "undefined") {
|
|
278
|
-
return this.options.tsconfig;
|
|
279
|
-
}
|
|
280
|
-
return this.findNearestTsconfig(dirname(entryPath)) ?? false;
|
|
281
|
-
}
|
|
282
|
-
findNearestTsconfig(startDir) {
|
|
283
|
-
const candidate = resolve(startDir, "tsconfig.json");
|
|
284
|
-
if (existsSync(candidate)) return candidate;
|
|
285
|
-
const parent = dirname(startDir);
|
|
286
|
-
if (parent === startDir) return void 0;
|
|
287
|
-
return this.findNearestTsconfig(parent);
|
|
288
|
-
}
|
|
289
|
-
};
|
|
290
|
-
|
|
291
|
-
// src/runtime/SeedcordDevRunner.ts
|
|
292
|
-
var SeedcordDevSession = class SeedcordDevSession2 {
|
|
293
|
-
static {
|
|
294
|
-
__name(this, "SeedcordDevSession");
|
|
295
|
-
}
|
|
296
|
-
config;
|
|
297
|
-
instanceLoader;
|
|
298
|
-
logger;
|
|
299
|
-
constructor(config, instanceLoader, logger) {
|
|
300
|
-
this.config = config;
|
|
301
|
-
this.instanceLoader = instanceLoader;
|
|
302
|
-
this.logger = logger;
|
|
303
|
-
}
|
|
304
|
-
async start() {
|
|
305
|
-
const instance = await this.instanceLoader.load(this.config.instance);
|
|
306
|
-
try {
|
|
307
|
-
this.logger.info("Starting Seedcord instance...");
|
|
308
|
-
await instance.start();
|
|
309
|
-
this.logger.info("Seedcord is running.");
|
|
310
|
-
} catch (error) {
|
|
311
|
-
const reason = error instanceof Error ? error.message : "Unknown error";
|
|
312
|
-
throw new SeedcordError(SeedcordErrorCode.CliStartFailed, [
|
|
313
|
-
this.config.instance,
|
|
314
|
-
reason
|
|
315
|
-
]);
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
};
|
|
319
|
-
var SeedcordDevRunner = class _SeedcordDevRunner {
|
|
320
|
-
static {
|
|
321
|
-
__name(this, "SeedcordDevRunner");
|
|
322
|
-
}
|
|
323
|
-
locator;
|
|
324
|
-
configLoader;
|
|
325
|
-
instanceLoader;
|
|
326
|
-
logger;
|
|
327
|
-
constructor(locator, configLoader, instanceLoader, logger) {
|
|
328
|
-
this.locator = locator;
|
|
329
|
-
this.configLoader = configLoader;
|
|
330
|
-
this.instanceLoader = instanceLoader;
|
|
331
|
-
this.logger = logger;
|
|
332
|
-
}
|
|
333
|
-
static create(logger) {
|
|
334
|
-
const moduleLoader = new RuntimeModuleLoader();
|
|
335
|
-
const locator = new ConfigLocator(logger);
|
|
336
|
-
const configLoader = new ConfigLoader(moduleLoader, logger);
|
|
337
|
-
const instanceLoader = new SeedcordInstanceLoader(moduleLoader, logger);
|
|
338
|
-
return new _SeedcordDevRunner(locator, configLoader, instanceLoader, logger);
|
|
339
|
-
}
|
|
340
|
-
async run() {
|
|
341
|
-
const config = await this.loadConfig();
|
|
342
|
-
const session = new SeedcordDevSession(config, this.instanceLoader, this.logger);
|
|
343
|
-
await session.start();
|
|
344
|
-
}
|
|
345
|
-
async loadConfig() {
|
|
346
|
-
const configPath = this.locator.locate();
|
|
347
|
-
return this.configLoader.load(configPath);
|
|
348
|
-
}
|
|
349
|
-
};
|
|
350
|
-
|
|
351
|
-
// src/commands/DevCommand.ts
|
|
352
|
-
var DevCommand = class _DevCommand {
|
|
353
|
-
static {
|
|
354
|
-
__name(this, "DevCommand");
|
|
355
|
-
}
|
|
356
|
-
runner;
|
|
357
|
-
logger;
|
|
358
|
-
constructor(runner, logger) {
|
|
359
|
-
this.runner = runner;
|
|
360
|
-
this.logger = logger;
|
|
361
|
-
}
|
|
362
|
-
register(program) {
|
|
363
|
-
program.command("dev").description("Run a Seedcord instance from seedcord.config.ts").action(async () => {
|
|
364
|
-
try {
|
|
365
|
-
await this.runner.run();
|
|
366
|
-
} catch (error) {
|
|
367
|
-
this.logger.error("Seedcord dev failed", error);
|
|
368
|
-
if (isSeedcordError(error)) process.exitCode = 1;
|
|
369
|
-
else process.exit(1);
|
|
370
|
-
}
|
|
371
|
-
});
|
|
372
|
-
}
|
|
373
|
-
static create(logger) {
|
|
374
|
-
return new _DevCommand(SeedcordDevRunner.create(logger), logger);
|
|
375
|
-
}
|
|
376
|
-
};
|
|
377
|
-
var BootstrapWriter = class {
|
|
378
|
-
static {
|
|
379
|
-
__name(this, "BootstrapWriter");
|
|
380
|
-
}
|
|
381
|
-
logger;
|
|
382
|
-
constructor(logger) {
|
|
383
|
-
this.logger = logger;
|
|
384
|
-
}
|
|
385
|
-
async write(config, emittedEntry) {
|
|
386
|
-
const target = config.build.bootstrap;
|
|
387
|
-
const relativeImport = this.formatImportPath(relative(dirname(target), emittedEntry));
|
|
388
|
-
const contents = `import '${relativeImport}';
|
|
389
|
-
`;
|
|
390
|
-
try {
|
|
391
|
-
await mkdir(dirname(target), {
|
|
392
|
-
recursive: true
|
|
393
|
-
});
|
|
394
|
-
await writeFile(target, contents, "utf8");
|
|
395
|
-
} catch (error) {
|
|
396
|
-
const reason = error instanceof Error ? error.message : "Unknown error";
|
|
397
|
-
throw new SeedcordError(SeedcordErrorCode.CliBootstrapWriteFailed, [
|
|
398
|
-
target,
|
|
399
|
-
reason
|
|
400
|
-
]);
|
|
401
|
-
}
|
|
402
|
-
this.logger.info(`Bootstrap file created at ${target}`);
|
|
403
|
-
}
|
|
404
|
-
formatImportPath(fragment) {
|
|
405
|
-
let normalized = fragment.replace(/\\/g, "/");
|
|
406
|
-
if (!normalized.startsWith(".")) normalized = `./${normalized}`;
|
|
407
|
-
return normalized;
|
|
408
|
-
}
|
|
409
|
-
};
|
|
410
|
-
var EntryPointCollector = class {
|
|
411
|
-
static {
|
|
412
|
-
__name(this, "EntryPointCollector");
|
|
413
|
-
}
|
|
414
|
-
collect(config, tsconfigPath) {
|
|
415
|
-
const parsed = this.parseTsconfig(tsconfigPath);
|
|
416
|
-
const entries = /* @__PURE__ */ new Map();
|
|
417
|
-
for (const filePath of parsed.fileNames) {
|
|
418
|
-
if (!this.shouldEmitFile(config, filePath)) continue;
|
|
419
|
-
entries.set(this.createEntryKey(config, filePath), filePath);
|
|
420
|
-
}
|
|
421
|
-
const entryKey = this.createEntryKey(config, config.entry);
|
|
422
|
-
if (!entries.size || !entries.has(entryKey)) entries.set(entryKey, config.entry);
|
|
423
|
-
return {
|
|
424
|
-
entryMap: Object.fromEntries(entries),
|
|
425
|
-
primaryKey: entryKey
|
|
426
|
-
};
|
|
427
|
-
}
|
|
428
|
-
parseTsconfig(tsconfigPath) {
|
|
429
|
-
const configFile = ts2.readConfigFile(tsconfigPath, (filePath) => ts2.sys.readFile(filePath));
|
|
430
|
-
if (configFile.error) {
|
|
431
|
-
const reason = this.formatDiagnostics([
|
|
432
|
-
configFile.error
|
|
433
|
-
]);
|
|
434
|
-
throw new SeedcordError(SeedcordErrorCode.CliBuildTsconfigInvalid, [
|
|
435
|
-
tsconfigPath,
|
|
436
|
-
reason
|
|
437
|
-
]);
|
|
438
|
-
}
|
|
439
|
-
const parsed = ts2.parseJsonConfigFileContent(configFile.config, ts2.sys, dirname(tsconfigPath), void 0, tsconfigPath);
|
|
440
|
-
if (parsed.errors.length) {
|
|
441
|
-
const reason = this.formatDiagnostics(parsed.errors);
|
|
442
|
-
throw new SeedcordError(SeedcordErrorCode.CliBuildTsconfigInvalid, [
|
|
443
|
-
tsconfigPath,
|
|
444
|
-
reason
|
|
445
|
-
]);
|
|
446
|
-
}
|
|
447
|
-
return parsed;
|
|
448
|
-
}
|
|
449
|
-
shouldEmitFile(config, filePath) {
|
|
450
|
-
if (!this.isWithinRoot(config.root, filePath)) return false;
|
|
451
|
-
if (/\.d\.[cm]?ts$/i.test(filePath)) return false;
|
|
452
|
-
return /\.[cm]?tsx?$/i.test(filePath);
|
|
453
|
-
}
|
|
454
|
-
isWithinRoot(root, target) {
|
|
455
|
-
const relativePath = relative(root, target);
|
|
456
|
-
return relativePath === "" || !relativePath.startsWith("..") && !relativePath.startsWith("..\\");
|
|
457
|
-
}
|
|
458
|
-
createEntryKey(config, filePath) {
|
|
459
|
-
const relativePath = relative(config.root, filePath);
|
|
460
|
-
const fallback = this.createEntryFallback(filePath);
|
|
461
|
-
if (relativePath.startsWith("..")) return fallback;
|
|
462
|
-
const sanitized = relativePath.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\.[^.]+$/, "").replace(/[^a-zA-Z0-9\-/_]/g, "-");
|
|
463
|
-
return sanitized || fallback;
|
|
464
|
-
}
|
|
465
|
-
createEntryFallback(filePath) {
|
|
466
|
-
const base = basename(filePath, extname(filePath)) || "seedcord-entry";
|
|
467
|
-
return base.replace(/[^a-zA-Z0-9-_]/g, "-");
|
|
468
|
-
}
|
|
469
|
-
formatDiagnostics(diagnostics) {
|
|
470
|
-
return diagnostics.map((diagnostic) => {
|
|
471
|
-
const message = ts2.flattenDiagnosticMessageText(diagnostic.messageText, "\n");
|
|
472
|
-
if (diagnostic.file && typeof diagnostic.start === "number") {
|
|
473
|
-
const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
|
|
474
|
-
return `${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message}`;
|
|
475
|
-
}
|
|
476
|
-
return message;
|
|
477
|
-
}).join("\n");
|
|
478
|
-
}
|
|
479
|
-
};
|
|
480
|
-
var RelativeSpecifierTransformer = class {
|
|
481
|
-
static {
|
|
482
|
-
__name(this, "RelativeSpecifierTransformer");
|
|
483
|
-
}
|
|
484
|
-
async transform(outDir) {
|
|
485
|
-
const files = await this.collectJavaScriptFiles(outDir);
|
|
486
|
-
for (const filePath of files) {
|
|
487
|
-
await this.rewriteFile(filePath);
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
async collectJavaScriptFiles(rootDir) {
|
|
491
|
-
const pending = [
|
|
492
|
-
rootDir
|
|
493
|
-
];
|
|
494
|
-
const files = [];
|
|
495
|
-
while (pending.length) {
|
|
496
|
-
const current = pending.pop();
|
|
497
|
-
if (!current) continue;
|
|
498
|
-
const entries = await readdir(current, {
|
|
499
|
-
withFileTypes: true
|
|
500
|
-
});
|
|
501
|
-
for (const entry of entries) {
|
|
502
|
-
const fullPath = resolve(current, entry.name);
|
|
503
|
-
if (entry.isDirectory()) pending.push(fullPath);
|
|
504
|
-
else if (entry.isFile() && entry.name.endsWith(".js")) files.push(fullPath);
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
return files;
|
|
508
|
-
}
|
|
509
|
-
async rewriteFile(filePath) {
|
|
510
|
-
const source = await readFile(filePath, "utf8");
|
|
511
|
-
const replacements = this.extractSpecifierReplacements(source);
|
|
512
|
-
if (!replacements.length) return;
|
|
513
|
-
let mutated = source;
|
|
514
|
-
for (const replacement of replacements.sort((a, b) => b.start - a.start)) {
|
|
515
|
-
mutated = `${mutated.slice(0, replacement.start)}${replacement.text}${mutated.slice(replacement.end)}`;
|
|
516
|
-
}
|
|
517
|
-
await writeFile(filePath, mutated, "utf8");
|
|
518
|
-
}
|
|
519
|
-
extractSpecifierReplacements(sourceText) {
|
|
520
|
-
const sourceFile = ts2.createSourceFile("generated.js", sourceText, ts2.ScriptTarget.ES2022, true, ts2.ScriptKind.JS);
|
|
521
|
-
const replacements = [];
|
|
522
|
-
const visit = /* @__PURE__ */ __name((node) => {
|
|
523
|
-
if (ts2.isImportDeclaration(node) && ts2.isStringLiteralLike(node.moduleSpecifier)) {
|
|
524
|
-
this.scheduleReplacement(sourceFile, node.moduleSpecifier, replacements);
|
|
525
|
-
} else if (ts2.isExportDeclaration(node) && node.moduleSpecifier && ts2.isStringLiteralLike(node.moduleSpecifier)) {
|
|
526
|
-
this.scheduleReplacement(sourceFile, node.moduleSpecifier, replacements);
|
|
527
|
-
} else if (ts2.isCallExpression(node) && node.expression.kind === ts2.SyntaxKind.ImportKeyword && node.arguments.length === 1) {
|
|
528
|
-
const [arg] = node.arguments;
|
|
529
|
-
if (arg && ts2.isStringLiteralLike(arg)) {
|
|
530
|
-
this.scheduleReplacement(sourceFile, arg, replacements);
|
|
531
|
-
}
|
|
532
|
-
}
|
|
533
|
-
ts2.forEachChild(node, visit);
|
|
534
|
-
}, "visit");
|
|
535
|
-
visit(sourceFile);
|
|
536
|
-
return replacements;
|
|
537
|
-
}
|
|
538
|
-
scheduleReplacement(sourceFile, literal, replacements) {
|
|
539
|
-
const updated = this.appendJsExtension(literal.text);
|
|
540
|
-
if (updated === literal.text) return;
|
|
541
|
-
const literalText = literal.getText(sourceFile);
|
|
542
|
-
const quote = literalText.startsWith("`") ? "`" : literalText.startsWith("'") ? "'" : '"';
|
|
543
|
-
replacements.push({
|
|
544
|
-
start: literal.getStart(sourceFile),
|
|
545
|
-
end: literal.getEnd(),
|
|
546
|
-
text: `${quote}${updated}${quote}`
|
|
547
|
-
});
|
|
548
|
-
}
|
|
549
|
-
appendJsExtension(specifier) {
|
|
550
|
-
if (!specifier.startsWith("./") && !specifier.startsWith("../")) return specifier;
|
|
551
|
-
if (/\.(?:[cm]?js|json)$/i.test(specifier)) return specifier;
|
|
552
|
-
return `${specifier}.js`;
|
|
553
|
-
}
|
|
554
|
-
};
|
|
555
|
-
|
|
556
|
-
// src/builder/TypeScriptProjectBuilder.ts
|
|
557
|
-
var TypeScriptProjectBuilder = class {
|
|
558
|
-
static {
|
|
559
|
-
__name(this, "TypeScriptProjectBuilder");
|
|
560
|
-
}
|
|
561
|
-
logger;
|
|
562
|
-
entries;
|
|
563
|
-
specifierTransformer;
|
|
564
|
-
constructor(logger, entries = new EntryPointCollector(), specifierTransformer = new RelativeSpecifierTransformer()) {
|
|
565
|
-
this.logger = logger;
|
|
566
|
-
this.entries = entries;
|
|
567
|
-
this.specifierTransformer = specifierTransformer;
|
|
568
|
-
}
|
|
569
|
-
async build(config) {
|
|
570
|
-
const tsconfigPath = this.resolveTsconfig(config);
|
|
571
|
-
const { entryMap, primaryKey } = this.entries.collect(config, tsconfigPath);
|
|
572
|
-
this.logger.info(`Building Seedcord project via ${tsconfigPath}`);
|
|
573
|
-
try {
|
|
574
|
-
await build({
|
|
575
|
-
entry: entryMap,
|
|
576
|
-
outDir: config.build.outDir,
|
|
577
|
-
format: [
|
|
578
|
-
"esm"
|
|
579
|
-
],
|
|
580
|
-
outExtension: /* @__PURE__ */ __name(() => ({
|
|
581
|
-
js: ".js"
|
|
582
|
-
}), "outExtension"),
|
|
583
|
-
shims: false,
|
|
584
|
-
splitting: false,
|
|
585
|
-
sourcemap: true,
|
|
586
|
-
clean: false,
|
|
587
|
-
skipNodeModulesBundle: true,
|
|
588
|
-
minify: false,
|
|
589
|
-
bundle: false,
|
|
590
|
-
dts: false,
|
|
591
|
-
target: "node22",
|
|
592
|
-
platform: "node",
|
|
593
|
-
keepNames: true,
|
|
594
|
-
treeshake: false,
|
|
595
|
-
tsconfig: tsconfigPath,
|
|
596
|
-
silent: true
|
|
597
|
-
});
|
|
598
|
-
await this.specifierTransformer.transform(config.build.outDir);
|
|
599
|
-
} catch (error) {
|
|
600
|
-
const reason = error instanceof Error ? error.message : "Unknown build error";
|
|
601
|
-
throw new SeedcordError(SeedcordErrorCode.CliBuildFailed, [
|
|
602
|
-
reason
|
|
603
|
-
]);
|
|
604
|
-
}
|
|
605
|
-
const emittedEntry = this.resolveEmittedEntry(config.build.outDir, primaryKey);
|
|
606
|
-
if (!existsSync(emittedEntry)) {
|
|
607
|
-
throw new SeedcordError(SeedcordErrorCode.CliBuildFailed, [
|
|
608
|
-
`Expected output file ${emittedEntry} missing after build`
|
|
609
|
-
]);
|
|
610
|
-
}
|
|
611
|
-
this.logger.info(`Emitted entry: ${emittedEntry}`);
|
|
612
|
-
return {
|
|
613
|
-
emittedEntry
|
|
614
|
-
};
|
|
615
|
-
}
|
|
616
|
-
resolveTsconfig(config) {
|
|
617
|
-
if (config.build.tsconfig) {
|
|
618
|
-
if (!existsSync(config.build.tsconfig)) {
|
|
619
|
-
throw new SeedcordError(SeedcordErrorCode.CliBuildTsconfigNotFound, [
|
|
620
|
-
config.build.tsconfig
|
|
621
|
-
]);
|
|
622
|
-
}
|
|
623
|
-
return config.build.tsconfig;
|
|
624
|
-
}
|
|
625
|
-
const configDir = dirname(config.configFile);
|
|
626
|
-
const candidates = [
|
|
627
|
-
"tsconfig.build.json",
|
|
628
|
-
"tsconfig.json"
|
|
629
|
-
].map((file) => resolve(configDir, file)).filter((candidate) => existsSync(candidate));
|
|
630
|
-
const [firstCandidate] = candidates;
|
|
631
|
-
if (firstCandidate) return firstCandidate;
|
|
632
|
-
throw new SeedcordError(SeedcordErrorCode.CliBuildTsconfigNotFound, [
|
|
633
|
-
configDir
|
|
634
|
-
]);
|
|
635
|
-
}
|
|
636
|
-
resolveEmittedEntry(outDir, entryKey) {
|
|
637
|
-
return resolve(outDir, `${entryKey}.js`);
|
|
638
|
-
}
|
|
639
|
-
};
|
|
640
|
-
|
|
641
|
-
// src/runtime/SeedcordBuildRunner.ts
|
|
642
|
-
var SeedcordBuildRunner = class _SeedcordBuildRunner {
|
|
643
|
-
static {
|
|
644
|
-
__name(this, "SeedcordBuildRunner");
|
|
645
|
-
}
|
|
646
|
-
locator;
|
|
647
|
-
configLoader;
|
|
648
|
-
builder;
|
|
649
|
-
bootstrapWriter;
|
|
650
|
-
logger;
|
|
651
|
-
constructor(locator, configLoader, builder, bootstrapWriter, logger) {
|
|
652
|
-
this.locator = locator;
|
|
653
|
-
this.configLoader = configLoader;
|
|
654
|
-
this.builder = builder;
|
|
655
|
-
this.bootstrapWriter = bootstrapWriter;
|
|
656
|
-
this.logger = logger;
|
|
657
|
-
}
|
|
658
|
-
static create(logger) {
|
|
659
|
-
const moduleLoader = new RuntimeModuleLoader();
|
|
660
|
-
const locator = new ConfigLocator(logger);
|
|
661
|
-
const configLoader = new ConfigLoader(moduleLoader, logger);
|
|
662
|
-
const builder = new TypeScriptProjectBuilder(logger);
|
|
663
|
-
const bootstrapWriter = new BootstrapWriter(logger);
|
|
664
|
-
return new _SeedcordBuildRunner(locator, configLoader, builder, bootstrapWriter, logger);
|
|
665
|
-
}
|
|
666
|
-
async run() {
|
|
667
|
-
const config = await this.loadConfig();
|
|
668
|
-
this.assertEntryExists(config.entry);
|
|
669
|
-
const { emittedEntry } = await this.builder.build(config);
|
|
670
|
-
await this.bootstrapWriter.write(config, emittedEntry);
|
|
671
|
-
this.logger.info("Seedcord build finished successfully.");
|
|
672
|
-
}
|
|
673
|
-
async loadConfig() {
|
|
674
|
-
const configPath = this.locator.locate();
|
|
675
|
-
return this.configLoader.load(configPath);
|
|
676
|
-
}
|
|
677
|
-
assertEntryExists(entryPath) {
|
|
678
|
-
if (!existsSync(entryPath)) {
|
|
679
|
-
throw new SeedcordError(SeedcordErrorCode.CliEntryNotFound, [
|
|
680
|
-
entryPath
|
|
681
|
-
]);
|
|
682
|
-
}
|
|
683
|
-
}
|
|
684
|
-
};
|
|
685
|
-
|
|
686
|
-
// src/commands/BuildCommand.ts
|
|
687
|
-
var BuildCommand = class _BuildCommand {
|
|
688
|
-
static {
|
|
689
|
-
__name(this, "BuildCommand");
|
|
690
|
-
}
|
|
691
|
-
runner;
|
|
692
|
-
logger;
|
|
693
|
-
constructor(runner, logger) {
|
|
694
|
-
this.runner = runner;
|
|
695
|
-
this.logger = logger;
|
|
696
|
-
}
|
|
697
|
-
register(program) {
|
|
698
|
-
program.command("build").description("Compile a Seedcord project using seedcord.config.ts").action(async () => {
|
|
699
|
-
try {
|
|
700
|
-
await this.runner.run();
|
|
701
|
-
} catch (error) {
|
|
702
|
-
this.logger.error("Seedcord build failed", error);
|
|
703
|
-
if (isSeedcordError(error)) process.exitCode = 1;
|
|
704
|
-
else process.exit(1);
|
|
705
|
-
}
|
|
706
|
-
});
|
|
707
|
-
}
|
|
708
|
-
static create(logger) {
|
|
709
|
-
return new _BuildCommand(SeedcordBuildRunner.create(logger), logger);
|
|
710
|
-
}
|
|
711
|
-
};
|
|
712
|
-
|
|
713
|
-
// src/index.ts
|
|
714
|
-
var version = "0.0.1";
|
|
715
|
-
|
|
716
|
-
export { BootstrapWriter, BuildCommand, ConfigLoader, ConfigLocator, DevCommand, RuntimeModuleLoader, SEEDCORD_CONFIG_FILENAMES, SeedcordBuildRunner, SeedcordDevRunner, SeedcordInstanceLoader, TypeScriptProjectBuilder, defineConfig, resolveDefaultExport, version };
|
|
717
|
-
//# sourceMappingURL=index.mjs.map
|
|
718
|
-
//# sourceMappingURL=index.mjs.map
|
|
3
|
+
export { SEEDCORD_CONFIG_FILENAMES, defineConfig, version };
|