vantris 0.1.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/dist/chunk-PSXNP5S5.js +308 -0
- package/dist/chunk-PSXNP5S5.js.map +1 -0
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.js +22 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/index.d.ts +299 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/package.json +34 -0
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
import { pathToFileURL } from 'url';
|
|
2
|
+
import { stat, readFile, mkdir } from 'fs/promises';
|
|
3
|
+
import { isAbsolute, resolve, relative } from 'path';
|
|
4
|
+
|
|
5
|
+
// src/shared/constants.ts
|
|
6
|
+
var APP_NAME = "vantris";
|
|
7
|
+
var VERSION = "0.1.0";
|
|
8
|
+
var HTML_ENTRY_FILENAME = "index.html";
|
|
9
|
+
var DEFAULTS = {
|
|
10
|
+
root: ".",
|
|
11
|
+
rootDir: "./src",
|
|
12
|
+
publicDir: "./public",
|
|
13
|
+
outDir: "./dist"
|
|
14
|
+
};
|
|
15
|
+
var CONFIG_FILENAMES = [
|
|
16
|
+
"vantris.config.ts",
|
|
17
|
+
"vantris.config.js",
|
|
18
|
+
"vantris.config.mjs"
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
// src/shared/errors.ts
|
|
22
|
+
var VantrisError = class extends Error {
|
|
23
|
+
name = "VantrisError";
|
|
24
|
+
constructor(message, options) {
|
|
25
|
+
super(message, options);
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
var ConfigError = class extends VantrisError {
|
|
29
|
+
name = "ConfigError";
|
|
30
|
+
};
|
|
31
|
+
var HtmlEntryError = class extends VantrisError {
|
|
32
|
+
name = "HtmlEntryError";
|
|
33
|
+
};
|
|
34
|
+
var NotImplementedError = class extends VantrisError {
|
|
35
|
+
name = "NotImplementedError";
|
|
36
|
+
};
|
|
37
|
+
function isVantrisError(error) {
|
|
38
|
+
return error instanceof VantrisError;
|
|
39
|
+
}
|
|
40
|
+
async function isFile(path) {
|
|
41
|
+
try {
|
|
42
|
+
return (await stat(path)).isFile();
|
|
43
|
+
} catch {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function readTextFile(path) {
|
|
48
|
+
return readFile(path, "utf8");
|
|
49
|
+
}
|
|
50
|
+
async function ensureDir(path) {
|
|
51
|
+
await mkdir(path, { recursive: true });
|
|
52
|
+
}
|
|
53
|
+
function resolveFrom(base, target) {
|
|
54
|
+
return isAbsolute(target) ? target : resolve(base, target);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// src/config/load.ts
|
|
58
|
+
async function loadConfig(options) {
|
|
59
|
+
const { cwd, logger } = options;
|
|
60
|
+
const file = options.configFile ? resolveFrom(cwd, options.configFile) : await findConfigFile(cwd);
|
|
61
|
+
if (!file) {
|
|
62
|
+
logger.debug("No config file found; using defaults.");
|
|
63
|
+
return { config: {}, file: null };
|
|
64
|
+
}
|
|
65
|
+
logger.debug(`Loading config from ${file}`);
|
|
66
|
+
const config = await importConfig(file);
|
|
67
|
+
return { config, file };
|
|
68
|
+
}
|
|
69
|
+
async function findConfigFile(cwd) {
|
|
70
|
+
for (const name of CONFIG_FILENAMES) {
|
|
71
|
+
const candidate = resolveFrom(cwd, name);
|
|
72
|
+
if (await isFile(candidate)) return candidate;
|
|
73
|
+
}
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
async function importConfig(file) {
|
|
77
|
+
let mod;
|
|
78
|
+
try {
|
|
79
|
+
const url = `${pathToFileURL(file).href}?t=${Date.now()}`;
|
|
80
|
+
mod = await import(url);
|
|
81
|
+
} catch (cause) {
|
|
82
|
+
throw new ConfigError(`Failed to load config file: ${file}`, { cause });
|
|
83
|
+
}
|
|
84
|
+
const exported = mod.default;
|
|
85
|
+
if (exported === void 0) {
|
|
86
|
+
throw new ConfigError(
|
|
87
|
+
`Config file "${file}" has no default export. Export your config with \`export default defineConfig({ ... })\`.`
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
return normalise(exported, file);
|
|
91
|
+
}
|
|
92
|
+
async function normalise(input, file) {
|
|
93
|
+
const value = typeof input === "function" ? await input() : input;
|
|
94
|
+
if (value === null || typeof value !== "object") {
|
|
95
|
+
throw new ConfigError(
|
|
96
|
+
`Config file "${file}" must export an object (or a function returning one).`
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
return value;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// src/config/resolve.ts
|
|
103
|
+
function resolveConfig(raw, cwd, configFile = null) {
|
|
104
|
+
const root = resolveFrom(cwd, raw.root ?? DEFAULTS.root);
|
|
105
|
+
const paths = {
|
|
106
|
+
root,
|
|
107
|
+
rootDir: resolveFrom(root, raw.rootDir ?? DEFAULTS.rootDir),
|
|
108
|
+
publicDir: resolveFrom(root, raw.publicDir ?? DEFAULTS.publicDir),
|
|
109
|
+
outDir: resolveFrom(root, raw.outDir ?? DEFAULTS.outDir)
|
|
110
|
+
};
|
|
111
|
+
return { raw, paths, configFile };
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// src/html/parse.ts
|
|
115
|
+
function parseHtml(file, html) {
|
|
116
|
+
return { file, html };
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// src/html/detect.ts
|
|
120
|
+
async function detectHtmlEntry(root) {
|
|
121
|
+
const file = resolveFrom(root, HTML_ENTRY_FILENAME);
|
|
122
|
+
if (!await isFile(file)) return null;
|
|
123
|
+
const html = await readTextFile(file);
|
|
124
|
+
return parseHtml(file, html);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// src/shared/logger.ts
|
|
128
|
+
var prefix = `[${APP_NAME}]`;
|
|
129
|
+
function createLogger(options = {}) {
|
|
130
|
+
const { verbose = false, sink = console } = options;
|
|
131
|
+
return {
|
|
132
|
+
info(message) {
|
|
133
|
+
sink.log(`${prefix} ${message}`);
|
|
134
|
+
},
|
|
135
|
+
warn(message) {
|
|
136
|
+
sink.warn(`${prefix} ${message}`);
|
|
137
|
+
},
|
|
138
|
+
error(message) {
|
|
139
|
+
sink.error(`${prefix} ${message}`);
|
|
140
|
+
},
|
|
141
|
+
debug(message) {
|
|
142
|
+
if (verbose) sink.log(`${prefix} ${message}`);
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// src/shared/context.ts
|
|
148
|
+
async function createContext(options) {
|
|
149
|
+
const { cwd, logger } = options;
|
|
150
|
+
const loaded = await loadConfig({
|
|
151
|
+
cwd,
|
|
152
|
+
logger,
|
|
153
|
+
...options.configFile !== void 0 ? { configFile: options.configFile } : {}
|
|
154
|
+
});
|
|
155
|
+
const config = resolveConfig(loaded.config, cwd, loaded.file);
|
|
156
|
+
return { cwd, config, logger };
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// src/server/index.ts
|
|
160
|
+
async function startDevServer(options) {
|
|
161
|
+
const { ctx } = options;
|
|
162
|
+
ctx.logger.info(
|
|
163
|
+
"dev server is not implemented in v0.1.0 (planned: H3 + HMR)."
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
function rel(ctx, target) {
|
|
167
|
+
return relative(ctx.config.paths.root, target) || ".";
|
|
168
|
+
}
|
|
169
|
+
async function inspectProject(ctx) {
|
|
170
|
+
const { paths, configFile } = ctx.config;
|
|
171
|
+
ctx.logger.info(
|
|
172
|
+
`config: ${configFile ? rel(ctx, configFile) : "defaults (no config file)"}`
|
|
173
|
+
);
|
|
174
|
+
ctx.logger.info(`rootDir: ${rel(ctx, paths.rootDir)}`);
|
|
175
|
+
ctx.logger.info(`publicDir: ${rel(ctx, paths.publicDir)}`);
|
|
176
|
+
ctx.logger.info(`outDir: ${rel(ctx, paths.outDir)}`);
|
|
177
|
+
const entry = await detectHtmlEntry(paths.root);
|
|
178
|
+
if (entry) {
|
|
179
|
+
ctx.logger.info(`html entry: ${rel(ctx, entry.file)}`);
|
|
180
|
+
} else {
|
|
181
|
+
ctx.logger.warn(
|
|
182
|
+
"no index.html found at the project root; nothing to serve yet."
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
return entry;
|
|
186
|
+
}
|
|
187
|
+
async function prepareDirectories(ctx, dirs) {
|
|
188
|
+
for (const dir of dirs) {
|
|
189
|
+
await ensureDir(dir);
|
|
190
|
+
ctx.logger.debug(`prepared directory: ${dir}`);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// src/commands/dev.ts
|
|
195
|
+
var dev = {
|
|
196
|
+
name: "dev",
|
|
197
|
+
description: "Start the development server",
|
|
198
|
+
async run(ctx) {
|
|
199
|
+
const { rootDir, publicDir } = ctx.config.paths;
|
|
200
|
+
await prepareDirectories(ctx, [rootDir, publicDir]);
|
|
201
|
+
await inspectProject(ctx);
|
|
202
|
+
await startDevServer({ ctx});
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
// src/build/index.ts
|
|
207
|
+
async function runBuild(options) {
|
|
208
|
+
const { ctx } = options;
|
|
209
|
+
ctx.logger.info(
|
|
210
|
+
"build is not implemented in v0.1.0 (planned: Rolldown + esbuild)."
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// src/commands/build.ts
|
|
215
|
+
var build = {
|
|
216
|
+
name: "build",
|
|
217
|
+
description: "Build the project for production",
|
|
218
|
+
async run(ctx) {
|
|
219
|
+
const { rootDir, publicDir, outDir } = ctx.config.paths;
|
|
220
|
+
await prepareDirectories(ctx, [rootDir, publicDir, outDir]);
|
|
221
|
+
await inspectProject(ctx);
|
|
222
|
+
await runBuild({ ctx});
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
// src/preview/index.ts
|
|
227
|
+
async function runPreview(options) {
|
|
228
|
+
const { ctx } = options;
|
|
229
|
+
ctx.logger.info(
|
|
230
|
+
"preview is not implemented in v0.1.0 (planned: static server over outDir)."
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// src/commands/preview.ts
|
|
235
|
+
var preview = {
|
|
236
|
+
name: "preview",
|
|
237
|
+
description: "Locally preview a production build",
|
|
238
|
+
async run(ctx) {
|
|
239
|
+
await prepareDirectories(ctx, [ctx.config.paths.outDir]);
|
|
240
|
+
await inspectProject(ctx);
|
|
241
|
+
await runPreview({ ctx });
|
|
242
|
+
}
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
// src/commands/index.ts
|
|
246
|
+
var commands = {
|
|
247
|
+
[dev.name]: dev,
|
|
248
|
+
[build.name]: build,
|
|
249
|
+
[preview.name]: preview
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
// src/cli/help.ts
|
|
253
|
+
function helpText() {
|
|
254
|
+
const lines = [
|
|
255
|
+
`${APP_NAME} v${VERSION} \u2014 a modern bundler for JavaScript/TypeScript`,
|
|
256
|
+
"",
|
|
257
|
+
"Usage:",
|
|
258
|
+
` ${APP_NAME} <command> [options]`,
|
|
259
|
+
"",
|
|
260
|
+
"Commands:"
|
|
261
|
+
];
|
|
262
|
+
const width = Math.max(...Object.keys(commands).map((n) => n.length));
|
|
263
|
+
for (const command of Object.values(commands)) {
|
|
264
|
+
lines.push(` ${command.name.padEnd(width)} ${command.description}`);
|
|
265
|
+
}
|
|
266
|
+
lines.push(
|
|
267
|
+
"",
|
|
268
|
+
"Options:",
|
|
269
|
+
" -h, --help Show this help",
|
|
270
|
+
" -v, --version Show the version number"
|
|
271
|
+
);
|
|
272
|
+
return lines.join("\n");
|
|
273
|
+
}
|
|
274
|
+
function versionText() {
|
|
275
|
+
return `${APP_NAME} v${VERSION}`;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// src/cli/run.ts
|
|
279
|
+
async function run(argv, options = {}) {
|
|
280
|
+
const verbose = argv.includes("--verbose") || argv.includes("--debug");
|
|
281
|
+
const logger = options.logger ?? createLogger({ verbose });
|
|
282
|
+
const cwd = options.cwd ?? process.cwd();
|
|
283
|
+
const [first, ...rest] = argv.filter((arg) => !isGlobalFlag(arg));
|
|
284
|
+
if (!first || first === "--help" || first === "-h" || first === "help") {
|
|
285
|
+
logger.info(helpText());
|
|
286
|
+
return 0 /* Ok */;
|
|
287
|
+
}
|
|
288
|
+
if (first === "--version" || first === "-v") {
|
|
289
|
+
logger.info(versionText());
|
|
290
|
+
return 0 /* Ok */;
|
|
291
|
+
}
|
|
292
|
+
const command = commands[first];
|
|
293
|
+
if (!command) {
|
|
294
|
+
logger.error(`Unknown command: "${first}"`);
|
|
295
|
+
logger.info(helpText());
|
|
296
|
+
return 1 /* Error */;
|
|
297
|
+
}
|
|
298
|
+
const ctx = await createContext({ cwd, logger });
|
|
299
|
+
await command.run(ctx, rest);
|
|
300
|
+
return 0 /* Ok */;
|
|
301
|
+
}
|
|
302
|
+
function isGlobalFlag(arg) {
|
|
303
|
+
return arg === "--verbose" || arg === "--debug";
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
export { ConfigError, HtmlEntryError, NotImplementedError, VERSION, VantrisError, commands, createContext, createLogger, detectHtmlEntry, isVantrisError, loadConfig, parseHtml, resolveConfig, run };
|
|
307
|
+
//# sourceMappingURL=chunk-PSXNP5S5.js.map
|
|
308
|
+
//# sourceMappingURL=chunk-PSXNP5S5.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/shared/constants.ts","../src/shared/errors.ts","../src/utils/fs.ts","../src/utils/paths.ts","../src/config/load.ts","../src/config/resolve.ts","../src/html/parse.ts","../src/html/detect.ts","../src/shared/logger.ts","../src/shared/context.ts","../src/server/index.ts","../src/commands/support.ts","../src/commands/dev.ts","../src/build/index.ts","../src/commands/build.ts","../src/preview/index.ts","../src/commands/preview.ts","../src/commands/index.ts","../src/cli/help.ts","../src/cli/run.ts"],"names":[],"mappings":"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","file":"chunk-PSXNP5S5.js","sourcesContent":["/** Product name, used in CLI banners and logs. */\nexport const APP_NAME = \"vantris\";\n\n/** Current Vantris version. Kept in sync with package.json at release time. */\nexport const VERSION = \"0.1.0\";\n\n/** The HTML entry filename Vantris looks for at the project root. */\nexport const HTML_ENTRY_FILENAME = \"index.html\";\n\n/** Default directory values, relative to the project root. */\nexport const DEFAULTS = {\n root: \".\",\n rootDir: \"./src\",\n publicDir: \"./public\",\n outDir: \"./dist\",\n} as const;\n\n/** Config filenames Vantris will look for, in priority order. */\nexport const CONFIG_FILENAMES = [\n \"vantris.config.ts\",\n \"vantris.config.js\",\n \"vantris.config.mjs\",\n] as const;\n","/**\n * Base class for all errors thrown intentionally by Vantris. The CLI layer can\n * recognise these and render them cleanly (without a stack trace), while\n * unexpected errors keep their full trace.\n */\nexport class VantrisError extends Error {\n override readonly name: string = \"VantrisError\";\n\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n }\n}\n\n/** Thrown when configuration is missing, malformed, or fails to load. */\nexport class ConfigError extends VantrisError {\n override readonly name = \"ConfigError\";\n}\n\n/** Thrown when the project's HTML entry cannot be found. */\nexport class HtmlEntryError extends VantrisError {\n override readonly name = \"HtmlEntryError\";\n}\n\n/** Thrown for functionality declared but not yet implemented in this version. */\nexport class NotImplementedError extends VantrisError {\n override readonly name = \"NotImplementedError\";\n}\n\n/** Narrowing helper. */\nexport function isVantrisError(error: unknown): error is VantrisError {\n return error instanceof VantrisError;\n}\n","import { mkdir, readFile, stat } from \"node:fs/promises\";\n\n/** Returns `true` if `path` exists and is a regular file. */\nexport async function isFile(path: string): Promise<boolean> {\n try {\n return (await stat(path)).isFile();\n } catch {\n return false;\n }\n}\n\n/** Reads a UTF-8 text file. */\nexport function readTextFile(path: string): Promise<string> {\n return readFile(path, \"utf8\");\n}\n\n/** Creates a directory (and any missing parents) if it does not exist. */\nexport async function ensureDir(path: string): Promise<void> {\n await mkdir(path, { recursive: true });\n}\n","import { isAbsolute, resolve } from \"node:path\";\n\n/**\n * Resolves `target` against `base`, returning an absolute path.\n * Absolute targets are returned untouched.\n */\nexport function resolveFrom(base: string, target: string): string {\n return isAbsolute(target) ? target : resolve(base, target);\n}\n","import { pathToFileURL } from \"node:url\";\nimport type { Config, ConfigInput } from \"../types/config.js\";\nimport type { Logger } from \"../types/logger.js\";\nimport { CONFIG_FILENAMES } from \"../shared/constants.js\";\nimport { ConfigError } from \"../shared/errors.js\";\nimport { isFile } from \"../utils/fs.js\";\nimport { resolveFrom } from \"../utils/paths.js\";\n\nexport interface LoadConfigOptions {\n /** Directory to search for a config file. */\n cwd: string;\n /** Logger for diagnostics. */\n logger: Logger;\n /** Explicit config file path; bypasses filename discovery. */\n configFile?: string;\n}\n\nexport interface LoadedConfig {\n /** Parsed configuration. Empty object when no config file is present. */\n config: Config;\n /** Absolute path of the file that was loaded, or `null` when none. */\n file: string | null;\n}\n\n/**\n * Locates and loads a `vantris.config.*` file from `cwd`.\n *\n * The actual module evaluation is isolated here so the loading strategy\n * (native TS stripping today; a bundled loader such as esbuild/jiti later)\n * can change without affecting any caller. A missing config is not an error —\n * defaults take over downstream.\n */\nexport async function loadConfig(\n options: LoadConfigOptions,\n): Promise<LoadedConfig> {\n const { cwd, logger } = options;\n\n const file = options.configFile\n ? resolveFrom(cwd, options.configFile)\n : await findConfigFile(cwd);\n\n if (!file) {\n logger.debug(\"No config file found; using defaults.\");\n return { config: {}, file: null };\n }\n\n logger.debug(`Loading config from ${file}`);\n const config = await importConfig(file);\n return { config, file };\n}\n\n/** Returns the first existing config file in {@link CONFIG_FILENAMES}. */\nasync function findConfigFile(cwd: string): Promise<string | null> {\n for (const name of CONFIG_FILENAMES) {\n const candidate = resolveFrom(cwd, name);\n if (await isFile(candidate)) return candidate;\n }\n return null;\n}\n\n/**\n * Imports a config module and normalises its export to a {@link Config}.\n * Relies on the Node runtime's native TypeScript support for `.ts` files.\n */\nasync function importConfig(file: string): Promise<Config> {\n let mod: { default?: unknown };\n try {\n // Cache-bust so repeated loads (e.g. a future config-watch mode) re-read.\n const url = `${pathToFileURL(file).href}?t=${Date.now()}`;\n mod = (await import(url)) as { default?: unknown };\n } catch (cause) {\n throw new ConfigError(`Failed to load config file: ${file}`, { cause });\n }\n\n const exported = mod.default;\n if (exported === undefined) {\n throw new ConfigError(\n `Config file \"${file}\" has no default export. ` +\n `Export your config with \\`export default defineConfig({ ... })\\`.`,\n );\n }\n\n return normalise(exported as ConfigInput, file);\n}\n\n/** Resolves a {@link ConfigInput} (object or factory) into a {@link Config}. */\nasync function normalise(\n input: ConfigInput,\n file: string,\n): Promise<Config> {\n const value = typeof input === \"function\" ? await input() : input;\n\n if (value === null || typeof value !== \"object\") {\n throw new ConfigError(\n `Config file \"${file}\" must export an object (or a function returning one).`,\n );\n }\n\n return value;\n}\n","import type { Config } from \"../types/config.js\";\nimport type { ResolvedConfig } from \"../types/config-resolved.js\";\nimport type { ResolvedPaths } from \"../types/paths.js\";\nimport { DEFAULTS } from \"../shared/constants.js\";\nimport { resolveFrom } from \"../utils/paths.js\";\n\n/**\n * Applies defaults to a raw {@link Config} and resolves every directory to an\n * absolute path. This is the single source of truth for default values and\n * path resolution — no other module should re-derive these.\n *\n * @param raw User configuration (after loading; may be empty).\n * @param cwd Working directory the invocation started from.\n * @param configFile Absolute path of the loaded config file, or `null`.\n */\nexport function resolveConfig(\n raw: Config,\n cwd: string,\n configFile: string | null = null,\n): ResolvedConfig {\n const root = resolveFrom(cwd, raw.root ?? DEFAULTS.root);\n\n const paths: ResolvedPaths = {\n root,\n rootDir: resolveFrom(root, raw.rootDir ?? DEFAULTS.rootDir),\n publicDir: resolveFrom(root, raw.publicDir ?? DEFAULTS.publicDir),\n outDir: resolveFrom(root, raw.outDir ?? DEFAULTS.outDir),\n };\n\n return { raw, paths, configFile };\n}\n","import type { HtmlEntry } from \"../types/html.js\";\n\n/**\n * Parses raw HTML into an {@link HtmlEntry}.\n *\n * v0.1.0 keeps this intentionally minimal: it only wraps the file path and\n * contents. The function exists as the single, isolated home for HTML\n * analysis so later versions can grow it (extracting `<script type=\"module\">`\n * entries, asset references, injection points for HMR) without scattering\n * parsing logic across the codebase.\n */\nexport function parseHtml(file: string, html: string): HtmlEntry {\n return { file, html };\n}\n","import type { HtmlEntry } from \"../types/html.js\";\nimport { HTML_ENTRY_FILENAME } from \"../shared/constants.js\";\nimport { isFile, readTextFile } from \"../utils/fs.js\";\nimport { resolveFrom } from \"../utils/paths.js\";\nimport { parseHtml } from \"./parse.js\";\n\n/**\n * Locates the project's `index.html` entry at `root`.\n *\n * @returns The parsed {@link HtmlEntry}, or `null` if no entry exists.\n */\nexport async function detectHtmlEntry(root: string): Promise<HtmlEntry | null> {\n const file = resolveFrom(root, HTML_ENTRY_FILENAME);\n if (!(await isFile(file))) return null;\n\n const html = await readTextFile(file);\n return parseHtml(file, html);\n}\n","import type { Logger } from \"../types/logger.js\";\nimport { APP_NAME } from \"./constants.js\";\n\nexport interface LoggerOptions {\n /** When `false`, `debug` calls are dropped. @default false */\n verbose?: boolean;\n /** Sink for output. Defaults to the console; overridable for tests. */\n sink?: Pick<Console, \"log\" | \"warn\" | \"error\">;\n}\n\nconst prefix = `[${APP_NAME}]`;\n\n/**\n * Creates the default console-backed {@link Logger}.\n *\n * The sink is injectable so tests can capture output, and verbosity is a\n * construction-time concern rather than a global flag.\n */\nexport function createLogger(options: LoggerOptions = {}): Logger {\n const { verbose = false, sink = console } = options;\n\n return {\n info(message) {\n sink.log(`${prefix} ${message}`);\n },\n warn(message) {\n sink.warn(`${prefix} ${message}`);\n },\n error(message) {\n sink.error(`${prefix} ${message}`);\n },\n debug(message) {\n if (verbose) sink.log(`${prefix} ${message}`);\n },\n };\n}\n","import type { Context } from \"../types/context.js\";\nimport type { Logger } from \"../types/logger.js\";\nimport { loadConfig } from \"../config/load.js\";\nimport { resolveConfig } from \"../config/resolve.js\";\n\nexport interface CreateContextOptions {\n /** Working directory the command was invoked from. */\n cwd: string;\n /** Injected logger. */\n logger: Logger;\n /** Optional explicit config file path. */\n configFile?: string;\n}\n\n/**\n * Builds the {@link Context} shared by every command: it loads the user config,\n * applies defaults, resolves paths, and bundles the injected services.\n *\n * Centralising construction here means commands never reach for global state —\n * everything they need arrives through the returned context.\n */\nexport async function createContext(\n options: CreateContextOptions,\n): Promise<Context> {\n const { cwd, logger } = options;\n\n const loaded = await loadConfig({\n cwd,\n logger,\n ...(options.configFile !== undefined\n ? { configFile: options.configFile }\n : {}),\n });\n\n const config = resolveConfig(loaded.config, cwd, loaded.file);\n\n return { cwd, config, logger };\n}\n","import type { Context } from \"../types/context.js\";\nimport type { HtmlEntry } from \"../types/html.js\";\n\n/**\n * Options handed to the dev server. Kept here so the contract is stable before\n * the implementation lands.\n */\nexport interface DevServerOptions {\n ctx: Context;\n /** The detected HTML entry, when present. */\n entry: HtmlEntry | null;\n}\n\n/**\n * Starts the development server.\n *\n * Reserved for a future version (planned: an H3-based server with HMR). The\n * seam exists now so `commands/dev` can already delegate here; only this file\n * changes when the engine is implemented.\n */\nexport async function startDevServer(options: DevServerOptions): Promise<void> {\n const { ctx } = options;\n ctx.logger.info(\n \"dev server is not implemented in v0.1.0 (planned: H3 + HMR).\",\n );\n}\n","import { relative } from \"node:path\";\nimport type { Context } from \"../types/context.js\";\nimport type { HtmlEntry } from \"../types/html.js\";\nimport { detectHtmlEntry } from \"../html/index.js\";\nimport { ensureDir } from \"../utils/fs.js\";\n\n/** Renders a path relative to the project root for tidy log output. */\nfunction rel(ctx: Context, target: string): string {\n return relative(ctx.config.paths.root, target) || \".\";\n}\n\n/**\n * Logs the resolved configuration and detects the HTML entry — the shared\n * preamble every command runs before delegating to its (future) engine.\n *\n * @returns The detected HTML entry, or `null` when none exists.\n */\nexport async function inspectProject(ctx: Context): Promise<HtmlEntry | null> {\n const { paths, configFile } = ctx.config;\n\n ctx.logger.info(\n `config: ${configFile ? rel(ctx, configFile) : \"defaults (no config file)\"}`,\n );\n ctx.logger.info(`rootDir: ${rel(ctx, paths.rootDir)}`);\n ctx.logger.info(`publicDir: ${rel(ctx, paths.publicDir)}`);\n ctx.logger.info(`outDir: ${rel(ctx, paths.outDir)}`);\n\n const entry = await detectHtmlEntry(paths.root);\n if (entry) {\n ctx.logger.info(`html entry: ${rel(ctx, entry.file)}`);\n } else {\n ctx.logger.warn(\n \"no index.html found at the project root; nothing to serve yet.\",\n );\n }\n\n return entry;\n}\n\n/** Ensures the given directories exist, creating them as needed. */\nexport async function prepareDirectories(\n ctx: Context,\n dirs: readonly string[],\n): Promise<void> {\n for (const dir of dirs) {\n await ensureDir(dir);\n ctx.logger.debug(`prepared directory: ${dir}`);\n }\n}\n","import type { Command } from \"../types/command.js\";\nimport { startDevServer } from \"../server/index.js\";\nimport { inspectProject, prepareDirectories } from \"./support.js\";\n\n/** `vantris dev` — start the development server. */\nexport const dev: Command = {\n name: \"dev\",\n description: \"Start the development server\",\n async run(ctx) {\n const { rootDir, publicDir } = ctx.config.paths;\n await prepareDirectories(ctx, [rootDir, publicDir]);\n\n const entry = await inspectProject(ctx);\n await startDevServer({ ctx, entry });\n },\n};\n","import type { Context } from \"../types/context.js\";\nimport type { HtmlEntry } from \"../types/html.js\";\n\n/** Options handed to the build pipeline. */\nexport interface BuildOptions {\n ctx: Context;\n /** The detected HTML entry, when present. */\n entry: HtmlEntry | null;\n}\n\n/**\n * Produces a production build into `outDir`.\n *\n * Reserved for a future version (planned: Rolldown for bundling, esbuild for\n * transforms). The seam exists now so `commands/build` can already delegate\n * here; only this file changes when the engine is implemented.\n */\nexport async function runBuild(options: BuildOptions): Promise<void> {\n const { ctx } = options;\n ctx.logger.info(\n \"build is not implemented in v0.1.0 (planned: Rolldown + esbuild).\",\n );\n}\n","import type { Command } from \"../types/command.js\";\nimport { runBuild } from \"../build/index.js\";\nimport { inspectProject, prepareDirectories } from \"./support.js\";\n\n/** `vantris build` — produce a production build. */\nexport const build: Command = {\n name: \"build\",\n description: \"Build the project for production\",\n async run(ctx) {\n const { rootDir, publicDir, outDir } = ctx.config.paths;\n await prepareDirectories(ctx, [rootDir, publicDir, outDir]);\n\n const entry = await inspectProject(ctx);\n await runBuild({ ctx, entry });\n },\n};\n","import type { Context } from \"../types/context.js\";\n\n/** Options handed to the preview server. */\nexport interface PreviewOptions {\n ctx: Context;\n}\n\n/**\n * Serves a previously produced production build from `outDir`.\n *\n * Reserved for a future version (planned: a static server over the build\n * output). The seam exists now so `commands/preview` can already delegate\n * here; only this file changes when the engine is implemented.\n */\nexport async function runPreview(options: PreviewOptions): Promise<void> {\n const { ctx } = options;\n ctx.logger.info(\n \"preview is not implemented in v0.1.0 (planned: static server over outDir).\",\n );\n}\n","import type { Command } from \"../types/command.js\";\nimport { runPreview } from \"../preview/index.js\";\nimport { inspectProject, prepareDirectories } from \"./support.js\";\n\n/** `vantris preview` — serve a production build locally. */\nexport const preview: Command = {\n name: \"preview\",\n description: \"Locally preview a production build\",\n async run(ctx) {\n await prepareDirectories(ctx, [ctx.config.paths.outDir]);\n\n await inspectProject(ctx);\n await runPreview({ ctx });\n },\n};\n","import type { Command } from \"../types/command.js\";\nimport { dev } from \"./dev.js\";\nimport { build } from \"./build.js\";\nimport { preview } from \"./preview.js\";\n\n/**\n * The command registry. The CLI routes purely against this map, so adding a\n * command is a one-line registration here plus its module — no CLI changes.\n */\nexport const commands: Readonly<Record<string, Command>> = {\n [dev.name]: dev,\n [build.name]: build,\n [preview.name]: preview,\n};\n\nexport type CommandName = keyof typeof commands;\n\nexport { dev, build, preview };\n","import { commands } from \"../commands/index.js\";\nimport { APP_NAME, VERSION } from \"../shared/constants.js\";\n\n/** Builds the help text listing every registered command. */\nexport function helpText(): string {\n const lines = [\n `${APP_NAME} v${VERSION} — a modern bundler for JavaScript/TypeScript`,\n \"\",\n \"Usage:\",\n ` ${APP_NAME} <command> [options]`,\n \"\",\n \"Commands:\",\n ];\n\n const width = Math.max(...Object.keys(commands).map((n) => n.length));\n for (const command of Object.values(commands)) {\n lines.push(` ${command.name.padEnd(width)} ${command.description}`);\n }\n\n lines.push(\n \"\",\n \"Options:\",\n \" -h, --help Show this help\",\n \" -v, --version Show the version number\",\n );\n\n return lines.join(\"\\n\");\n}\n\n/** Builds the version line. */\nexport function versionText(): string {\n return `${APP_NAME} v${VERSION}`;\n}\n","import type { Logger } from \"../types/logger.js\";\nimport { commands } from \"../commands/index.js\";\nimport { createContext } from \"../shared/context.js\";\nimport { createLogger } from \"../shared/logger.js\";\nimport { helpText, versionText } from \"./help.js\";\n\nexport interface RunOptions {\n /** Working directory; defaults to `process.cwd()`. */\n cwd?: string;\n /** Logger override, primarily for tests. */\n logger?: Logger;\n}\n\n/** Process exit codes used by the CLI. */\nexport const enum ExitCode {\n Ok = 0,\n Error = 1,\n}\n\n/**\n * Parses arguments and routes to a command. This is the entire CLI surface:\n * it owns argument handling and dispatch only — never command behaviour, which\n * lives behind the {@link commands} registry.\n *\n * @returns A process exit code.\n */\nexport async function run(\n argv: readonly string[],\n options: RunOptions = {},\n): Promise<ExitCode> {\n const verbose = argv.includes(\"--verbose\") || argv.includes(\"--debug\");\n const logger = options.logger ?? createLogger({ verbose });\n const cwd = options.cwd ?? process.cwd();\n\n const [first, ...rest] = argv.filter((arg) => !isGlobalFlag(arg));\n\n if (!first || first === \"--help\" || first === \"-h\" || first === \"help\") {\n logger.info(helpText());\n return ExitCode.Ok;\n }\n\n if (first === \"--version\" || first === \"-v\") {\n logger.info(versionText());\n return ExitCode.Ok;\n }\n\n const command = commands[first];\n if (!command) {\n logger.error(`Unknown command: \"${first}\"`);\n logger.info(helpText());\n return ExitCode.Error;\n }\n\n const ctx = await createContext({ cwd, logger });\n await command.run(ctx, rest);\n return ExitCode.Ok;\n}\n\n/** Flags handled by the runner itself rather than passed to commands. */\nfunction isGlobalFlag(arg: string): boolean {\n return arg === \"--verbose\" || arg === \"--debug\";\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { run, createLogger, isVantrisError } from '../chunk-PSXNP5S5.js';
|
|
3
|
+
|
|
4
|
+
// src/cli/index.ts
|
|
5
|
+
async function main() {
|
|
6
|
+
try {
|
|
7
|
+
const code = await run(process.argv.slice(2));
|
|
8
|
+
process.exitCode = code;
|
|
9
|
+
} catch (error) {
|
|
10
|
+
const logger = createLogger();
|
|
11
|
+
if (isVantrisError(error)) {
|
|
12
|
+
logger.error(error.message);
|
|
13
|
+
} else {
|
|
14
|
+
logger.error("An unexpected error occurred:");
|
|
15
|
+
logger.error(error instanceof Error ? error.stack ?? error.message : String(error));
|
|
16
|
+
}
|
|
17
|
+
process.exitCode = 1 /* Error */;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
void main();
|
|
21
|
+
//# sourceMappingURL=index.js.map
|
|
22
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/cli/index.ts"],"names":[],"mappings":";;;;AASA,eAAe,IAAA,GAAsB;AACnC,EAAA,IAAI;AACF,IAAA,MAAM,OAAO,MAAM,GAAA,CAAI,QAAQ,IAAA,CAAK,KAAA,CAAM,CAAC,CAAC,CAAA;AAC5C,IAAA,OAAA,CAAQ,QAAA,GAAW,IAAA;AAAA,EACrB,SAAS,KAAA,EAAO;AACd,IAAA,MAAM,SAAS,YAAA,EAAa;AAC5B,IAAA,IAAI,cAAA,CAAe,KAAK,CAAA,EAAG;AAEzB,MAAA,MAAA,CAAO,KAAA,CAAM,MAAM,OAAO,CAAA;AAAA,IAC5B,CAAA,MAAO;AACL,MAAA,MAAA,CAAO,MAAM,+BAA+B,CAAA;AAC5C,MAAA,MAAA,CAAO,KAAA,CAAM,iBAAiB,KAAA,GAAS,KAAA,CAAM,SAAS,KAAA,CAAM,OAAA,GAAW,MAAA,CAAO,KAAK,CAAC,CAAA;AAAA,IACtF;AACA,IAAA,OAAA,CAAQ,QAAA,GAAA,CAAA;AAAA,EACV;AACF;AAEA,KAAK,IAAA,EAAK","file":"index.js","sourcesContent":["#!/usr/bin/env node\nimport { createLogger } from \"../shared/logger.js\";\nimport { isVantrisError } from \"../shared/errors.js\";\nimport { ExitCode, run } from \"./run.js\";\n\n/**\n * Binary entry point. Owns process concerns only — argv intake, exit codes,\n * and top-level error rendering — and delegates all routing to {@link run}.\n */\nasync function main(): Promise<void> {\n try {\n const code = await run(process.argv.slice(2));\n process.exitCode = code;\n } catch (error) {\n const logger = createLogger();\n if (isVantrisError(error)) {\n // Expected, user-facing failures: show the message, skip the stack.\n logger.error(error.message);\n } else {\n logger.error(\"An unexpected error occurred:\");\n logger.error(error instanceof Error ? (error.stack ?? error.message) : String(error));\n }\n process.exitCode = ExitCode.Error;\n }\n}\n\nvoid main();\n"]}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public, user-facing configuration for Vantris.
|
|
3
|
+
*
|
|
4
|
+
* Every field is optional: a project with zero configuration must still build
|
|
5
|
+
* and run using the documented defaults. This interface is intentionally the
|
|
6
|
+
* single extension point through which future versions will grow (plugins,
|
|
7
|
+
* build options, HMR, server tuning, …) without breaking existing configs.
|
|
8
|
+
*/
|
|
9
|
+
interface Config {
|
|
10
|
+
/**
|
|
11
|
+
* Project root. Resolved relative to the current working directory.
|
|
12
|
+
* The `index.html` entry and every other directory below are resolved
|
|
13
|
+
* relative to this root.
|
|
14
|
+
*
|
|
15
|
+
* @default "."
|
|
16
|
+
*/
|
|
17
|
+
root?: string;
|
|
18
|
+
/**
|
|
19
|
+
* Directory containing application source files.
|
|
20
|
+
*
|
|
21
|
+
* @default "./src"
|
|
22
|
+
*/
|
|
23
|
+
rootDir?: string;
|
|
24
|
+
/**
|
|
25
|
+
* Directory of static assets served as-is (copied verbatim on build).
|
|
26
|
+
*
|
|
27
|
+
* @default "./public"
|
|
28
|
+
*/
|
|
29
|
+
publicDir?: string;
|
|
30
|
+
/**
|
|
31
|
+
* Output directory for production builds.
|
|
32
|
+
*
|
|
33
|
+
* @default "./dist"
|
|
34
|
+
*/
|
|
35
|
+
outDir?: string;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* A factory form of {@link Config}. Supporting a function (sync or async)
|
|
39
|
+
* lets configs react to environment/CLI input in later versions without an
|
|
40
|
+
* API change.
|
|
41
|
+
*/
|
|
42
|
+
type ConfigFn = () => Config | Promise<Config>;
|
|
43
|
+
/** Anything accepted by {@link defineConfig}. */
|
|
44
|
+
type ConfigInput = Config | ConfigFn;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Identity helper that gives config authors full type-checking and
|
|
48
|
+
* autocompletion in `vantris.config.ts` / `vantris.config.js`.
|
|
49
|
+
*
|
|
50
|
+
* Accepts either a {@link Config} object or a (possibly async) factory, so the
|
|
51
|
+
* same entry point keeps working as configuration grows more dynamic.
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```ts
|
|
55
|
+
* import { defineConfig } from "vantris";
|
|
56
|
+
*
|
|
57
|
+
* export default defineConfig({
|
|
58
|
+
* rootDir: "./src",
|
|
59
|
+
* outDir: "./dist",
|
|
60
|
+
* });
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
declare function defineConfig(config: Config): Config;
|
|
64
|
+
declare function defineConfig(config: ConfigInput): ConfigInput;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Minimal logging contract injected throughout Vantris.
|
|
68
|
+
*
|
|
69
|
+
* Depending on an interface (rather than calling `console` directly) keeps the
|
|
70
|
+
* core testable and lets future versions swap in a richer, level-aware logger
|
|
71
|
+
* without touching call sites.
|
|
72
|
+
*/
|
|
73
|
+
interface Logger {
|
|
74
|
+
info(message: string): void;
|
|
75
|
+
warn(message: string): void;
|
|
76
|
+
error(message: string): void;
|
|
77
|
+
/** Verbose diagnostics; may be a no-op depending on configuration. */
|
|
78
|
+
debug(message: string): void;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
interface LoadConfigOptions {
|
|
82
|
+
/** Directory to search for a config file. */
|
|
83
|
+
cwd: string;
|
|
84
|
+
/** Logger for diagnostics. */
|
|
85
|
+
logger: Logger;
|
|
86
|
+
/** Explicit config file path; bypasses filename discovery. */
|
|
87
|
+
configFile?: string;
|
|
88
|
+
}
|
|
89
|
+
interface LoadedConfig {
|
|
90
|
+
/** Parsed configuration. Empty object when no config file is present. */
|
|
91
|
+
config: Config;
|
|
92
|
+
/** Absolute path of the file that was loaded, or `null` when none. */
|
|
93
|
+
file: string | null;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Locates and loads a `vantris.config.*` file from `cwd`.
|
|
97
|
+
*
|
|
98
|
+
* The actual module evaluation is isolated here so the loading strategy
|
|
99
|
+
* (native TS stripping today; a bundled loader such as esbuild/jiti later)
|
|
100
|
+
* can change without affecting any caller. A missing config is not an error —
|
|
101
|
+
* defaults take over downstream.
|
|
102
|
+
*/
|
|
103
|
+
declare function loadConfig(options: LoadConfigOptions): Promise<LoadedConfig>;
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Fully resolved, absolute filesystem paths derived from a {@link Config}.
|
|
107
|
+
*
|
|
108
|
+
* Commands and subsystems should depend on this resolved shape rather than on
|
|
109
|
+
* the raw user config, so that path resolution lives in exactly one place.
|
|
110
|
+
*/
|
|
111
|
+
interface ResolvedPaths {
|
|
112
|
+
/** Absolute project root. */
|
|
113
|
+
root: string;
|
|
114
|
+
/** Absolute source directory. */
|
|
115
|
+
rootDir: string;
|
|
116
|
+
/** Absolute public/static directory. */
|
|
117
|
+
publicDir: string;
|
|
118
|
+
/** Absolute build output directory. */
|
|
119
|
+
outDir: string;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* A {@link Config} after defaults have been applied and paths resolved.
|
|
124
|
+
*
|
|
125
|
+
* This is what the rest of the system consumes. Keeping it separate from the
|
|
126
|
+
* user-facing {@link Config} means defaults and resolution rules can evolve
|
|
127
|
+
* without forcing optionality onto every internal consumer.
|
|
128
|
+
*/
|
|
129
|
+
interface ResolvedConfig {
|
|
130
|
+
/** The raw configuration as authored by the user (post-normalisation). */
|
|
131
|
+
readonly raw: Config;
|
|
132
|
+
/** Absolute paths derived from the configuration. */
|
|
133
|
+
readonly paths: ResolvedPaths;
|
|
134
|
+
/** Absolute path of the config file that was loaded, if any. */
|
|
135
|
+
readonly configFile: string | null;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Applies defaults to a raw {@link Config} and resolves every directory to an
|
|
140
|
+
* absolute path. This is the single source of truth for default values and
|
|
141
|
+
* path resolution — no other module should re-derive these.
|
|
142
|
+
*
|
|
143
|
+
* @param raw User configuration (after loading; may be empty).
|
|
144
|
+
* @param cwd Working directory the invocation started from.
|
|
145
|
+
* @param configFile Absolute path of the loaded config file, or `null`.
|
|
146
|
+
*/
|
|
147
|
+
declare function resolveConfig(raw: Config, cwd: string, configFile?: string | null): ResolvedConfig;
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* The HTML entry point of a project, as discovered and parsed by the
|
|
151
|
+
* `html` subsystem. Parsing is deliberately minimal in v0.1.0 — only what is
|
|
152
|
+
* needed to locate the entry — but the shape anticipates richer analysis
|
|
153
|
+
* (script tags, module graph roots, asset references) in later versions.
|
|
154
|
+
*/
|
|
155
|
+
interface HtmlEntry {
|
|
156
|
+
/** Absolute path to the `index.html` file. */
|
|
157
|
+
file: string;
|
|
158
|
+
/** Raw HTML contents. */
|
|
159
|
+
html: string;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Locates the project's `index.html` entry at `root`.
|
|
164
|
+
*
|
|
165
|
+
* @returns The parsed {@link HtmlEntry}, or `null` if no entry exists.
|
|
166
|
+
*/
|
|
167
|
+
declare function detectHtmlEntry(root: string): Promise<HtmlEntry | null>;
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Parses raw HTML into an {@link HtmlEntry}.
|
|
171
|
+
*
|
|
172
|
+
* v0.1.0 keeps this intentionally minimal: it only wraps the file path and
|
|
173
|
+
* contents. The function exists as the single, isolated home for HTML
|
|
174
|
+
* analysis so later versions can grow it (extracting `<script type="module">`
|
|
175
|
+
* entries, asset references, injection points for HMR) without scattering
|
|
176
|
+
* parsing logic across the codebase.
|
|
177
|
+
*/
|
|
178
|
+
declare function parseHtml(file: string, html: string): HtmlEntry;
|
|
179
|
+
|
|
180
|
+
/** Current Vantris version. Kept in sync with package.json at release time. */
|
|
181
|
+
declare const VERSION = "0.1.0";
|
|
182
|
+
|
|
183
|
+
interface LoggerOptions {
|
|
184
|
+
/** When `false`, `debug` calls are dropped. @default false */
|
|
185
|
+
verbose?: boolean;
|
|
186
|
+
/** Sink for output. Defaults to the console; overridable for tests. */
|
|
187
|
+
sink?: Pick<Console, "log" | "warn" | "error">;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Creates the default console-backed {@link Logger}.
|
|
191
|
+
*
|
|
192
|
+
* The sink is injectable so tests can capture output, and verbosity is a
|
|
193
|
+
* construction-time concern rather than a global flag.
|
|
194
|
+
*/
|
|
195
|
+
declare function createLogger(options?: LoggerOptions): Logger;
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* The execution context threaded into every command.
|
|
199
|
+
*
|
|
200
|
+
* It bundles the resolved configuration and the injected services a command
|
|
201
|
+
* may need. Commands receive everything they depend on through this object —
|
|
202
|
+
* there is no hidden global state — which keeps them pure and testable.
|
|
203
|
+
*/
|
|
204
|
+
interface Context {
|
|
205
|
+
/** Absolute working directory the invocation started from. */
|
|
206
|
+
readonly cwd: string;
|
|
207
|
+
/** Resolved configuration (defaults applied, paths absolute). */
|
|
208
|
+
readonly config: ResolvedConfig;
|
|
209
|
+
/** Injected logger. */
|
|
210
|
+
readonly logger: Logger;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
interface CreateContextOptions {
|
|
214
|
+
/** Working directory the command was invoked from. */
|
|
215
|
+
cwd: string;
|
|
216
|
+
/** Injected logger. */
|
|
217
|
+
logger: Logger;
|
|
218
|
+
/** Optional explicit config file path. */
|
|
219
|
+
configFile?: string;
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Builds the {@link Context} shared by every command: it loads the user config,
|
|
223
|
+
* applies defaults, resolves paths, and bundles the injected services.
|
|
224
|
+
*
|
|
225
|
+
* Centralising construction here means commands never reach for global state —
|
|
226
|
+
* everything they need arrives through the returned context.
|
|
227
|
+
*/
|
|
228
|
+
declare function createContext(options: CreateContextOptions): Promise<Context>;
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Base class for all errors thrown intentionally by Vantris. The CLI layer can
|
|
232
|
+
* recognise these and render them cleanly (without a stack trace), while
|
|
233
|
+
* unexpected errors keep their full trace.
|
|
234
|
+
*/
|
|
235
|
+
declare class VantrisError extends Error {
|
|
236
|
+
readonly name: string;
|
|
237
|
+
constructor(message: string, options?: ErrorOptions);
|
|
238
|
+
}
|
|
239
|
+
/** Thrown when configuration is missing, malformed, or fails to load. */
|
|
240
|
+
declare class ConfigError extends VantrisError {
|
|
241
|
+
readonly name = "ConfigError";
|
|
242
|
+
}
|
|
243
|
+
/** Thrown when the project's HTML entry cannot be found. */
|
|
244
|
+
declare class HtmlEntryError extends VantrisError {
|
|
245
|
+
readonly name = "HtmlEntryError";
|
|
246
|
+
}
|
|
247
|
+
/** Thrown for functionality declared but not yet implemented in this version. */
|
|
248
|
+
declare class NotImplementedError extends VantrisError {
|
|
249
|
+
readonly name = "NotImplementedError";
|
|
250
|
+
}
|
|
251
|
+
/** Narrowing helper. */
|
|
252
|
+
declare function isVantrisError(error: unknown): error is VantrisError;
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* A single CLI command. The CLI layer only knows about this contract; it never
|
|
256
|
+
* contains command logic itself. New commands are added by implementing this
|
|
257
|
+
* interface and registering them — no CLI refactor required.
|
|
258
|
+
*/
|
|
259
|
+
interface Command {
|
|
260
|
+
/** Invocation name, e.g. `"dev"`. */
|
|
261
|
+
readonly name: string;
|
|
262
|
+
/** One-line description shown in help output. */
|
|
263
|
+
readonly description: string;
|
|
264
|
+
/**
|
|
265
|
+
* Execute the command.
|
|
266
|
+
*
|
|
267
|
+
* @param ctx Fully-built execution context.
|
|
268
|
+
* @param args Remaining positional/flag arguments after the command name.
|
|
269
|
+
*/
|
|
270
|
+
run(ctx: Context, args: readonly string[]): Promise<void> | void;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* The command registry. The CLI routes purely against this map, so adding a
|
|
275
|
+
* command is a one-line registration here plus its module — no CLI changes.
|
|
276
|
+
*/
|
|
277
|
+
declare const commands: Readonly<Record<string, Command>>;
|
|
278
|
+
|
|
279
|
+
interface RunOptions {
|
|
280
|
+
/** Working directory; defaults to `process.cwd()`. */
|
|
281
|
+
cwd?: string;
|
|
282
|
+
/** Logger override, primarily for tests. */
|
|
283
|
+
logger?: Logger;
|
|
284
|
+
}
|
|
285
|
+
/** Process exit codes used by the CLI. */
|
|
286
|
+
declare const enum ExitCode {
|
|
287
|
+
Ok = 0,
|
|
288
|
+
Error = 1
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Parses arguments and routes to a command. This is the entire CLI surface:
|
|
292
|
+
* it owns argument handling and dispatch only — never command behaviour, which
|
|
293
|
+
* lives behind the {@link commands} registry.
|
|
294
|
+
*
|
|
295
|
+
* @returns A process exit code.
|
|
296
|
+
*/
|
|
297
|
+
declare function run(argv: readonly string[], options?: RunOptions): Promise<ExitCode>;
|
|
298
|
+
|
|
299
|
+
export { type Command, type Config, ConfigError, type ConfigFn, type ConfigInput, type Context, type HtmlEntry, HtmlEntryError, type Logger, NotImplementedError, type ResolvedConfig, type ResolvedPaths, VERSION, VantrisError, commands, createContext, createLogger, defineConfig, detectHtmlEntry, isVantrisError, loadConfig, parseHtml, resolveConfig, run };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { ConfigError, HtmlEntryError, NotImplementedError, VERSION, VantrisError, commands, createContext, createLogger, detectHtmlEntry, isVantrisError, loadConfig, parseHtml, resolveConfig, run } from './chunk-PSXNP5S5.js';
|
|
2
|
+
|
|
3
|
+
// src/config/define-config.ts
|
|
4
|
+
function defineConfig(config) {
|
|
5
|
+
return config;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export { defineConfig };
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/config/define-config.ts"],"names":[],"mappings":";;;AAqBO,SAAS,aAAa,MAAA,EAAkC;AAC7D,EAAA,OAAO,MAAA;AACT","file":"index.js","sourcesContent":["import type { Config, ConfigInput } from \"../types/config.js\";\n\n/**\n * Identity helper that gives config authors full type-checking and\n * autocompletion in `vantris.config.ts` / `vantris.config.js`.\n *\n * Accepts either a {@link Config} object or a (possibly async) factory, so the\n * same entry point keeps working as configuration grows more dynamic.\n *\n * @example\n * ```ts\n * import { defineConfig } from \"vantris\";\n *\n * export default defineConfig({\n * rootDir: \"./src\",\n * outDir: \"./dist\",\n * });\n * ```\n */\nexport function defineConfig(config: Config): Config;\nexport function defineConfig(config: ConfigInput): ConfigInput;\nexport function defineConfig(config: ConfigInput): ConfigInput {\n return config;\n}\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "vantris",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "A modern bundler for JavaScript/TypeScript",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"keywords": ["bundler", "build-tool", "dev-server", "typescript"],
|
|
8
|
+
"bin": {
|
|
9
|
+
"vantris": "dist/cli/index.js"
|
|
10
|
+
},
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"import": "./dist/index.js"
|
|
15
|
+
},
|
|
16
|
+
"./package.json": "./package.json"
|
|
17
|
+
},
|
|
18
|
+
"main": "./dist/index.js",
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"files": ["dist"],
|
|
21
|
+
"engines": {
|
|
22
|
+
"node": ">=20.11.0"
|
|
23
|
+
},
|
|
24
|
+
"scripts": {
|
|
25
|
+
"build": "tsup",
|
|
26
|
+
"dev": "tsup --watch",
|
|
27
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
28
|
+
"clean": "rm -rf dist",
|
|
29
|
+
"prepublishOnly": "pnpm run build"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"tsup": "^8.3.5"
|
|
33
|
+
}
|
|
34
|
+
}
|