@raven-js/fledge
Version:
From nestling to flight-ready - Build & bundle tool for modern JavaScript apps
225 lines (196 loc) • 5.51 kB
JavaScript
/**
* @author Anonyfox <max@anonyfox.com>
* @license MIT
* @see {@link https://ravenjs.dev}
* @see {@link https://github.com/Anonyfox/ravenjs}
* @see {@link https://anonyfox.com}
*/
/**
* @file Main configuration class for script mode bundling.
*
* Orchestrates script generation configuration with validation, defaults, and
* factory methods for creating instances from various sources.
*/
import { Assets } from "./assets.js";
import { Environment } from "./environment.js";
import {
importConfigFromFile,
importConfigFromString,
validateConfigObject,
} from "./import-config.js";
import { Metadata } from "./metadata.js";
/**
* @typedef {function({ port: number }): Promise<void>} ServerBootFunction
*/
/**
* Script bundling configuration with validation and defaults
*/
export class ScriptConfig {
/**
* Entry point file path - required
* @type {string}
*/
entry;
/**
* Output executable file path - required
* @type {string}
*/
output;
/**
* Module format for bundling
* @type {"cjs" | "esm"}
*/
format;
/**
* Node.js runtime flags
* @type {string[]}
*/
nodeFlags;
/**
* Client bundles to build and embed
* @type {Record<string, string>}
*/
bundles;
/**
* Assets to embed in executable
* @type {Assets}
*/
assets;
/**
* Environment variables to embed
* @type {Environment}
*/
env;
/**
* Banner metadata for executable
* @type {Metadata}
*/
metadata;
/**
* Create ScriptConfig instance
* @param {Object} config - Configuration object
* @param {string} config.entry - Entry point file path
* @param {string} config.output - Output executable file path
* @param {"cjs" | "esm"} [config.format="cjs"] - Module format
* @param {string[]} [config.nodeFlags=[]] - Node.js runtime flags
* @param {Record<string, string>} [config.bundles={}] - Client bundles
* @param {Assets} [config.assets] - Assets instance
* @param {Environment} [config.env] - Environment instance
* @param {Metadata} [config.metadata] - Metadata instance
*/
constructor(config) {
// Validate configuration object
validateConfigObject(config);
// Required fields
this.entry = config.entry;
this.output = config.output;
// Optional fields with defaults
this.format = config.format || "cjs";
this.nodeFlags = config.nodeFlags || [];
this.bundles = config.bundles || {};
// Complex fields - expect instances or create defaults
this.assets = config.assets || new Assets([]);
this.env = config.env || new Environment({});
this.metadata = config.metadata || Metadata.fromPackageJson();
}
/**
* Create config from JavaScript string (piped input)
* @param {string} configString - JavaScript configuration code
* @param {string} [exportName] - Optional named export to select (uses default if not specified)
* @returns {Promise<ScriptConfig>} ScriptConfig instance
* @throws {Error} If string parsing or validation fails
*/
static async fromString(configString, exportName) {
const configObject = await importConfigFromString(configString, exportName);
return await ScriptConfig.fromObject(configObject);
}
/**
* Create config from JavaScript file
* @param {string} configPath - Path to configuration file
* @param {string} [exportName] - Optional named export to select (uses default if not specified)
* @returns {Promise<ScriptConfig>} ScriptConfig instance
* @throws {Error} If file doesn't exist or validation fails
*/
static async fromFile(configPath, exportName) {
const configObject = await importConfigFromFile(configPath, exportName);
return await ScriptConfig.fromObject(configObject);
}
/**
* Create config from object (for programmatic usage)
* @param {Object} configObject - Configuration object
* @returns {Promise<ScriptConfig>} ScriptConfig instance
* @throws {Error} If validation fails
*/
static async fromObject(configObject) {
// Resolve complex fields asynchronously
const config = /** @type {any} */ (configObject);
const assets = await Assets.resolve(config.assets);
const env = await Environment.resolve(config.env);
const metadata = Metadata.fromPackageJson(config.metadata);
// Create final config with resolved instances
const resolvedConfig = {
...config,
assets,
env,
metadata,
};
return new ScriptConfig(/** @type {any} */ (resolvedConfig));
}
/**
* Get entry point file path
* @returns {string} Entry point path
*/
getEntry() {
return this.entry;
}
/**
* Get output executable file path
* @returns {string} Output path
*/
getOutput() {
return this.output;
}
/**
* Get module format
* @returns {"cjs" | "esm"} Module format
*/
getFormat() {
return this.format;
}
/**
* Get Node.js runtime flags (includes default --experimental-sqlite)
* @returns {string[]} Runtime flags array
*/
getNodeFlags() {
const defaultFlags = ["--experimental-sqlite"];
return [...defaultFlags, ...this.nodeFlags];
}
/**
* Get client bundles configuration
* @returns {Record<string, string>} Mount path to source file mapping
*/
getBundles() {
return this.bundles;
}
/**
* Get assets configuration
* @returns {Assets} Assets instance
*/
getAssets() {
return this.assets;
}
/**
* Get environment configuration
* @returns {Environment} Environment instance
*/
getEnvironment() {
return this.env;
}
/**
* Get metadata configuration
* @returns {Metadata} Metadata instance
*/
getMetadata() {
return this.metadata;
}
}