@remotex-labs/xbuild 2.2.3 → 2.3.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/index.d.ts CHANGED
@@ -6,7 +6,7 @@
6
6
  import ts, { CompilerOptions, DiagnosticCategory, IScriptSnapshot, LanguageService, ParsedCommandLine, ResolvedModuleWithFailedLookupLocations, SourceFile } from 'typescript';
7
7
  import { BuildOptions, BuildResult, Loader, Message, OnEndResult, OnLoadArgs, OnLoadResult, OnResolveArgs, OnResolveResult, OnStartResult, PartialMessage, Platform, PluginBuild } from 'esbuild';
8
8
  import { IncomingMessage, ServerResponse } from 'http';
9
- import { PositionInterface, SourceService } from '@remotex-labs/xmap';
9
+ import { ResolveMetadataInterface as xMapResolveMetadataInterface, ResolveOptionsInterface } from '@remotex-labs/xmap';
10
10
  import { Options } from 'yargs';
11
11
 
12
12
  /**
@@ -224,31 +224,43 @@ declare class BuildService {
224
224
  * Reloads the build configuration and updates variants accordingly.
225
225
  *
226
226
  * @param config - Optional new configuration to replace the current one
227
+ * @param clearCache - Whether to clear cached files and TypeScript language service state before reloading
227
228
  *
228
229
  * @remarks
229
230
  * The reload process:
230
- * 1. Replaces configuration if provided
231
- * 2. Compares new variant names with existing ones
232
- * 3. Disposes variants no longer in configuration
233
- * 4. Creates new variants from the updated configuration
234
- * 5. Existing variants with matching names continue unchanged
231
+ * 1. Optionally clears cached file state and TypeScript language service data
232
+ * 2. Replaces configuration if provided
233
+ * 3. Compares new variant names with existing ones
234
+ * 4. Disposes variants no longer in configuration
235
+ * 5. Creates new variants from the updated configuration
236
+ * 6. Existing variants with matching names continue unchanged
235
237
  *
236
238
  * This is useful for hot-reloading configuration files without restarting the build process.
237
239
  *
238
240
  * @example
239
241
  * ```ts
240
- * // Add a new staging variant
242
+ * // Reload with a new staging variant
241
243
  * buildService.reload({
242
- * variants: {
243
- * ...buildService.config.variants,
244
- * staging: { esbuild: { minify: true } }
244
+ * config: {
245
+ * variants: {
246
+ * ...buildService.config.variants,
247
+ * staging: { esbuild: { minify: true } }
248
+ * }
245
249
  * }
246
250
  * });
247
251
  * ```
248
252
  *
249
- * @since 2.0.0
253
+ * @example
254
+ * ```ts
255
+ * // Reload and clear cached file/type-checking state first
256
+ * buildService.reload({
257
+ * clearCache: true
258
+ * });
259
+ * ```
260
+ *
261
+ * @since 2.3.0
250
262
  */
251
- reload(config?: PartialBuildConfigType): void;
263
+ reload({ config, clearCache }?: ReloadOptionsInterface): void;
252
264
  /**
253
265
  * Notifies all variants that specific files have been modified.
254
266
  *
@@ -743,6 +755,19 @@ declare class LanguageHostService implements ts.LanguageServiceHost {
743
755
  * @since 2.0.0
744
756
  */
745
757
  private alias;
758
+ /**
759
+ * Cache for resolved module specifiers.
760
+ *
761
+ * @remarks
762
+ * Stores the absolute resolved file path for each module name so repeated lookups
763
+ * do not trigger TypeScript module resolution again. A value of `undefined` means
764
+ * the module could not be resolved and that result is cached too.
765
+ *
766
+ * This cache is keyed by the raw import specifier, so it is only safe when the
767
+ * same specifier is resolved in a compatible context.
768
+ *
769
+ * @since 2.3.0
770
+ */
746
771
  private aliasCache;
747
772
  /**
748
773
  * Cache for TypeScript module resolution results.
@@ -839,6 +864,18 @@ declare class LanguageHostService implements ts.LanguageServiceHost {
839
864
  * @since 2.0.0
840
865
  */
841
866
  set options(options: CompilerOptions);
867
+ /**
868
+ * Reloads all tracked file snapshots in the shared {@link FilesModel} cache.
869
+ *
870
+ * @remarks
871
+ * This method iterates over every currently tracked file path and touches each file again so
872
+ * the cache can refresh its stored modification time, version, and content snapshot when needed.
873
+ * It is useful in watch-mode or manual refresh scenarios where the underlying files may have changed
874
+ * and dependent services need to observe the updated state.
875
+ *
876
+ * @since 2.3.0
877
+ */
878
+ static reload(): void;
842
879
  /**
843
880
  * Updates file snapshot in the cache and returns the current state.
844
881
  *
@@ -1139,1689 +1176,1717 @@ interface FileSnapshotInterface {
1139
1176
  contentSnapshot: ScriptSnapshotType | undefined;
1140
1177
  }
1141
1178
  /**
1142
- * Recursively makes all properties of a type optional.
1179
+ * Extended build result interface with normalized error and warning arrays.
1143
1180
  *
1144
1181
  * @remarks
1145
- * This utility type behaves like TypeScript’s built-in {@link Partial} type,
1146
- * but applies recursively to all nested object properties.
1182
+ * This interface extends esbuild's {@link BuildResult} while replacing the `errors` and `warnings`
1183
+ * properties with normalized Error instances instead of esbuild's Message objects. This normalization
1184
+ * provides consistent error handling throughout the xBuild system with proper stack traces, formatting,
1185
+ * and error classification.
1147
1186
  *
1148
- * It is commonly used for:
1149
- * - Partial configuration overrides
1150
- * - Patch / update objects
1151
- * - Programmatic configuration merging
1152
- * - Build variant and preset definitions
1187
+ * **Key differences from esbuild's BuildResult**:
1188
+ * - `errors`: Changed from `Message[]` to `Error[]` with normalized error types
1189
+ * - `warnings`: Changed from `Message[]` to `Error[]` with normalized error types
1190
+ * - All other properties (metafile, outputFiles, mangleCache) are preserved unchanged
1153
1191
  *
1154
- * This type only affects compile-time type checking and has no runtime impact.
1192
+ * **Benefits of normalization**:
1193
+ * - Consistent error handling across different error sources (esbuild, TypeScript, VM runtime)
1194
+ * - Proper error inheritance and type checking
1195
+ * - Rich stack trace information with source mapping
1196
+ * - Formatted error output with syntax highlighting
1197
+ * - Integration with xBuild's custom error classes
1155
1198
  *
1156
- * ⚠️ **Important limitations**:
1157
- * - Arrays and functions are treated as objects and will also be recursively
1158
- * transformed. If this is undesirable, a more specialized deep-partial
1159
- * implementation should be used.
1160
- * - Intended for configuration and data-shaping use cases, not strict domain models.
1199
+ * The normalized errors may include:
1200
+ * - {@link TypesError} for TypeScript type checking failures
1201
+ * - {@link xBuildError} for text errors during build hooks
1202
+ * - {@link esBuildError} for esbuild compilation errors with location information
1203
+ * - {@link VMRuntimeError} for runtime errors during build hooks
1204
+ * - {@link xBuildBaseError} for custom build system errors
1161
1205
  *
1162
1206
  * @example
1163
1207
  * ```ts
1164
- * interface Config {
1165
- * server: {
1166
- * host: string;
1167
- * port: number;
1168
- * };
1169
- * features: {
1170
- * experimental: boolean;
1171
- * };
1172
- * }
1173
- *
1174
- * const override: DeepPartialType<Config> = {
1175
- * server: {
1176
- * port: 8080
1177
- * }
1208
+ * const result: BuildResultInterface = {
1209
+ * errors: [
1210
+ * new esBuildError(esbuildMessage),
1211
+ * new TypesError('Type checking failed', diagnostics)
1212
+ * ],
1213
+ * warnings: [
1214
+ * new xBuildError('Deprecation warning')
1215
+ * ],
1216
+ * metafile: { ... },
1217
+ * outputFiles: [ ... ],
1218
+ * mangleCache: { ... }
1178
1219
  * };
1179
1220
  * ```
1180
1221
  *
1181
- * @template T - The type to recursively make optional.
1222
+ * @see {@link BuildResult} from esbuild for the base interface
1182
1223
  *
1183
1224
  * @since 2.0.0
1184
1225
  */
1185
- type DeepPartialType<T> = {
1186
- [K in keyof T]?: T[K] extends object ? DeepPartialType<T[K]> : T[K];
1187
- };
1226
+ interface BuildResultInterface extends Omit<BuildResult, 'errors' | 'warnings'> {
1227
+ /**
1228
+ * Array of normalized error instances encountered during the build.
1229
+ *
1230
+ * @remarks
1231
+ * Contains Error instances converted from esbuild messages and other error sources.
1232
+ * Unlike esbuild's native error array which contains Message objects, this array
1233
+ * contains fully normalized Error instances with proper stack traces and formatting.
1234
+ *
1235
+ * Errors in this array may originate from:
1236
+ * - Compilation errors (syntax, resolution failures)
1237
+ * - Type checking failures
1238
+ * - Build hook execution errors
1239
+ * - Plugin errors
1240
+ *
1241
+ * @example
1242
+ * ```ts
1243
+ * if (result.errors.length > 0) {
1244
+ * console.error(`Build failed with ${result.errors.length} errors`);
1245
+ * result.errors.forEach(err => console.error(err.stack));
1246
+ * }
1247
+ * ```
1248
+ *
1249
+ * @since 2.0.0
1250
+ */
1251
+ errors: Array<Error>;
1252
+ /**
1253
+ * Array of normalized warning instances encountered during the build.
1254
+ *
1255
+ * @remarks
1256
+ * Contains Error instances converted from esbuild warning messages and other warning sources.
1257
+ * Unlike esbuild's native warning array which contains Message objects, this array
1258
+ * contains fully normalized Error instances with proper stack traces and formatting.
1259
+ *
1260
+ * Warnings indicate non-fatal issues that don't prevent build completion but may
1261
+ * require attention, such as:
1262
+ * - Deprecated API usage
1263
+ * - Type checking warnings
1264
+ * - Performance concerns
1265
+ * - Potential runtime issues
1266
+ *
1267
+ * @example
1268
+ * ```ts
1269
+ * if (result.warnings.length > 0) {
1270
+ * console.warn(`Build completed with ${result.warnings.length} warnings`);
1271
+ * result.warnings.forEach(warn => console.warn(warn.message));
1272
+ * }
1273
+ * ```
1274
+ *
1275
+ * @since 2.0.0
1276
+ */
1277
+ warnings: Array<Error>;
1278
+ }
1188
1279
  /**
1189
- * Represents code that can be injected into build output as a banner or footer.
1190
- * Can be a static string or a function that generates code dynamically based on build context.
1280
+ * Represents a value that may be synchronous, asynchronous, void, null, or the specified type.
1191
1281
  *
1192
- * @remarks
1193
- * This type provides flexibility for injecting code at the top (banner) or bottom (footer) of
1194
- * bundled output files. The function form receives the plugin name and command-line arguments,
1195
- * allowing for context-aware code generation.
1282
+ * @template T - The actual value type when present
1196
1283
  *
1197
- * Common use cases:
1198
- * - Static banners: Copyright notices, license headers, version information
1199
- * - Dynamic banners: Build timestamps, environment-specific code, conditional imports
1200
- * - Footer code: Analytics snippets, polyfills, initialization scripts
1284
+ * @remarks
1285
+ * This utility type is used for hook handlers that may return values in multiple forms:
1286
+ * - Synchronous return: `T`, `void`, or `null`
1287
+ * - Asynchronous return: `Promise<T>`, `Promise<void>`, or `Promise<null>`
1201
1288
  *
1202
- * When using the function form, the generated string is cached per build variant to avoid
1203
- * regenerating the same code multiple times.
1289
+ * This flexibility allows hooks to be implemented as sync or async functions and to optionally
1290
+ * return results. Handlers that don't need to return data can return `void` or `null`.
1204
1291
  *
1205
1292
  * @example
1206
1293
  * ```ts
1207
- * // Static banner
1208
- * const banner: InjectableCodeType = '\/* Copyright 2024 *\/';
1209
- *
1210
- * // Dynamic banner
1211
- * const banner: InjectableCodeType = (name, argv) => {
1212
- * const version = argv.version || '1.0.0';
1213
- * return `\/* Built by ${name} v${version} at ${new Date().toISOString()} *\/`;
1214
- * };
1294
+ * // All valid implementations
1295
+ * const sync: MaybeVoidPromiseType<string> = 'result';
1296
+ * const voidSync: MaybeVoidPromiseType<string> = null;
1297
+ * const async: MaybeVoidPromiseType<string> = Promise.resolve('result');
1298
+ * const voidAsync: MaybeVoidPromiseType<string> = Promise.resolve(null);
1215
1299
  * ```
1216
1300
  *
1217
- * @see {@link BaseBuildDefinitionInterface.banner}
1218
- * @see {@link BaseBuildDefinitionInterface.footer}
1301
+ * @see {@link OnEndType}
1302
+ * @see {@link OnStartType}
1219
1303
  *
1220
1304
  * @since 2.0.0
1221
1305
  */
1222
- type InjectableCodeType = string | ((name: string, argv: Record<string, unknown>) => string);
1306
+ type MaybeVoidPromiseType<T> = void | null | T | Promise<void | null | T>;
1223
1307
  /**
1224
- * Defines lifecycle hook handlers for build process stages.
1225
- * Allows registration of custom logic during resolution, loading, build start, build end, and success.
1308
+ * Represents a value that may be synchronous, asynchronous, undefined, null, or the specified type.
1226
1309
  *
1227
- * @remarks
1228
- * This interface groups all available lifecycle hooks in a single configuration object.
1229
- * All hooks are optional, allowing selective registration of only necessary handlers.
1310
+ * @template T - The actual value type when present
1230
1311
  *
1231
- * Hook execution order during a build:
1232
- * 1. `onStart` - Before any file processing
1233
- * 2. `onResolve` - During import path resolution
1234
- * 3. `onLoad` - When loading file contents
1235
- * 4. `onEnd` - After build completes (success or failure)
1236
- * 5. `onSuccess` - After a build completes successfully
1312
+ * @remarks
1313
+ * This utility type is used for hook handlers that may return values in multiple forms:
1314
+ * - Synchronous return: `T`, `undefined`, or `null`
1315
+ * - Asynchronous return: `Promise<T>`, `Promise<undefined>`, or `Promise<null>`
1237
1316
  *
1238
- * Each hook receives a specialized context object appropriate for its lifecycle stage, providing
1239
- * access to build configuration, variant information, and cross-hook communication through the
1240
- * shared stage object.
1317
+ * Similar to {@link MaybeVoidPromiseType} but uses `undefined` instead of `void`, allowing handlers
1318
+ * to explicitly return nothing or optionally return results. This distinction is important for
1319
+ * hooks where the absence of a return value has semantic meaning (like allowing default behavior).
1241
1320
  *
1242
1321
  * @example
1243
1322
  * ```ts
1244
- * const hooks: LifecycleHooksInterface = {
1245
- * onStart: async (context) => {
1246
- * console.log(`${context.variantName} build starting...`);
1247
- * },
1248
- * onLoad: async (context) => {
1249
- * if (context.args.path.endsWith('.custom')) {
1250
- * return { contents: transform(context.contents), loader: 'ts' };
1251
- * }
1252
- * },
1253
- * onSuccess: async (context) => {
1254
- * console.log(`Build succeeded in ${context.duration}ms!`);
1255
- * }
1256
- * };
1323
+ * // All valid implementations
1324
+ * const sync: MaybeUndefinedPromiseType<object> = { path: '/file.ts' };
1325
+ * const undefinedSync: MaybeUndefinedPromiseType<object> = undefined;
1326
+ * const async: MaybeUndefinedPromiseType<object> = Promise.resolve({ path: '/file.ts' });
1327
+ * const undefinedAsync: MaybeUndefinedPromiseType<object> = Promise.resolve(undefined);
1257
1328
  * ```
1258
1329
  *
1259
- * @see {@link OnEndType}
1260
1330
  * @see {@link OnLoadType}
1261
- * @see {@link OnStartType}
1262
1331
  * @see {@link OnResolveType}
1263
1332
  *
1264
1333
  * @since 2.0.0
1265
1334
  */
1266
- interface LifecycleHooksInterface {
1267
- /**
1268
- * Hook handler executed when the build completes, regardless of success or failure.
1269
- *
1270
- * @remarks
1271
- * Called after all build operations finish with a result context containing the build result,
1272
- * calculated duration, variant name, arguments, and stage state. Useful for cleanup, logging,
1273
- * reporting, and post-processing.
1274
- *
1275
- * The handler receives `ResultContextInterface` providing access to:
1276
- * - `buildResult`: Final build outcome with errors and warnings
1277
- * - `duration`: Build duration in milliseconds
1278
- * - `variantName`: Build variant identifier
1279
- * - `argv`: Command-line arguments and configuration
1280
- * - `stage`: Shared state object for cross-hook communication
1281
- *
1282
- * @example
1283
- * ```ts
1284
- * onEnd: async (context) => {
1285
- * const { buildResult, duration, variantName } = context;
1286
- * console.log(`${variantName} completed in ${duration}ms`);
1287
- * if (buildResult.errors.length > 0) {
1288
- * // Handle errors
1289
- * }
1290
- * }
1291
- * ```
1292
- *
1293
- * @see {@link ResultContextInterface}
1294
- *
1295
- * @since 2.0.0
1296
- */
1297
- onEnd?: OnEndType;
1298
- /**
1299
- * Hook handler executed when loading file contents during module processing.
1300
- *
1301
- * @remarks
1302
- * Called for each file being processed with a load context containing the current file contents
1303
- * (potentially transformed by previous hooks), loader type, load arguments, variant name, and
1304
- * stage state. Can transform contents and change the loader type. Multiple handlers execute in
1305
- * a pipeline pattern where each receives the output of previous hooks.
1335
+ type MaybeUndefinedPromiseType<T> = undefined | null | T | Promise<undefined | null | T>;
1336
+ /**
1337
+ * Represents a transient build stage state shared across hook handlers during a single build.
1338
+ *
1339
+ * @remarks
1340
+ * This interface provides a flexible container for storing temporary data during the build lifecycle.
1341
+ * It's reset at the start of each build and is available to all hooks through the plugin context.
1342
+ *
1343
+ * The `startTime` property is always present and set when the build begins, allowing hooks to
1344
+ * calculate durations and timing information. Additional properties can be added dynamically
1345
+ * using the index signature to facilitate cross-handler communication.
1346
+ *
1347
+ * Common use cases:
1348
+ * - Storing build start time for duration calculations
1349
+ * - Passing data between different hook handlers
1350
+ * - Accumulating statistics during the build
1351
+ * - Caching computed values for reuse across hooks
1352
+ *
1353
+ * @example
1354
+ * ```ts
1355
+ * // In onStart hook
1356
+ * context.stage.startTime = new Date();
1357
+ * context.stage.fileCount = 0;
1358
+ *
1359
+ * // In onLoad hook
1360
+ * context.stage.fileCount++;
1361
+ *
1362
+ * // In onEnd hook
1363
+ * const duration = Date.now() - context.stage.startTime.getTime();
1364
+ * console.log(`Processed ${context.stage.fileCount} files in ${duration}ms`);
1365
+ * ```
1366
+ *
1367
+ * @see {@link LifecycleContextInterface}
1368
+ *
1369
+ * @since 2.0.0
1370
+ */
1371
+ interface LifecycleStageInterface {
1372
+ /**
1373
+ * Timestamp when the build process started.
1306
1374
  *
1307
- * The handler receives `LoadContextInterface` providing access to:
1308
- * - `contents`: Current file contents (string or binary)
1309
- * - `loader`: Current loader type (e.g., 'ts', 'js', 'json')
1310
- * - `args`: Load arguments including file path and namespace
1311
- * - `variantName`: Build variant identifier
1312
- * - `argv`: Command-line arguments and configuration
1313
- * - `stage`: Shared state object for cross-hook communication
1375
+ * @remarks
1376
+ * Set during the first `onStart` hook execution and available throughout the build lifecycle.
1377
+ * Used to calculate build duration and timing information.
1314
1378
  *
1315
- * @example
1316
- * ```ts
1317
- * onLoad: async (context) => {
1318
- * const { contents, args, variantName } = context;
1319
- * if (args.path.endsWith('.custom')) {
1320
- * return {
1321
- * contents: transform(contents.toString()),
1322
- * loader: 'ts'
1323
- * };
1324
- * }
1325
- * }
1326
- * ```
1379
+ * @since 2.0.0
1380
+ */
1381
+ startTime: Date;
1382
+ /**
1383
+ * Additional dynamic properties for cross-handler communication.
1327
1384
  *
1328
- * @see {@link LoadContextInterface}
1385
+ * @remarks
1386
+ * Handlers can store arbitrary data in the stage object using any string key.
1387
+ * This allows passing information between hooks during a single build.
1329
1388
  *
1330
1389
  * @since 2.0.0
1331
1390
  */
1332
- onLoad?: OnLoadType;
1391
+ [key: string]: unknown;
1392
+ }
1393
+ /**
1394
+ * Base context interface shared by all lifecycle hook handlers.
1395
+ * Provides access to plugin configuration, command-line arguments, and transient build state.
1396
+ *
1397
+ * @remarks
1398
+ * This context is initialized during the `onStart` phase and remains available throughout the
1399
+ * entire build lifecycle. All hook handlers receive a variant of this context, enabling:
1400
+ * - Access to command-line arguments and configuration
1401
+ * - Cross-handler communication through the stage object
1402
+ * - Consistent variant identification across hooks
1403
+ *
1404
+ * The context is immutable at the top level (variantName and argv don't change during a build),
1405
+ * but the stage object is mutable and reset between builds.
1406
+ *
1407
+ * @example
1408
+ * ```ts
1409
+ * // In onStart hook
1410
+ * const handler: OnStartType = async (context) => {
1411
+ * console.log(`Variant ${context.variantName} starting`);
1412
+ * context.stage.customData = { processed: 0 };
1413
+ * };
1414
+ * ```
1415
+ *
1416
+ * @see {@link LoadContextInterface}
1417
+ * @see {@link BuildContextInterface}
1418
+ * @see {@link ResultContextInterface}
1419
+ * @see {@link ResolveContextInterface}
1420
+ * @see {@link LifecycleStageInterface}
1421
+ *
1422
+ * @since 2.0.0
1423
+ */
1424
+ interface LifecycleContextInterface {
1333
1425
  /**
1334
- * Hook handler executed when the build process begins.
1426
+ * Command-line arguments and configuration options passed to the provider.
1335
1427
  *
1336
1428
  * @remarks
1337
- * Called before any file processing starts with a build context containing the esbuild build object,
1338
- * variant name, arguments, and stage state. Useful for initialization, validation, and setup tasks.
1339
- *
1340
- * The handler receives `BuildContextInterface` providing access to:
1341
- * - `build`: esbuild plugin build object with configuration and utilities
1342
- * - `variantName`: Build variant identifier
1343
- * - `argv`: Command-line arguments and configuration
1344
- * - `stage`: Shared state object for cross-hook communication
1429
+ * Contains all CLI options and flags passed when the provider was created.
1430
+ * Available to all handlers for accessing build-specific configuration like
1431
+ * debug flags, output paths, or custom settings.
1345
1432
  *
1346
1433
  * @example
1347
1434
  * ```ts
1348
- * onStart: async (context) => {
1349
- * const { build, variantName, stage } = context;
1350
- * console.log(`Starting ${variantName} build`);
1351
- * stage.startTime = new Date();
1352
- *
1353
- * // Validate configuration
1354
- * if (!build.initialOptions.outdir) {
1355
- * return { errors: [{ text: 'Output directory required' }] };
1356
- * }
1357
- * }
1435
+ * context.argv; // { debug: true, verbose: false, outdir: 'dist' }
1358
1436
  * ```
1359
1437
  *
1360
- * @see {@link BuildContextInterface}
1361
- *
1362
1438
  * @since 2.0.0
1363
1439
  */
1364
- onStart?: OnStartType;
1440
+ argv: Record<string, unknown>;
1365
1441
  /**
1366
- * Hook handler executed when the build completes successfully without errors.
1442
+ * Transient state object for cross-handler communication during a single build.
1367
1443
  *
1368
1444
  * @remarks
1369
- * Only called when `buildResult.errors.length === 0`, after all regular end hooks have completed.
1370
- * Receives the same result context as end hooks, containing build result, duration, variant name,
1371
- * arguments, and stage state. Useful for deployment, success notifications, and success-only operations.
1445
+ * Reset to contain only `startTime` at the beginning of each build. Handlers can store
1446
+ * and retrieve temporary data during the build lifecycle through this object.
1372
1447
  *
1373
- * The handler receives `ResultContextInterface` providing access to:
1374
- * - `buildResult`: Final build outcome (guaranteed to have zero errors)
1375
- * - `duration`: Build duration in milliseconds
1376
- * - `variantName`: Build variant identifier
1377
- * - `argv`: Command-line arguments and configuration
1378
- * - `stage`: Shared state object for cross-hook communication
1448
+ * Common patterns:
1449
+ * - Accumulating statistics across multiple hooks
1450
+ * - Passing processed data between different hook types
1451
+ * - Caching expensive computations for reuse
1379
1452
  *
1380
1453
  * @example
1381
1454
  * ```ts
1382
- * onSuccess: async (context) => {
1383
- * const { buildResult, duration, variantName } = context;
1384
- * console.log(`${variantName} succeeded in ${duration}ms!`);
1385
- * await deploy(buildResult.metafile);
1386
- * }
1455
+ * // Store data in onLoad
1456
+ * context.stage.transformedFiles = [];
1457
+ *
1458
+ * // Access in onEnd
1459
+ * console.log(`Transformed ${context.stage.transformedFiles.length} files`);
1387
1460
  * ```
1388
1461
  *
1389
- * @see {@link ResultContextInterface}
1462
+ * @see {@link LifecycleStageInterface}
1390
1463
  *
1391
1464
  * @since 2.0.0
1392
1465
  */
1393
- onSuccess?: OnEndType;
1466
+ stage: LifecycleStageInterface;
1394
1467
  /**
1395
- * Hook handler executed during module path resolution.
1468
+ * Identifier for the build variant or plugin instance.
1396
1469
  *
1397
1470
  * @remarks
1398
- * Called when resolving import paths to file system locations with a resolve context containing
1399
- * the resolution arguments, variant name, and stage state. Can redirect imports, mark modules as
1400
- * external, or implement custom resolution logic. Multiple handlers execute, and their results are
1401
- * merged, with later hooks able to override earlier ones.
1402
- *
1403
- * The handler receives `ResolveContextInterface` providing access to:
1404
- * - `args`: Resolution arguments including import path and importer info
1405
- * - `variantName`: Build variant identifier
1406
- * - `argv`: Command-line arguments and configuration
1407
- * - `stage`: Shared state object for cross-hook communication
1471
+ * Used for identification and logging. Same as the variant name passed to
1472
+ * the HooksProvider constructor or build configuration.
1408
1473
  *
1409
1474
  * @example
1410
1475
  * ```ts
1411
- * onResolve: async (context) => {
1412
- * const { args, variantName } = context;
1413
- *
1414
- * // Redirect '@/' imports to 'src/'
1415
- * if (args.path.startsWith('@/')) {
1416
- * return {
1417
- * path: resolve('src', args.path.slice(2)),
1418
- * namespace: 'file'
1419
- * };
1420
- * }
1421
- *
1422
- * // Mark as external in production
1423
- * if (variantName === 'production' && args.path.includes('node_modules')) {
1424
- * return { path: args.path, external: true };
1425
- * }
1426
- * }
1476
+ * context.variantName; // 'production' or 'development'
1427
1477
  * ```
1428
1478
  *
1429
- * @see {@link ResolveContextInterface}
1430
- *
1431
1479
  * @since 2.0.0
1432
1480
  */
1433
- onResolve?: OnResolveType;
1481
+ variantName: string;
1482
+ /**
1483
+ * esbuild configuration options used for this lifecycle execution.
1484
+ *
1485
+ * @remarks
1486
+ * These options represent the active build configuration for the provider and
1487
+ * are intended to be read by lifecycle handlers when build behavior depends on
1488
+ * entry points, output settings, plugins, or other esbuild flags.
1489
+ *
1490
+ * @since 2.2.0
1491
+ */
1492
+ options: BuildOptions;
1434
1493
  }
1435
1494
  /**
1436
- * Configuration options for TypeScript declaration file generation.
1495
+ * Context interface for `onStart` hooks, providing access to the esbuild plugin build object.
1437
1496
  *
1438
1497
  * @remarks
1439
- * Controls how and where TypeScript declaration files (`.d.ts`) are generated during the build.
1440
- * These options work in conjunction with the TypeScript compiler to produce type definitions
1441
- * for bundled code.
1498
+ * This specialized context extends the base lifecycle context with the esbuild `PluginBuild`
1499
+ * object, giving start hooks access to build configuration, utilities, and the ability to
1500
+ * register additional esbuild hooks dynamically.
1442
1501
  *
1443
- * When `bundle` is true, declarations from multiple source files are combined into a single
1444
- * declaration file per entry point. When false, individual declaration files are generated
1445
- * for each source file.
1502
+ * Start hooks are the only lifecycle phase that receives the build object, as they execute
1503
+ * before file processing begins and may need to configure or inspect build settings.
1446
1504
  *
1447
1505
  * @example
1448
1506
  * ```ts
1449
- * // Generate bundled declarations in custom directory
1450
- * const options: DeclarationOptionsInterface = {
1451
- * outDir: 'types',
1452
- * bundle: true
1507
+ * const handler: OnStartType = async (context) => {
1508
+ * const { build, variantName, argv } = context;
1509
+ * console.log(`Starting ${variantName} build`);
1510
+ *
1511
+ * // Access build configuration
1512
+ * console.log(`Platform: ${build.initialOptions.platform}`);
1513
+ *
1514
+ * return { errors: [], warnings: [] };
1453
1515
  * };
1454
1516
  * ```
1455
1517
  *
1456
- * @see {@link BaseBuildDefinitionInterface.declaration}
1518
+ * @see {@link OnStartType}
1519
+ * @see {@link LifecycleContextInterface}
1457
1520
  *
1458
1521
  * @since 2.0.0
1459
1522
  */
1460
- interface DeclarationOptionsInterface {
1523
+ interface BuildContextInterface extends LifecycleContextInterface {
1461
1524
  /**
1462
- * Output directory for generated declaration files.
1525
+ * The esbuild plugin build object providing build configuration and utilities.
1463
1526
  *
1464
1527
  * @remarks
1465
- * Specifies where `.d.ts` files should be written. If not provided, uses the TypeScript
1466
- * compiler's `declarationDir` or `outDir` from `tsconfig.json`.
1528
+ * Provides access to:
1529
+ * - `initialOptions`: Build configuration options
1530
+ * - `resolve`: Path resolution utilities
1531
+ * - Dynamic hook registration methods
1532
+ * - Build environment information
1533
+ *
1534
+ * Available only in `onStart` hooks, as later phases don't require build-level access.
1467
1535
  *
1468
1536
  * @example
1469
1537
  * ```ts
1470
- * outDir: 'dist/types'
1538
+ * // Access initial options
1539
+ * const outdir = context.build.initialOptions.outdir;
1540
+ *
1541
+ * // Resolve a path
1542
+ * const resolved = await context.build.resolve('./module', {
1543
+ * resolveDir: '/src'
1544
+ * });
1471
1545
  * ```
1472
1546
  *
1473
1547
  * @since 2.0.0
1474
1548
  */
1475
- outDir?: string;
1549
+ build: PluginBuild;
1550
+ }
1551
+ /**
1552
+ * Context interface for `onEnd` and `onSuccess` hooks, providing access to build results and duration.
1553
+ *
1554
+ * @remarks
1555
+ * This specialized context extends the base lifecycle context with the final build result
1556
+ * and calculated build duration, giving end hooks access to a build outcome, errors, warnings,
1557
+ * and metadata.
1558
+ *
1559
+ * The duration is automatically calculated from the start time in the stage object, providing
1560
+ * a convenient way to measure build performance without manual timestamp calculations.
1561
+ *
1562
+ * @example
1563
+ * ```ts
1564
+ * const handler: OnEndType = async (context) => {
1565
+ * const { buildResult, duration, variantName } = context;
1566
+ *
1567
+ * console.log(`${variantName} build completed in ${duration}ms`);
1568
+ *
1569
+ * if (buildResult.errors.length > 0) {
1570
+ * console.error(`Build failed with ${buildResult.errors.length} errors`);
1571
+ * }
1572
+ *
1573
+ * // Access metafile for dependency analysis
1574
+ * if (buildResult.metafile) {
1575
+ * console.log('Outputs:', Object.keys(buildResult.metafile.outputs));
1576
+ * }
1577
+ * };
1578
+ * ```
1579
+ *
1580
+ * @see {@link OnEndType}
1581
+ * @see {@link LifecycleContextInterface}
1582
+ *
1583
+ * @since 2.0.0
1584
+ */
1585
+ interface ResultContextInterface extends LifecycleContextInterface {
1476
1586
  /**
1477
- * Whether to bundle declarations into a single file per entry point.
1587
+ * Build duration in milliseconds.
1478
1588
  *
1479
1589
  * @remarks
1480
- * When true, combines all declarations from imported modules into a single `.d.ts` file.
1481
- * When false, generates individual declaration files mirroring the source structure.
1590
+ * Automatically calculated as the time elapsed from `context.stage.startTime` to
1591
+ * when the build completed. Useful for performance monitoring and reporting.
1482
1592
  *
1483
- * Bundling is useful for library distribution as it provides a single type definition file
1484
- * that consumers can reference.
1593
+ * @example
1594
+ * ```ts
1595
+ * console.log(`Build took ${context.duration}ms`);
1596
+ * ```
1597
+ *
1598
+ * @since 2.0.0
1599
+ */
1600
+ duration: number;
1601
+ /**
1602
+ * The final build result from esbuild containing errors, warnings, and metadata.
1603
+ *
1604
+ * @remarks
1605
+ * Provides access to:
1606
+ * - `errors`: Array of build errors
1607
+ * - `warnings`: Array of build warnings
1608
+ * - `metafile`: Build metadata including inputs, outputs, and dependencies
1609
+ * - `outputFiles`: Generated file contents (if `write: false`)
1485
1610
  *
1486
1611
  * @example
1487
1612
  * ```ts
1488
- * bundle: true // Produces single bundled .d.ts
1489
- * bundle: false // Produces multiple .d.ts files
1613
+ * // Check for errors
1614
+ * if (context.buildResult.errors.length > 0) {
1615
+ * // Handle build failure
1616
+ * }
1617
+ *
1618
+ * // Analyze dependencies
1619
+ * const inputs = context.buildResult.metafile?.inputs;
1490
1620
  * ```
1491
1621
  *
1492
1622
  * @since 2.0.0
1493
1623
  */
1494
- bundle?: boolean;
1624
+ buildResult: BuildResult;
1495
1625
  }
1496
1626
  /**
1497
- * Configuration options for TypeScript type checking during builds.
1627
+ * Context interface for `onResolve` hooks, providing access to resolution arguments.
1498
1628
  *
1499
1629
  * @remarks
1500
- * Controls how TypeScript type checking is performed and whether type errors should fail the build.
1501
- * Type checking runs in parallel with the esbuild compilation process for better performance.
1630
+ * This specialized context extends the base lifecycle context with esbuild's resolution
1631
+ * arguments, giving resolve hooks access to the import path, importer information, and
1632
+ * resolution context needed to implement custom module resolution logic.
1633
+ *
1634
+ * Resolve hooks use this context to determine how to resolve import paths, redirect imports,
1635
+ * or mark modules as external based on the resolution arguments.
1502
1636
  *
1503
1637
  * @example
1504
1638
  * ```ts
1505
- * // Fail build on type errors
1506
- * const options: TypeCheckOptionsInterface = {
1507
- * failOnError: true
1639
+ * const handler: OnResolveType = async (context) => {
1640
+ * const { args, variantName } = context;
1641
+ *
1642
+ * // Redirect '@/' imports to 'src/'
1643
+ * if (args.path.startsWith('@/')) {
1644
+ * return {
1645
+ * path: resolve('src', args.path.slice(2)),
1646
+ * namespace: 'file'
1647
+ * };
1648
+ * }
1649
+ *
1650
+ * // Mark node_modules as external in development
1651
+ * if (variantName === 'development' && args.path.includes('node_modules')) {
1652
+ * return { path: args.path, external: true };
1653
+ * }
1654
+ *
1655
+ * return undefined; // Use default resolution
1508
1656
  * };
1509
1657
  * ```
1510
1658
  *
1511
- * @see {@link BaseBuildDefinitionInterface.types}
1659
+ * @see {@link OnResolveType}
1660
+ * @see {@link LifecycleContextInterface}
1512
1661
  *
1513
1662
  * @since 2.0.0
1514
1663
  */
1515
- interface TypeCheckOptionsInterface {
1664
+ interface ResolveContextInterface extends LifecycleContextInterface {
1516
1665
  /**
1517
- * Whether to fail the build when TypeScript errors are detected.
1666
+ * Resolution arguments from esbuild containing the import path and resolution context.
1518
1667
  *
1519
1668
  * @remarks
1520
- * When true, any TypeScript errors will cause the build to fail with a non-zero exit code.
1521
- * When false, errors are logged, but the build continues and succeeds.
1522
- *
1523
- * Useful in CI/CD pipelines where type safety must be enforced before deployment.
1669
+ * Provides access to:
1670
+ * - `path`: The import path to resolve (e.g., './module', '\@/utils')
1671
+ * - `importer`: The file that contains this import
1672
+ * - `namespace`: The namespace of the importer
1673
+ * - `resolveDir`: The directory to resolve relative imports from
1674
+ * - `kind`: The kind of import (e.g., 'import-statement', 'require-call')
1675
+ * - `pluginData`: Data passed from previous plugins
1524
1676
  *
1525
1677
  * @example
1526
1678
  * ```ts
1527
- * failOnError: true // Build fails on type errors
1528
- * failOnError: false // Type errors logged, but build continues
1679
+ * console.log(`Resolving ${context.args.path} from ${context.args.importer}`);
1680
+ *
1681
+ * if (context.args.kind === 'dynamic-import') {
1682
+ * // Handle dynamic imports specially
1683
+ * }
1529
1684
  * ```
1530
1685
  *
1531
1686
  * @since 2.0.0
1532
1687
  */
1533
- failOnError?: boolean;
1688
+ args: OnResolveArgs;
1534
1689
  }
1535
1690
  /**
1536
- * Base configuration shared across all build definitions, including common and variant builds.
1537
- * Provides common settings for hooks, type checking, code injection, and declaration generation.
1691
+ * Context interface for `onLoad` hooks, providing access to load arguments, current contents, and loader.
1538
1692
  *
1539
1693
  * @remarks
1540
- * This interface defines the foundation for build configuration that applies to both common
1541
- * settings and individual build variants. Properties defined here can be overridden at the
1542
- * variant level for customization.
1694
+ * This specialized context extends the base lifecycle context with esbuild's load arguments,
1695
+ * the current file contents (potentially transformed by previous hooks), and the current loader
1696
+ * type. This enables load hooks to implement content transformations in a pipeline pattern.
1543
1697
  *
1544
- * Configuration inheritance:
1545
- * - Common build settings apply to all variants
1546
- * - Variant settings override common settings
1547
- * - Objects like `define` are merged (variant takes precedence)
1548
- * - Arrays and primitives replace common values
1698
+ * Load hooks receive the output of previous hooks through `contents` and `loader`, allowing
1699
+ * sequential transformations where each hook builds on the work of previous hooks.
1549
1700
  *
1550
1701
  * @example
1551
1702
  * ```ts
1552
- * const base: BaseBuildDefinitionInterface = {
1553
- * types: { failOnError: true },
1554
- * declaration: { bundle: true, outDir: 'types' },
1555
- * define: { 'process.env.NODE_ENV': '"production"' },
1556
- * banner: 'const x = "test"',
1557
- * hooks: {
1558
- * onSuccess: async () => console.log('Build complete!')
1703
+ * const handler: OnLoadType = async (context) => {
1704
+ * const { contents, loader, args, variantName } = context;
1705
+ *
1706
+ * // Transform .custom files to TypeScript
1707
+ * if (args.path.endsWith('.custom')) {
1708
+ * return {
1709
+ * contents: transformCustomSyntax(contents.toString()),
1710
+ * loader: 'ts'
1711
+ * };
1712
+ * }
1713
+ *
1714
+ * // Add debugging in development
1715
+ * if (variantName === 'development' && loader === 'ts') {
1716
+ * return {
1717
+ * contents: `console.log('Loading: ${args.path}');\n${contents}`,
1718
+ * loader
1719
+ * };
1559
1720
  * }
1721
+ *
1722
+ * return undefined; // Pass through unchanged
1560
1723
  * };
1561
1724
  * ```
1562
1725
  *
1563
- * @see {@link CommonBuildInterface}
1564
- * @see {@link VariantBuildInterface}
1565
- * @see {@link BuildConfigInterface}
1726
+ * @see {@link OnLoadType}
1727
+ * @see {@link LifecycleContextInterface}
1566
1728
  *
1567
1729
  * @since 2.0.0
1568
1730
  */
1569
- interface BaseBuildDefinitionInterface {
1731
+ interface LoadContextInterface extends LifecycleContextInterface {
1570
1732
  /**
1571
- * Lifecycle hook handlers for build process stages.
1733
+ * Load arguments from esbuild containing file path and namespace.
1572
1734
  *
1573
1735
  * @remarks
1574
- * Registers custom handlers for various build lifecycle events including start, resolve,
1575
- * load, end, and success stages. All hooks are optional.
1736
+ * Provides access to:
1737
+ * - `path`: The absolute path to the file being loaded
1738
+ * - `namespace`: The namespace for this module
1739
+ * - `suffix`: Optional suffix for special handling
1740
+ * - `pluginData`: Data passed from resolve hooks or previous plugins
1576
1741
  *
1577
- * @see {@link LifecycleHooksInterface}
1742
+ * @example
1743
+ * ```ts
1744
+ * console.log(`Loading ${context.args.path}`);
1745
+ *
1746
+ * if (context.args.namespace === 'virtual') {
1747
+ * // Handle virtual modules
1748
+ * }
1749
+ * ```
1578
1750
  *
1579
1751
  * @since 2.0.0
1580
1752
  */
1581
- lifecycle?: LifecycleHooksInterface;
1753
+ args: OnLoadArgs;
1582
1754
  /**
1583
- * TypeScript type checking configuration.
1755
+ * The current loader type for this file.
1584
1756
  *
1585
1757
  * @remarks
1586
- * Controls whether and how TypeScript type checking is performed during builds.
1587
- * - `true`: Enable type checking with default options
1588
- * - `false` or omitted: Disable type checking
1589
- * - Object: Enable with specific options like `failOnError`
1758
+ * Reflects any loader changes made by previous hooks in the pipeline. Can be:
1759
+ * - `'js'`, `'ts'`, `'jsx'`, `'tsx'`: JavaScript/TypeScript variants
1760
+ * - `'json'`, `'css'`, `'text'`: Special content types
1761
+ * - `'base64'`, `'binary'`, `'dataurl'`: Binary content encodings
1762
+ * - `'default'`: Let esbuild determine the loader
1763
+ * - `undefined`: No loader has been set yet
1764
+ *
1765
+ * Hooks can change the loader to affect how esbuild processes the contents.
1590
1766
  *
1591
1767
  * @example
1592
1768
  * ```ts
1593
- * types: true // Enable with default
1594
- * types: { failOnError: true } // Enable and fail on errors
1595
- * types: false // Disable
1769
+ * if (context.loader === 'json') {
1770
+ * // Transform JSON before esbuild processes it
1771
+ * }
1596
1772
  * ```
1597
1773
  *
1598
- * @see {@link TypeCheckOptionsInterface}
1599
- *
1600
1774
  * @since 2.0.0
1601
1775
  */
1602
- types?: boolean | TypeCheckOptionsInterface;
1776
+ loader: Loader | undefined;
1603
1777
  /**
1604
- * Global constants to replace during bundling.
1778
+ * The current file contents as string or binary data.
1605
1779
  *
1606
1780
  * @remarks
1607
- * Defines key-value pairs for constant replacement during the build. Keys are identifiers
1608
- * or property access expressions, values are JSON-stringified replacements.
1781
+ * Contains the output of previous load hooks in the pipeline, or the initial file
1782
+ * contents if this is the first hook. Hooks can transform this content and return
1783
+ * new contents for further hooks to process.
1609
1784
  *
1610
- * Commonly used for environment variables, feature flags, and build-time constants.
1785
+ * Content can be:
1786
+ * - `string`: Text content (source code, JSON, CSS, etc.)
1787
+ * - `Uint8Array`: Binary content (images, fonts, etc.)
1611
1788
  *
1612
1789
  * @example
1613
1790
  * ```ts
1614
- * define: {
1615
- * 'process.env.NODE_ENV': '"production"',
1616
- * 'DEBUG': 'false',
1617
- * 'VERSION': '"1.2.3"'
1791
+ * // Transform string contents
1792
+ * const transformed = context.contents.toString().replace(/old/g, 'new');
1793
+ *
1794
+ * // Check content type
1795
+ * if (typeof context.contents === 'string') {
1796
+ * // Handle text
1797
+ * } else {
1798
+ * // Handle binary
1618
1799
  * }
1619
1800
  * ```
1620
1801
  *
1621
1802
  * @since 2.0.0
1622
1803
  */
1623
- define?: Record<string, unknown>;
1624
- /**
1625
- * Code to inject at the beginning of each output file.
1626
- *
1627
- * @remarks
1628
- * Can be a static string or a function that generates code based on build context.
1629
- * Commonly used for copyright notices, license headers, or polyfill imports.
1630
- *
1631
- * @example
1632
- * ```ts
1633
- * banner: 'const x = "test"'
1634
- * banner: (name, argv) => `const x = "Built: ${new Date().toISOString()}"`
1635
- * ```
1636
- *
1637
- * @see {@link InjectableCodeType}
1638
- *
1639
- * @since 2.0.0
1640
- */
1641
- banner?: {
1642
- [key: string]: InjectableCodeType;
1643
- };
1644
- /**
1645
- * Code to inject at the end of each output file.
1646
- *
1647
- * @remarks
1648
- * Can be a static string or a function that generates code based on build context.
1649
- * Commonly used for initialization code, analytics, or polyfills.
1650
- *
1651
- * @example
1652
- * ```ts
1653
- * footer: '// End of bundle'
1654
- * footer: (name, argv) => `console.log('Loaded ${name}');`
1655
- * ```
1656
- *
1657
- * @see {@link InjectableCodeType}
1658
- *
1659
- * @since 2.0.0
1660
- */
1661
- footer?: {
1662
- [key: string]: InjectableCodeType;
1663
- };
1664
- /**
1665
- * TypeScript declaration file generation configuration.
1666
- *
1667
- * @remarks
1668
- * Controls whether and how TypeScript declaration files are generated.
1669
- * - `true`: Generate declarations with default options
1670
- * - `false` or omitted: Do not generate declarations
1671
- * - Object: Generate with specific options like `outDir` and `bundle`
1672
- *
1673
- * @example
1674
- * ```ts
1675
- * declaration: true // Generate with default
1676
- * declaration: { outDir: 'types', bundle: true } // Generate bundled in custom dir
1677
- * declaration: false // Disable
1678
- * ```
1679
- *
1680
- * @see {@link DeclarationOptionsInterface}
1681
- *
1682
- * @since 2.0.0
1683
- */
1684
- declaration?: boolean | DeclarationOptionsInterface;
1804
+ contents: string | Uint8Array;
1685
1805
  }
1686
1806
  /**
1687
- * Build configuration for a specific build variant including esbuild settings and entry points.
1688
- * Extends base configuration with variant-specific esbuild options and required entry points.
1807
+ * Handler function signature for `onStart` hooks executed when a build begins.
1689
1808
  *
1690
- * @remarks
1691
- * A variant represents a distinct build target with its own entry points and esbuild configuration.
1692
- * Variants inherit settings from the common configuration but can override any property.
1809
+ * @param context - Build context containing the esbuild build object, arguments, and stage state
1693
1810
  *
1694
- * The `esbuild` property excludes fields that are managed by the build system:
1695
- * - `plugins`: Managed by the hook provider
1696
- * - `define`, `banner`, `footer`: Managed by base configuration
1697
- * - `entryPoints`: Required at variant level (non-nullable)
1811
+ * @returns Optional result containing errors and warnings to report, or void/null if none
1698
1812
  *
1699
- * Multiple variants enable building different outputs from the same codebase, such as
1700
- * - Different module formats (ESM, CJS)
1701
- * - Different targets (Node.js, browser)
1702
- * - Different bundles (main, worker, tests)
1813
+ * @remarks
1814
+ * Start hooks are executed before any file processing occurs and receive a build context
1815
+ * with access to the esbuild `PluginBuild` object. They can perform initialization tasks
1816
+ * and return errors or warnings that will be aggregated with results from other start hooks.
1817
+ *
1818
+ * Return value semantics:
1819
+ * - Return `void` or `null` if the hook has nothing to report
1820
+ * - Return `OnStartResult` with errors/warnings arrays to report issues
1821
+ * - Can be synchronous or asynchronous (return a Promise)
1703
1822
  *
1704
1823
  * @example
1705
1824
  * ```ts
1706
- * const variant: VariantBuildInterface = {
1707
- * esbuild: {
1708
- * entryPoints: ['src/index.ts'],
1709
- * outdir: 'dist/esm',
1710
- * format: 'esm',
1711
- * target: 'es2020'
1712
- * },
1713
- * types: true,
1714
- * declaration: { bundle: true, outDir: 'dist/types' }
1825
+ * const onStart: OnStartType = async (context) => {
1826
+ * console.log(`Starting ${context.variantName} build`);
1827
+ * context.stage.startTime = new Date();
1828
+ *
1829
+ * // Validate build configuration
1830
+ * if (!context.build.initialOptions.outdir) {
1831
+ * return {
1832
+ * errors: [{
1833
+ * text: 'Output directory not specified',
1834
+ * location: null
1835
+ * }]
1836
+ * };
1837
+ * }
1838
+ *
1839
+ * return { errors: [], warnings: [] };
1715
1840
  * };
1716
1841
  * ```
1717
1842
  *
1718
- * @see {@link VariantsType}
1719
- * @see {@link CommonBuildInterface}
1720
- * @see {@link BaseBuildDefinitionInterface}
1843
+ * @see {@link MaybeVoidPromiseType}
1844
+ * @see {@link BuildContextInterface}
1845
+ * @see {@link LifecycleProvider.onStart}
1721
1846
  *
1722
1847
  * @since 2.0.0
1723
1848
  */
1724
- interface VariantBuildInterface extends BaseBuildDefinitionInterface {
1725
- /**
1726
- * Esbuild-specific configuration for this variant including entry points.
1727
- *
1728
- * @remarks
1729
- * Contains all esbuild options except those managed by the build system.
1730
- * The `entryPoints` field is required and must be non-empty to define what to build.
1731
- *
1732
- * Common options include:
1733
- * - `format`: Output format (esm, cjs, iife)
1734
- * - `outdir` or `outfile`: Output location
1735
- * - `target`: ECMAScript target version
1736
- * - `platform`: Target platform (browser, node, neutral)
1737
- * - `minify`: Whether to minify output
1738
- * - `sourcemap`: Whether to generate source maps
1739
- *
1740
- * @example
1741
- * ```ts
1742
- * esbuild: {
1743
- * entryPoints: ['src/index.ts', 'src/worker.ts'],
1744
- * outdir: 'dist',
1745
- * format: 'esm',
1746
- * target: 'es2020',
1747
- * minify: true,
1748
- * sourcemap: true
1749
- * }
1750
- * ```
1751
- *
1752
- * @since 2.0.0
1753
- */
1754
- esbuild: Omit<BuildOptions, 'plugins' | 'define' | 'banner' | 'footer'>;
1755
- }
1849
+ type OnStartType = (context: BuildContextInterface) => MaybeVoidPromiseType<OnStartResult>;
1756
1850
  /**
1757
- * Shared configuration applied to all build variants.
1758
- * Extends base configuration with esbuild settings but without entry points.
1851
+ * Handler function signature for `onEnd` and `onSuccess` hooks executed when a build completes.
1852
+ *
1853
+ * @param context - Result context containing the build result, duration, arguments, and stage state
1854
+ *
1855
+ * @returns Optional result containing additional errors and warnings to report, or void/null if none
1759
1856
  *
1760
1857
  * @remarks
1761
- * Common configuration provides default settings that apply to all variants unless overridden.
1762
- * This reduces duplication when multiple variants share similar settings.
1858
+ * End hooks are executed after all build operations are complete, regardless of success or failure.
1859
+ * They receive a result context with the final build outcome, calculated duration, and can perform
1860
+ * cleanup, logging, or post-processing tasks.
1763
1861
  *
1764
- * The `esbuild` property excludes managed fields and `entryPoints` (which must be variant-specific).
1765
- * Settings defined here are merged with variant-specific settings, with variants taking precedence.
1862
+ * Success hooks use the same signature but only execute when `context.buildResult.errors.length === 0`,
1863
+ * making them suitable for deployment or success-only operations.
1766
1864
  *
1767
- * Typical use cases:
1768
- * - Shared compiler options (target, platform)
1769
- * - Common minification and sourcemap settings
1770
- * - Shared external dependencies
1771
- * - Default output configuration
1865
+ * Return value semantics:
1866
+ * - Return `void` or `null` if the hook has nothing to report
1867
+ * - Return `OnEndResult` with errors/warnings arrays to add to build output
1868
+ * - Can be synchronous or asynchronous (return a Promise)
1772
1869
  *
1773
1870
  * @example
1774
1871
  * ```ts
1775
- * const common: CommonBuildInterface = {
1776
- * esbuild: {
1777
- * target: 'es2020',
1778
- * platform: 'node',
1779
- * sourcemap: true,
1780
- * external: ['react', 'react-dom']
1781
- * },
1782
- * types: { failOnError: true },
1783
- * declaration: true
1872
+ * const onEnd: OnEndType = async (context) => {
1873
+ * console.log(`${context.variantName} build completed in ${context.duration}ms`);
1874
+ *
1875
+ * if (context.buildResult.errors.length > 0) {
1876
+ * console.error(`Build failed with ${context.buildResult.errors.length} errors`);
1877
+ * } else {
1878
+ * console.log('Build succeeded!');
1879
+ * }
1880
+ *
1881
+ * // Clean up temporary files
1882
+ * await cleanupTempFiles(context.stage.tempDir);
1784
1883
  * };
1785
1884
  * ```
1786
1885
  *
1787
- * @see {@link BaseBuildDefinitionInterface}
1788
- * @see {@link VariantBuildInterface}
1789
- * @see {@link BuildConfigInterface}
1886
+ * @example
1887
+ * ```ts
1888
+ * const onSuccess: OnEndType = async (context) => {
1889
+ * console.log('Deploying build artifacts...');
1890
+ * await deploy(context.buildResult.metafile);
1891
+ * };
1892
+ * ```
1893
+ *
1894
+ * @see {@link MaybeVoidPromiseType}
1895
+ * @see {@link ResultContextInterface}
1896
+ * @see {@link LifecycleProvider.onEnd}
1897
+ * @see {@link LifecycleProvider.onSuccess}
1790
1898
  *
1791
1899
  * @since 2.0.0
1792
1900
  */
1793
- interface CommonBuildInterface extends BaseBuildDefinitionInterface {
1794
- /**
1795
- * Shared esbuild configuration for all variants.
1796
- *
1797
- * @remarks
1798
- * Contains esbuild options that apply to all variants by default. Variants can override
1799
- * any of these settings with their own specific values.
1800
- *
1801
- * Excludes managed fields and `entryPoints` since entry points must be variant-specific.
1802
- *
1803
- * @example
1804
- * ```ts
1805
- * esbuild: {
1806
- * platform: 'node',
1807
- * target: 'node18',
1808
- * external: ['typescript']
1809
- * }
1810
- * ```
1811
- *
1812
- * @since 2.0.0
1813
- */
1814
- esbuild?: Omit<BuildOptions, 'plugins' | 'define' | 'banner' | 'footer'>;
1815
- }
1901
+ type OnEndType = (context: ResultContextInterface) => MaybeVoidPromiseType<OnEndResult>;
1816
1902
  /**
1817
- * Maps variant names to their build configurations.
1818
- * Allows defining multiple build targets with different entry points and settings.
1903
+ * Handler function signature for `onResolve` hooks executed during module path resolution.
1904
+ *
1905
+ * @param context - Resolve context containing resolution arguments, variant name, and stage state
1906
+ *
1907
+ * @returns Optional resolution result to override default resolution, or undefined/null for default behavior
1819
1908
  *
1820
1909
  * @remarks
1821
- * This type represents a collection of named build variants. Each key is a user-defined
1822
- * variant name (e.g., 'esm', 'cjs', 'browser'), and each value is the complete build
1823
- * configuration for that variant.
1910
+ * Resolve hooks are executed when esbuild needs to resolve import paths to file system locations.
1911
+ * They receive a resolve context with the import path, importer information, and can redirect imports,
1912
+ * implement custom resolution algorithms, or provide virtual modules.
1824
1913
  *
1825
- * Variant names are used for:
1826
- * - CLI targeting specific builds
1827
- * - Build output organization
1828
- * - Logging and error reporting
1829
- * - Parallel build coordination
1914
+ * Return value semantics:
1915
+ * - Return `undefined` or `null` to allow default esbuild resolution
1916
+ * - Return `OnResolveResult` to override with custom resolution (path, namespace, external flag, etc.)
1917
+ * - Can be synchronous or asynchronous (return a Promise)
1830
1918
  *
1831
- * @example
1919
+ * Multiple resolve hooks can execute, and their results are merged, with later hooks able to
1920
+ * override properties set by earlier hooks.
1921
+ *
1922
+ * @example
1832
1923
  * ```ts
1833
- * const variants: VariantsType = {
1834
- * esm: {
1835
- * esbuild: {
1836
- * entryPoints: ['src/index.ts'],
1837
- * format: 'esm',
1838
- * outdir: 'dist/esm'
1839
- * }
1840
- * },
1841
- * cjs: {
1842
- * esbuild: {
1843
- * entryPoints: ['src/index.ts'],
1844
- * format: 'cjs',
1845
- * outdir: 'dist/cjs'
1846
- * }
1924
+ * const onResolve: OnResolveType = async (context) => {
1925
+ * const { args, variantName } = context;
1926
+ *
1927
+ * // Redirect '@/' imports to 'src/'
1928
+ * if (args.path.startsWith('@/')) {
1929
+ * return {
1930
+ * path: resolve('src', args.path.slice(2)),
1931
+ * namespace: 'file'
1932
+ * };
1933
+ * }
1934
+ *
1935
+ * // Mark dependencies as external in production
1936
+ * if (variantName === 'production' && args.path.startsWith('lodash')) {
1937
+ * return { path: args.path, external: true };
1847
1938
  * }
1939
+ *
1940
+ * // Allow default resolution
1941
+ * return undefined;
1848
1942
  * };
1849
1943
  * ```
1850
1944
  *
1851
- * @see {@link VariantBuildInterface}
1852
- * @see {@link BuildConfigInterface}
1945
+ * @see {@link ResolveContextInterface}
1946
+ * @see {@link MaybeUndefinedPromiseType}
1947
+ * @see {@link LifecycleProvider.onResolve}
1853
1948
  *
1854
1949
  * @since 2.0.0
1855
1950
  */
1856
- type VariantsType = {
1857
- [variantName: string]: VariantBuildInterface;
1858
- };
1951
+ type OnResolveType = (context: ResolveContextInterface) => MaybeUndefinedPromiseType<OnResolveResult>;
1859
1952
  /**
1860
- * Complete build configuration including common settings, variants, and CLI options.
1861
- * Serves as the root configuration object for the entire build system.
1953
+ * Handler function signature for `onLoad` hooks executed when loading file contents.
1954
+ *
1955
+ * @param context - Load context containing current contents, loader, load arguments, and stage state
1956
+ *
1957
+ * @returns Optional load result to transform contents or change loader, or undefined/null for no changes
1862
1958
  *
1863
1959
  * @remarks
1864
- * This interface defines the complete structure of the build configuration file. It includes:
1865
- * - Optional common settings shared across all variants
1866
- * - Required variants mapping defining all build targets
1867
- * - Optional verbose logging flag
1868
- * - Optional custom command-line argument definitions
1960
+ * Load hooks are executed when esbuild loads file contents and can transform the contents,
1961
+ * change the loader type, or inject additional code. Multiple load hooks execute in a pipeline
1962
+ * pattern where each hook receives the transformed output of previous hooks through the context.
1869
1963
  *
1870
- * The configuration is typically exported from a `build.config.ts` or similar file and
1871
- * loaded by the build system at startup.
1964
+ * Return value semantics:
1965
+ * - Return `undefined` or `null` to pass contents unchanged to the next hook
1966
+ * - Return `OnLoadResult` with `contents` to transform file contents
1967
+ * - Return `OnLoadResult` with `loader` to change the loader type
1968
+ * - Can be synchronous or asynchronous (return a Promise)
1872
1969
  *
1873
- * Configuration resolution:
1874
- * 1. Load the configuration file
1875
- * 2. Parse command-line arguments using `userArgv` definitions
1876
- * 3. Merge common settings with each variant
1877
- * 4. Execute builds for all or selected variants
1970
+ * The `context.contents` property receives the output of previous hooks, and `context.loader`
1971
+ * reflects any loader changes made by previous hooks.
1878
1972
  *
1879
1973
  * @example
1880
1974
  * ```ts
1881
- * const config: BuildConfigInterface = {
1882
- * verbose: true,
1883
- * common: {
1884
- * esbuild: {
1885
- * platform: 'node',
1886
- * target: 'node18'
1887
- * },
1888
- * types: true
1889
- * },
1890
- * variants: {
1891
- * esm: {
1892
- * esbuild: {
1893
- * entryPoints: ['src/index.ts'],
1894
- * format: 'esm',
1895
- * outdir: 'dist/esm'
1896
- * }
1897
- * },
1898
- * cjs: {
1899
- * esbuild: {
1900
- * entryPoints: ['src/index.ts'],
1901
- * format: 'cjs',
1902
- * outdir: 'dist/cjs'
1903
- * }
1904
- * }
1905
- * },
1906
- * userArgv: {
1907
- * watch: { type: 'boolean', description: 'Watch for changes' }
1975
+ * const onLoad: OnLoadType = async (context) => {
1976
+ * const { contents, loader, args, variantName } = context;
1977
+ *
1978
+ * // Transform .custom files to TypeScript
1979
+ * if (args.path.endsWith('.custom')) {
1980
+ * return {
1981
+ * contents: transformCustomSyntax(contents.toString()),
1982
+ * loader: 'ts'
1983
+ * };
1984
+ * }
1985
+ *
1986
+ * // Inject environment variables in development
1987
+ * if (variantName === 'development' && loader === 'js') {
1988
+ * return {
1989
+ * contents: `const ENV = '${variantName}';\n${contents}`,
1990
+ * loader
1991
+ * };
1908
1992
  * }
1993
+ *
1994
+ * // Pass through unchanged
1995
+ * return undefined;
1909
1996
  * };
1910
1997
  * ```
1911
1998
  *
1912
- * @see {@link VariantsType}
1913
- * @see {@link CommonBuildInterface}
1914
- * @see {@link PartialBuildConfigType}
1999
+ * @see {@link LoadContextInterface}
2000
+ * @see {@link LifecycleProvider.onLoad}
2001
+ * @see {@link MaybeUndefinedPromiseType}
1915
2002
  *
1916
2003
  * @since 2.0.0
1917
2004
  */
1918
- interface BuildConfigInterface {
1919
- /**
1920
- * Shared configuration applied to all build variants.
1921
- *
1922
- * @remarks
1923
- * Optional common settings that are merged with each variant's configuration.
1924
- * Variants can override these settings with their own specific values.
1925
- *
1926
- * @see {@link CommonBuildInterface}
1927
- *
1928
- * @since 2.0.0
1929
- */
1930
- common?: CommonBuildInterface;
2005
+ type OnLoadType = (context: LoadContextInterface) => MaybeUndefinedPromiseType<OnLoadResult>;
2006
+ /**
2007
+ * Options used to reload the build service configuration.
2008
+ *
2009
+ * @remarks
2010
+ * These options control how configuration reload behaves:
2011
+ * - `config` replaces the current build configuration
2012
+ * - `clearCache` clears cached file and TypeScript language service state before reloading
2013
+ *
2014
+ * @since 2.3.0
2015
+ */
2016
+ interface ReloadOptionsInterface {
1931
2017
  /**
1932
- * Enable verbose logging output during builds.
2018
+ * Optional new configuration to replace the current one.
1933
2019
  *
1934
2020
  * @remarks
1935
- * When true, outputs detailed build information including file processing,
1936
- * hook execution, and timing information. Useful for debugging build issues.
1937
- *
1938
- * @example
1939
- * ```ts
1940
- * verbose: true // Detailed output
1941
- * verbose: false // Minimal output
1942
- * ```
1943
- *
1944
- * @since 2.0.0
2021
+ * When provided, the build service reloads using this configuration
2022
+ * before recalculating variants.
1945
2023
  */
1946
- verbose?: boolean;
2024
+ config?: PartialBuildConfigType;
1947
2025
  /**
1948
- * Build variant definitions mapping names to configurations.
2026
+ * Whether to clear cached files and TypeScript language service state before reloading.
1949
2027
  *
1950
2028
  * @remarks
1951
- * Required field defining all build targets. At least one variant must be defined.
1952
- * Each variant specifies its own entry points and can override common settings.
1953
- *
1954
- * @see {@link VariantsType}
1955
- *
1956
- * @since 2.0.0
2029
+ * When enabled, cached file tracking and language service state are reset
2030
+ * before the configuration is reloaded.
1957
2031
  */
1958
- variants: VariantsType;
2032
+ clearCache?: boolean;
1959
2033
  }
1960
2034
  /**
1961
- * Partial build configuration for incremental or programmatic configuration building.
1962
- * Allows omitting variants and userArgv while making other fields optional.
2035
+ * Recursively makes all properties of a type optional.
1963
2036
  *
1964
2037
  * @remarks
1965
- * This type is useful when building configuration programmatically or when providing
1966
- * configuration fragments that will be merged with a base configuration. It makes
1967
- * all properties optional except `variants` and `userArgv` which are completely omitted.
2038
+ * This utility type behaves like TypeScript’s built-in {@link Partial} type,
2039
+ * but applies recursively to all nested object properties.
1968
2040
  *
1969
- * Common use cases:
1970
- * - Configuration presets or templates
1971
- * - Programmatic configuration generation
1972
- * - Configuration merging utilities
1973
- * - Partial overrides in build scripts
2041
+ * It is commonly used for:
2042
+ * - Partial configuration overrides
2043
+ * - Patch / update objects
2044
+ * - Programmatic configuration merging
2045
+ * - Build variant and preset definitions
2046
+ *
2047
+ * This type only affects compile-time type checking and has no runtime impact.
2048
+ *
2049
+ * ⚠️ **Important limitations**:
2050
+ * - Arrays and functions are treated as objects and will also be recursively
2051
+ * transformed. If this is undesirable, a more specialized deep-partial
2052
+ * implementation should be used.
2053
+ * - Intended for configuration and data-shaping use cases, not strict domain models.
1974
2054
  *
1975
2055
  * @example
1976
2056
  * ```ts
1977
- * const preset: PartialBuildConfigType = {
1978
- * verbose: true,
1979
- * common: {
1980
- * types: { failOnError: true },
1981
- * declaration: true
1982
- * }
1983
- * };
2057
+ * interface Config {
2058
+ * server: {
2059
+ * host: string;
2060
+ * port: number;
2061
+ * };
2062
+ * features: {
2063
+ * experimental: boolean;
2064
+ * };
2065
+ * }
1984
2066
  *
1985
- * // Merge with full config
1986
- * const fullConfig: BuildConfigInterface = {
1987
- * ...preset,
1988
- * variants: { ... }
2067
+ * const override: DeepPartialType<Config> = {
2068
+ * server: {
2069
+ * port: 8080
2070
+ * }
1989
2071
  * };
1990
2072
  * ```
1991
2073
  *
1992
- * @see {@link BuildConfigInterface}
2074
+ * @template T - The type to recursively make optional.
1993
2075
  *
1994
2076
  * @since 2.0.0
1995
2077
  */
1996
- type PartialBuildConfigType = Partial<BuildConfigInterface>;
2078
+ type DeepPartialType<T> = {
2079
+ [K in keyof T]?: T[K] extends object ? DeepPartialType<T[K]> : T[K];
2080
+ };
1997
2081
  /**
1998
- * Represents a value that may be synchronous, asynchronous, void, null, or the specified type.
1999
- *
2000
- * @template T - The actual value type when present
2082
+ * Represents code that can be injected into build output as a banner or footer.
2083
+ * Can be a static string or a function that generates code dynamically based on build context.
2001
2084
  *
2002
2085
  * @remarks
2003
- * This utility type is used for hook handlers that may return values in multiple forms:
2004
- * - Synchronous return: `T`, `void`, or `null`
2005
- * - Asynchronous return: `Promise<T>`, `Promise<void>`, or `Promise<null>`
2086
+ * This type provides flexibility for injecting code at the top (banner) or bottom (footer) of
2087
+ * bundled output files. The function form receives the plugin name and command-line arguments,
2088
+ * allowing for context-aware code generation.
2006
2089
  *
2007
- * This flexibility allows hooks to be implemented as sync or async functions and to optionally
2008
- * return results. Handlers that don't need to return data can return `void` or `null`.
2090
+ * Common use cases:
2091
+ * - Static banners: Copyright notices, license headers, version information
2092
+ * - Dynamic banners: Build timestamps, environment-specific code, conditional imports
2093
+ * - Footer code: Analytics snippets, polyfills, initialization scripts
2094
+ *
2095
+ * When using the function form, the generated string is cached per build variant to avoid
2096
+ * regenerating the same code multiple times.
2009
2097
  *
2010
2098
  * @example
2011
2099
  * ```ts
2012
- * // All valid implementations
2013
- * const sync: MaybeVoidPromiseType<string> = 'result';
2014
- * const voidSync: MaybeVoidPromiseType<string> = null;
2015
- * const async: MaybeVoidPromiseType<string> = Promise.resolve('result');
2016
- * const voidAsync: MaybeVoidPromiseType<string> = Promise.resolve(null);
2100
+ * // Static banner
2101
+ * const banner: InjectableCodeType = '\/* Copyright 2024 *\/';
2102
+ *
2103
+ * // Dynamic banner
2104
+ * const banner: InjectableCodeType = (name, argv) => {
2105
+ * const version = argv.version || '1.0.0';
2106
+ * return `\/* Built by ${name} v${version} at ${new Date().toISOString()} *\/`;
2107
+ * };
2017
2108
  * ```
2018
2109
  *
2019
- * @see {@link OnEndType}
2020
- * @see {@link OnStartType}
2110
+ * @see {@link BaseBuildDefinitionInterface.banner}
2111
+ * @see {@link BaseBuildDefinitionInterface.footer}
2021
2112
  *
2022
2113
  * @since 2.0.0
2023
2114
  */
2024
- type MaybeVoidPromiseType<T> = void | null | T | Promise<void | null | T>;
2115
+ type InjectableCodeType = string | ((name: string, argv: Record<string, unknown>) => string);
2025
2116
  /**
2026
- * Represents a value that may be synchronous, asynchronous, undefined, null, or the specified type.
2027
- *
2028
- * @template T - The actual value type when present
2117
+ * Defines lifecycle hook handlers for build process stages.
2118
+ * Allows registration of custom logic during resolution, loading, build start, build end, and success.
2029
2119
  *
2030
2120
  * @remarks
2031
- * This utility type is used for hook handlers that may return values in multiple forms:
2032
- * - Synchronous return: `T`, `undefined`, or `null`
2033
- * - Asynchronous return: `Promise<T>`, `Promise<undefined>`, or `Promise<null>`
2121
+ * This interface groups all available lifecycle hooks in a single configuration object.
2122
+ * All hooks are optional, allowing selective registration of only necessary handlers.
2034
2123
  *
2035
- * Similar to {@link MaybeVoidPromiseType} but uses `undefined` instead of `void`, allowing handlers
2036
- * to explicitly return nothing or optionally return results. This distinction is important for
2037
- * hooks where the absence of a return value has semantic meaning (like allowing default behavior).
2124
+ * Hook execution order during a build:
2125
+ * 1. `onStart` - Before any file processing
2126
+ * 2. `onResolve` - During import path resolution
2127
+ * 3. `onLoad` - When loading file contents
2128
+ * 4. `onEnd` - After build completes (success or failure)
2129
+ * 5. `onSuccess` - After a build completes successfully
2130
+ *
2131
+ * Each hook receives a specialized context object appropriate for its lifecycle stage, providing
2132
+ * access to build configuration, variant information, and cross-hook communication through the
2133
+ * shared stage object.
2038
2134
  *
2039
2135
  * @example
2040
2136
  * ```ts
2041
- * // All valid implementations
2042
- * const sync: MaybeUndefinedPromiseType<object> = { path: '/file.ts' };
2043
- * const undefinedSync: MaybeUndefinedPromiseType<object> = undefined;
2044
- * const async: MaybeUndefinedPromiseType<object> = Promise.resolve({ path: '/file.ts' });
2045
- * const undefinedAsync: MaybeUndefinedPromiseType<object> = Promise.resolve(undefined);
2137
+ * const hooks: LifecycleHooksInterface = {
2138
+ * onStart: async (context) => {
2139
+ * console.log(`${context.variantName} build starting...`);
2140
+ * },
2141
+ * onLoad: async (context) => {
2142
+ * if (context.args.path.endsWith('.custom')) {
2143
+ * return { contents: transform(context.contents), loader: 'ts' };
2144
+ * }
2145
+ * },
2146
+ * onSuccess: async (context) => {
2147
+ * console.log(`Build succeeded in ${context.duration}ms!`);
2148
+ * }
2149
+ * };
2046
2150
  * ```
2047
2151
  *
2152
+ * @see {@link OnEndType}
2048
2153
  * @see {@link OnLoadType}
2154
+ * @see {@link OnStartType}
2049
2155
  * @see {@link OnResolveType}
2050
2156
  *
2051
2157
  * @since 2.0.0
2052
2158
  */
2053
- type MaybeUndefinedPromiseType<T> = undefined | null | T | Promise<undefined | null | T>;
2054
- /**
2055
- * Represents a transient build stage state shared across hook handlers during a single build.
2056
- *
2057
- * @remarks
2058
- * This interface provides a flexible container for storing temporary data during the build lifecycle.
2059
- * It's reset at the start of each build and is available to all hooks through the plugin context.
2060
- *
2061
- * The `startTime` property is always present and set when the build begins, allowing hooks to
2062
- * calculate durations and timing information. Additional properties can be added dynamically
2063
- * using the index signature to facilitate cross-handler communication.
2064
- *
2065
- * Common use cases:
2066
- * - Storing build start time for duration calculations
2067
- * - Passing data between different hook handlers
2068
- * - Accumulating statistics during the build
2069
- * - Caching computed values for reuse across hooks
2070
- *
2071
- * @example
2072
- * ```ts
2073
- * // In onStart hook
2074
- * context.stage.startTime = new Date();
2075
- * context.stage.fileCount = 0;
2076
- *
2077
- * // In onLoad hook
2078
- * context.stage.fileCount++;
2079
- *
2080
- * // In onEnd hook
2081
- * const duration = Date.now() - context.stage.startTime.getTime();
2082
- * console.log(`Processed ${context.stage.fileCount} files in ${duration}ms`);
2083
- * ```
2084
- *
2085
- * @see {@link LifecycleContextInterface}
2086
- *
2087
- * @since 2.0.0
2088
- */
2089
- interface LifecycleStageInterface {
2159
+ interface LifecycleHooksInterface {
2090
2160
  /**
2091
- * Timestamp when the build process started.
2161
+ * Hook handler executed when the build completes, regardless of success or failure.
2092
2162
  *
2093
2163
  * @remarks
2094
- * Set during the first `onStart` hook execution and available throughout the build lifecycle.
2095
- * Used to calculate build duration and timing information.
2164
+ * Called after all build operations finish with a result context containing the build result,
2165
+ * calculated duration, variant name, arguments, and stage state. Useful for cleanup, logging,
2166
+ * reporting, and post-processing.
2096
2167
  *
2097
- * @since 2.0.0
2098
- */
2099
- startTime: Date;
2100
- /**
2101
- * Additional dynamic properties for cross-handler communication.
2168
+ * The handler receives `ResultContextInterface` providing access to:
2169
+ * - `buildResult`: Final build outcome with errors and warnings
2170
+ * - `duration`: Build duration in milliseconds
2171
+ * - `variantName`: Build variant identifier
2172
+ * - `argv`: Command-line arguments and configuration
2173
+ * - `stage`: Shared state object for cross-hook communication
2102
2174
  *
2103
- * @remarks
2104
- * Handlers can store arbitrary data in the stage object using any string key.
2105
- * This allows passing information between hooks during a single build.
2175
+ * @example
2176
+ * ```ts
2177
+ * onEnd: async (context) => {
2178
+ * const { buildResult, duration, variantName } = context;
2179
+ * console.log(`${variantName} completed in ${duration}ms`);
2180
+ * if (buildResult.errors.length > 0) {
2181
+ * // Handle errors
2182
+ * }
2183
+ * }
2184
+ * ```
2185
+ *
2186
+ * @see {@link ResultContextInterface}
2106
2187
  *
2107
2188
  * @since 2.0.0
2108
2189
  */
2109
- [key: string]: unknown;
2110
- }
2111
- /**
2112
- * Base context interface shared by all lifecycle hook handlers.
2113
- * Provides access to plugin configuration, command-line arguments, and transient build state.
2114
- *
2115
- * @remarks
2116
- * This context is initialized during the `onStart` phase and remains available throughout the
2117
- * entire build lifecycle. All hook handlers receive a variant of this context, enabling:
2118
- * - Access to command-line arguments and configuration
2119
- * - Cross-handler communication through the stage object
2120
- * - Consistent variant identification across hooks
2121
- *
2122
- * The context is immutable at the top level (variantName and argv don't change during a build),
2123
- * but the stage object is mutable and reset between builds.
2124
- *
2125
- * @example
2126
- * ```ts
2127
- * // In onStart hook
2128
- * const handler: OnStartType = async (context) => {
2129
- * console.log(`Variant ${context.variantName} starting`);
2130
- * context.stage.customData = { processed: 0 };
2131
- * };
2132
- * ```
2133
- *
2134
- * @see {@link LoadContextInterface}
2135
- * @see {@link BuildContextInterface}
2136
- * @see {@link ResultContextInterface}
2137
- * @see {@link ResolveContextInterface}
2138
- * @see {@link LifecycleStageInterface}
2139
- *
2140
- * @since 2.0.0
2141
- */
2142
- interface LifecycleContextInterface {
2190
+ onEnd?: OnEndType;
2143
2191
  /**
2144
- * Command-line arguments and configuration options passed to the provider.
2192
+ * Hook handler executed when loading file contents during module processing.
2145
2193
  *
2146
2194
  * @remarks
2147
- * Contains all CLI options and flags passed when the provider was created.
2148
- * Available to all handlers for accessing build-specific configuration like
2149
- * debug flags, output paths, or custom settings.
2195
+ * Called for each file being processed with a load context containing the current file contents
2196
+ * (potentially transformed by previous hooks), loader type, load arguments, variant name, and
2197
+ * stage state. Can transform contents and change the loader type. Multiple handlers execute in
2198
+ * a pipeline pattern where each receives the output of previous hooks.
2199
+ *
2200
+ * The handler receives `LoadContextInterface` providing access to:
2201
+ * - `contents`: Current file contents (string or binary)
2202
+ * - `loader`: Current loader type (e.g., 'ts', 'js', 'json')
2203
+ * - `args`: Load arguments including file path and namespace
2204
+ * - `variantName`: Build variant identifier
2205
+ * - `argv`: Command-line arguments and configuration
2206
+ * - `stage`: Shared state object for cross-hook communication
2150
2207
  *
2151
2208
  * @example
2152
2209
  * ```ts
2153
- * context.argv; // { debug: true, verbose: false, outdir: 'dist' }
2210
+ * onLoad: async (context) => {
2211
+ * const { contents, args, variantName } = context;
2212
+ * if (args.path.endsWith('.custom')) {
2213
+ * return {
2214
+ * contents: transform(contents.toString()),
2215
+ * loader: 'ts'
2216
+ * };
2217
+ * }
2218
+ * }
2154
2219
  * ```
2155
2220
  *
2221
+ * @see {@link LoadContextInterface}
2222
+ *
2156
2223
  * @since 2.0.0
2157
2224
  */
2158
- argv: Record<string, unknown>;
2225
+ onLoad?: OnLoadType;
2159
2226
  /**
2160
- * Transient state object for cross-handler communication during a single build.
2227
+ * Hook handler executed when the build process begins.
2161
2228
  *
2162
2229
  * @remarks
2163
- * Reset to contain only `startTime` at the beginning of each build. Handlers can store
2164
- * and retrieve temporary data during the build lifecycle through this object.
2230
+ * Called before any file processing starts with a build context containing the esbuild build object,
2231
+ * variant name, arguments, and stage state. Useful for initialization, validation, and setup tasks.
2165
2232
  *
2166
- * Common patterns:
2167
- * - Accumulating statistics across multiple hooks
2168
- * - Passing processed data between different hook types
2169
- * - Caching expensive computations for reuse
2233
+ * The handler receives `BuildContextInterface` providing access to:
2234
+ * - `build`: esbuild plugin build object with configuration and utilities
2235
+ * - `variantName`: Build variant identifier
2236
+ * - `argv`: Command-line arguments and configuration
2237
+ * - `stage`: Shared state object for cross-hook communication
2170
2238
  *
2171
2239
  * @example
2172
2240
  * ```ts
2173
- * // Store data in onLoad
2174
- * context.stage.transformedFiles = [];
2241
+ * onStart: async (context) => {
2242
+ * const { build, variantName, stage } = context;
2243
+ * console.log(`Starting ${variantName} build`);
2244
+ * stage.startTime = new Date();
2175
2245
  *
2176
- * // Access in onEnd
2177
- * console.log(`Transformed ${context.stage.transformedFiles.length} files`);
2246
+ * // Validate configuration
2247
+ * if (!build.initialOptions.outdir) {
2248
+ * return { errors: [{ text: 'Output directory required' }] };
2249
+ * }
2250
+ * }
2178
2251
  * ```
2179
2252
  *
2180
- * @see {@link LifecycleStageInterface}
2253
+ * @see {@link BuildContextInterface}
2181
2254
  *
2182
2255
  * @since 2.0.0
2183
2256
  */
2184
- stage: LifecycleStageInterface;
2257
+ onStart?: OnStartType;
2185
2258
  /**
2186
- * Identifier for the build variant or plugin instance.
2259
+ * Hook handler executed when the build completes successfully without errors.
2187
2260
  *
2188
2261
  * @remarks
2189
- * Used for identification and logging. Same as the variant name passed to
2190
- * the HooksProvider constructor or build configuration.
2262
+ * Only called when `buildResult.errors.length === 0`, after all regular end hooks have completed.
2263
+ * Receives the same result context as end hooks, containing build result, duration, variant name,
2264
+ * arguments, and stage state. Useful for deployment, success notifications, and success-only operations.
2265
+ *
2266
+ * The handler receives `ResultContextInterface` providing access to:
2267
+ * - `buildResult`: Final build outcome (guaranteed to have zero errors)
2268
+ * - `duration`: Build duration in milliseconds
2269
+ * - `variantName`: Build variant identifier
2270
+ * - `argv`: Command-line arguments and configuration
2271
+ * - `stage`: Shared state object for cross-hook communication
2191
2272
  *
2192
2273
  * @example
2193
2274
  * ```ts
2194
- * context.variantName; // 'production' or 'development'
2275
+ * onSuccess: async (context) => {
2276
+ * const { buildResult, duration, variantName } = context;
2277
+ * console.log(`${variantName} succeeded in ${duration}ms!`);
2278
+ * await deploy(buildResult.metafile);
2279
+ * }
2195
2280
  * ```
2196
2281
  *
2282
+ * @see {@link ResultContextInterface}
2283
+ *
2197
2284
  * @since 2.0.0
2198
2285
  */
2199
- variantName: string;
2286
+ onSuccess?: OnEndType;
2200
2287
  /**
2201
- * esbuild configuration options used for this lifecycle execution.
2288
+ * Hook handler executed during module path resolution.
2202
2289
  *
2203
2290
  * @remarks
2204
- * These options represent the active build configuration for the provider and
2205
- * are intended to be read by lifecycle handlers when build behavior depends on
2206
- * entry points, output settings, plugins, or other esbuild flags.
2291
+ * Called when resolving import paths to file system locations with a resolve context containing
2292
+ * the resolution arguments, variant name, and stage state. Can redirect imports, mark modules as
2293
+ * external, or implement custom resolution logic. Multiple handlers execute, and their results are
2294
+ * merged, with later hooks able to override earlier ones.
2207
2295
  *
2208
- * @since 2.2.0
2209
- */
2210
- options: BuildOptions;
2211
- }
2212
- /**
2213
- * Context interface for `onStart` hooks, providing access to the esbuild plugin build object.
2214
- *
2215
- * @remarks
2216
- * This specialized context extends the base lifecycle context with the esbuild `PluginBuild`
2217
- * object, giving start hooks access to build configuration, utilities, and the ability to
2218
- * register additional esbuild hooks dynamically.
2219
- *
2220
- * Start hooks are the only lifecycle phase that receives the build object, as they execute
2221
- * before file processing begins and may need to configure or inspect build settings.
2222
- *
2223
- * @example
2224
- * ```ts
2225
- * const handler: OnStartType = async (context) => {
2226
- * const { build, variantName, argv } = context;
2227
- * console.log(`Starting ${variantName} build`);
2228
- *
2229
- * // Access build configuration
2230
- * console.log(`Platform: ${build.initialOptions.platform}`);
2231
- *
2232
- * return { errors: [], warnings: [] };
2233
- * };
2234
- * ```
2235
- *
2236
- * @see {@link OnStartType}
2237
- * @see {@link LifecycleContextInterface}
2238
- *
2239
- * @since 2.0.0
2240
- */
2241
- interface BuildContextInterface extends LifecycleContextInterface {
2242
- /**
2243
- * The esbuild plugin build object providing build configuration and utilities.
2244
- *
2245
- * @remarks
2246
- * Provides access to:
2247
- * - `initialOptions`: Build configuration options
2248
- * - `resolve`: Path resolution utilities
2249
- * - Dynamic hook registration methods
2250
- * - Build environment information
2251
- *
2252
- * Available only in `onStart` hooks, as later phases don't require build-level access.
2296
+ * The handler receives `ResolveContextInterface` providing access to:
2297
+ * - `args`: Resolution arguments including import path and importer info
2298
+ * - `variantName`: Build variant identifier
2299
+ * - `argv`: Command-line arguments and configuration
2300
+ * - `stage`: Shared state object for cross-hook communication
2253
2301
  *
2254
2302
  * @example
2255
2303
  * ```ts
2256
- * // Access initial options
2257
- * const outdir = context.build.initialOptions.outdir;
2304
+ * onResolve: async (context) => {
2305
+ * const { args, variantName } = context;
2258
2306
  *
2259
- * // Resolve a path
2260
- * const resolved = await context.build.resolve('./module', {
2261
- * resolveDir: '/src'
2262
- * });
2307
+ * // Redirect '@/' imports to 'src/'
2308
+ * if (args.path.startsWith('@/')) {
2309
+ * return {
2310
+ * path: resolve('src', args.path.slice(2)),
2311
+ * namespace: 'file'
2312
+ * };
2313
+ * }
2314
+ *
2315
+ * // Mark as external in production
2316
+ * if (variantName === 'production' && args.path.includes('node_modules')) {
2317
+ * return { path: args.path, external: true };
2318
+ * }
2319
+ * }
2263
2320
  * ```
2264
2321
  *
2322
+ * @see {@link ResolveContextInterface}
2323
+ *
2265
2324
  * @since 2.0.0
2266
2325
  */
2267
- build: PluginBuild;
2326
+ onResolve?: OnResolveType;
2268
2327
  }
2269
2328
  /**
2270
- * Context interface for `onEnd` and `onSuccess` hooks, providing access to build results and duration.
2329
+ * Configuration options for TypeScript declaration file generation.
2271
2330
  *
2272
2331
  * @remarks
2273
- * This specialized context extends the base lifecycle context with the final build result
2274
- * and calculated build duration, giving end hooks access to a build outcome, errors, warnings,
2275
- * and metadata.
2332
+ * Controls how and where TypeScript declaration files (`.d.ts`) are generated during the build.
2333
+ * These options work in conjunction with the TypeScript compiler to produce type definitions
2334
+ * for bundled code.
2276
2335
  *
2277
- * The duration is automatically calculated from the start time in the stage object, providing
2278
- * a convenient way to measure build performance without manual timestamp calculations.
2336
+ * When `bundle` is true, declarations from multiple source files are combined into a single
2337
+ * declaration file per entry point. When false, individual declaration files are generated
2338
+ * for each source file.
2279
2339
  *
2280
2340
  * @example
2281
2341
  * ```ts
2282
- * const handler: OnEndType = async (context) => {
2283
- * const { buildResult, duration, variantName } = context;
2284
- *
2285
- * console.log(`${variantName} build completed in ${duration}ms`);
2286
- *
2287
- * if (buildResult.errors.length > 0) {
2288
- * console.error(`Build failed with ${buildResult.errors.length} errors`);
2289
- * }
2290
- *
2291
- * // Access metafile for dependency analysis
2292
- * if (buildResult.metafile) {
2293
- * console.log('Outputs:', Object.keys(buildResult.metafile.outputs));
2294
- * }
2342
+ * // Generate bundled declarations in custom directory
2343
+ * const options: DeclarationOptionsInterface = {
2344
+ * outDir: 'types',
2345
+ * bundle: true
2295
2346
  * };
2296
2347
  * ```
2297
2348
  *
2298
- * @see {@link OnEndType}
2299
- * @see {@link LifecycleContextInterface}
2349
+ * @see {@link BaseBuildDefinitionInterface.declaration}
2300
2350
  *
2301
2351
  * @since 2.0.0
2302
2352
  */
2303
- interface ResultContextInterface extends LifecycleContextInterface {
2353
+ interface DeclarationOptionsInterface {
2304
2354
  /**
2305
- * Build duration in milliseconds.
2355
+ * Output directory for generated declaration files.
2306
2356
  *
2307
2357
  * @remarks
2308
- * Automatically calculated as the time elapsed from `context.stage.startTime` to
2309
- * when the build completed. Useful for performance monitoring and reporting.
2358
+ * Specifies where `.d.ts` files should be written. If not provided, uses the TypeScript
2359
+ * compiler's `declarationDir` or `outDir` from `tsconfig.json`.
2310
2360
  *
2311
2361
  * @example
2312
2362
  * ```ts
2313
- * console.log(`Build took ${context.duration}ms`);
2363
+ * outDir: 'dist/types'
2314
2364
  * ```
2315
2365
  *
2316
2366
  * @since 2.0.0
2317
2367
  */
2318
- duration: number;
2368
+ outDir?: string;
2319
2369
  /**
2320
- * The final build result from esbuild containing errors, warnings, and metadata.
2370
+ * Whether to bundle declarations into a single file per entry point.
2321
2371
  *
2322
2372
  * @remarks
2323
- * Provides access to:
2324
- * - `errors`: Array of build errors
2325
- * - `warnings`: Array of build warnings
2326
- * - `metafile`: Build metadata including inputs, outputs, and dependencies
2327
- * - `outputFiles`: Generated file contents (if `write: false`)
2373
+ * When true, combines all declarations from imported modules into a single `.d.ts` file.
2374
+ * When false, generates individual declaration files mirroring the source structure.
2375
+ *
2376
+ * Bundling is useful for library distribution as it provides a single type definition file
2377
+ * that consumers can reference.
2328
2378
  *
2329
2379
  * @example
2330
2380
  * ```ts
2331
- * // Check for errors
2332
- * if (context.buildResult.errors.length > 0) {
2333
- * // Handle build failure
2334
- * }
2335
- *
2336
- * // Analyze dependencies
2337
- * const inputs = context.buildResult.metafile?.inputs;
2381
+ * bundle: true // Produces single bundled .d.ts
2382
+ * bundle: false // Produces multiple .d.ts files
2338
2383
  * ```
2339
2384
  *
2340
2385
  * @since 2.0.0
2341
2386
  */
2342
- buildResult: BuildResult;
2387
+ bundle?: boolean;
2343
2388
  }
2344
2389
  /**
2345
- * Context interface for `onResolve` hooks, providing access to resolution arguments.
2390
+ * Configuration options for TypeScript type checking during builds.
2346
2391
  *
2347
2392
  * @remarks
2348
- * This specialized context extends the base lifecycle context with esbuild's resolution
2349
- * arguments, giving resolve hooks access to the import path, importer information, and
2350
- * resolution context needed to implement custom module resolution logic.
2351
- *
2352
- * Resolve hooks use this context to determine how to resolve import paths, redirect imports,
2353
- * or mark modules as external based on the resolution arguments.
2393
+ * Controls how TypeScript type checking is performed and whether type errors should fail the build.
2394
+ * Type checking runs in parallel with the esbuild compilation process for better performance.
2354
2395
  *
2355
2396
  * @example
2356
2397
  * ```ts
2357
- * const handler: OnResolveType = async (context) => {
2358
- * const { args, variantName } = context;
2359
- *
2360
- * // Redirect '@/' imports to 'src/'
2361
- * if (args.path.startsWith('@/')) {
2362
- * return {
2363
- * path: resolve('src', args.path.slice(2)),
2364
- * namespace: 'file'
2365
- * };
2366
- * }
2367
- *
2368
- * // Mark node_modules as external in development
2369
- * if (variantName === 'development' && args.path.includes('node_modules')) {
2370
- * return { path: args.path, external: true };
2371
- * }
2372
- *
2373
- * return undefined; // Use default resolution
2398
+ * // Fail build on type errors
2399
+ * const options: TypeCheckOptionsInterface = {
2400
+ * failOnError: true
2374
2401
  * };
2375
2402
  * ```
2376
2403
  *
2377
- * @see {@link OnResolveType}
2378
- * @see {@link LifecycleContextInterface}
2404
+ * @see {@link BaseBuildDefinitionInterface.types}
2379
2405
  *
2380
2406
  * @since 2.0.0
2381
2407
  */
2382
- interface ResolveContextInterface extends LifecycleContextInterface {
2408
+ interface TypeCheckOptionsInterface {
2383
2409
  /**
2384
- * Resolution arguments from esbuild containing the import path and resolution context.
2410
+ * Whether to fail the build when TypeScript errors are detected.
2385
2411
  *
2386
2412
  * @remarks
2387
- * Provides access to:
2388
- * - `path`: The import path to resolve (e.g., './module', '\@/utils')
2389
- * - `importer`: The file that contains this import
2390
- * - `namespace`: The namespace of the importer
2391
- * - `resolveDir`: The directory to resolve relative imports from
2392
- * - `kind`: The kind of import (e.g., 'import-statement', 'require-call')
2393
- * - `pluginData`: Data passed from previous plugins
2413
+ * When true, any TypeScript errors will cause the build to fail with a non-zero exit code.
2414
+ * When false, errors are logged, but the build continues and succeeds.
2415
+ *
2416
+ * Useful in CI/CD pipelines where type safety must be enforced before deployment.
2394
2417
  *
2395
2418
  * @example
2396
2419
  * ```ts
2397
- * console.log(`Resolving ${context.args.path} from ${context.args.importer}`);
2398
- *
2399
- * if (context.args.kind === 'dynamic-import') {
2400
- * // Handle dynamic imports specially
2401
- * }
2420
+ * failOnError: true // Build fails on type errors
2421
+ * failOnError: false // Type errors logged, but build continues
2402
2422
  * ```
2403
2423
  *
2404
2424
  * @since 2.0.0
2405
2425
  */
2406
- args: OnResolveArgs;
2426
+ failOnError?: boolean;
2407
2427
  }
2408
2428
  /**
2409
- * Context interface for `onLoad` hooks, providing access to load arguments, current contents, and loader.
2429
+ * Base configuration shared across all build definitions, including common and variant builds.
2430
+ * Provides common settings for hooks, type checking, code injection, and declaration generation.
2410
2431
  *
2411
2432
  * @remarks
2412
- * This specialized context extends the base lifecycle context with esbuild's load arguments,
2413
- * the current file contents (potentially transformed by previous hooks), and the current loader
2414
- * type. This enables load hooks to implement content transformations in a pipeline pattern.
2433
+ * This interface defines the foundation for build configuration that applies to both common
2434
+ * settings and individual build variants. Properties defined here can be overridden at the
2435
+ * variant level for customization.
2415
2436
  *
2416
- * Load hooks receive the output of previous hooks through `contents` and `loader`, allowing
2417
- * sequential transformations where each hook builds on the work of previous hooks.
2437
+ * Configuration inheritance:
2438
+ * - Common build settings apply to all variants
2439
+ * - Variant settings override common settings
2440
+ * - Objects like `define` are merged (variant takes precedence)
2441
+ * - Arrays and primitives replace common values
2418
2442
  *
2419
2443
  * @example
2420
2444
  * ```ts
2421
- * const handler: OnLoadType = async (context) => {
2422
- * const { contents, loader, args, variantName } = context;
2423
- *
2424
- * // Transform .custom files to TypeScript
2425
- * if (args.path.endsWith('.custom')) {
2426
- * return {
2427
- * contents: transformCustomSyntax(contents.toString()),
2428
- * loader: 'ts'
2429
- * };
2430
- * }
2431
- *
2432
- * // Add debugging in development
2433
- * if (variantName === 'development' && loader === 'ts') {
2434
- * return {
2435
- * contents: `console.log('Loading: ${args.path}');\n${contents}`,
2436
- * loader
2437
- * };
2445
+ * const base: BaseBuildDefinitionInterface = {
2446
+ * types: { failOnError: true },
2447
+ * declaration: { bundle: true, outDir: 'types' },
2448
+ * define: { 'process.env.NODE_ENV': '"production"' },
2449
+ * banner: 'const x = "test"',
2450
+ * hooks: {
2451
+ * onSuccess: async () => console.log('Build complete!')
2438
2452
  * }
2439
- *
2440
- * return undefined; // Pass through unchanged
2441
2453
  * };
2442
2454
  * ```
2443
2455
  *
2444
- * @see {@link OnLoadType}
2445
- * @see {@link LifecycleContextInterface}
2456
+ * @see {@link CommonBuildInterface}
2457
+ * @see {@link VariantBuildInterface}
2458
+ * @see {@link BuildConfigInterface}
2446
2459
  *
2447
2460
  * @since 2.0.0
2448
2461
  */
2449
- interface LoadContextInterface extends LifecycleContextInterface {
2462
+ interface BaseBuildDefinitionInterface {
2450
2463
  /**
2451
- * Load arguments from esbuild containing file path and namespace.
2464
+ * Lifecycle hook handlers for build process stages.
2452
2465
  *
2453
2466
  * @remarks
2454
- * Provides access to:
2455
- * - `path`: The absolute path to the file being loaded
2456
- * - `namespace`: The namespace for this module
2457
- * - `suffix`: Optional suffix for special handling
2458
- * - `pluginData`: Data passed from resolve hooks or previous plugins
2467
+ * Registers custom handlers for various build lifecycle events including start, resolve,
2468
+ * load, end, and success stages. All hooks are optional.
2459
2469
  *
2460
- * @example
2461
- * ```ts
2462
- * console.log(`Loading ${context.args.path}`);
2470
+ * @see {@link LifecycleHooksInterface}
2463
2471
  *
2464
- * if (context.args.namespace === 'virtual') {
2465
- * // Handle virtual modules
2466
- * }
2472
+ * @since 2.0.0
2473
+ */
2474
+ lifecycle?: LifecycleHooksInterface;
2475
+ /**
2476
+ * TypeScript type checking configuration.
2477
+ *
2478
+ * @remarks
2479
+ * Controls whether and how TypeScript type checking is performed during builds.
2480
+ * - `true`: Enable type checking with default options
2481
+ * - `false` or omitted: Disable type checking
2482
+ * - Object: Enable with specific options like `failOnError`
2483
+ *
2484
+ * @example
2485
+ * ```ts
2486
+ * types: true // Enable with default
2487
+ * types: { failOnError: true } // Enable and fail on errors
2488
+ * types: false // Disable
2467
2489
  * ```
2468
2490
  *
2491
+ * @see {@link TypeCheckOptionsInterface}
2492
+ *
2469
2493
  * @since 2.0.0
2470
2494
  */
2471
- args: OnLoadArgs;
2495
+ types?: boolean | TypeCheckOptionsInterface;
2472
2496
  /**
2473
- * The current loader type for this file.
2497
+ * Global constants to replace during bundling.
2474
2498
  *
2475
2499
  * @remarks
2476
- * Reflects any loader changes made by previous hooks in the pipeline. Can be:
2477
- * - `'js'`, `'ts'`, `'jsx'`, `'tsx'`: JavaScript/TypeScript variants
2478
- * - `'json'`, `'css'`, `'text'`: Special content types
2479
- * - `'base64'`, `'binary'`, `'dataurl'`: Binary content encodings
2480
- * - `'default'`: Let esbuild determine the loader
2481
- * - `undefined`: No loader has been set yet
2500
+ * Defines key-value pairs for constant replacement during the build. Keys are identifiers
2501
+ * or property access expressions, values are JSON-stringified replacements.
2482
2502
  *
2483
- * Hooks can change the loader to affect how esbuild processes the contents.
2503
+ * Commonly used for environment variables, feature flags, and build-time constants.
2484
2504
  *
2485
2505
  * @example
2486
2506
  * ```ts
2487
- * if (context.loader === 'json') {
2488
- * // Transform JSON before esbuild processes it
2507
+ * define: {
2508
+ * 'process.env.NODE_ENV': '"production"',
2509
+ * 'DEBUG': 'false',
2510
+ * 'VERSION': '"1.2.3"'
2489
2511
  * }
2490
2512
  * ```
2491
2513
  *
2492
2514
  * @since 2.0.0
2493
2515
  */
2494
- loader: Loader | undefined;
2516
+ define?: Record<string, unknown>;
2495
2517
  /**
2496
- * The current file contents as string or binary data.
2518
+ * Code to inject at the beginning of each output file.
2497
2519
  *
2498
2520
  * @remarks
2499
- * Contains the output of previous load hooks in the pipeline, or the initial file
2500
- * contents if this is the first hook. Hooks can transform this content and return
2501
- * new contents for further hooks to process.
2521
+ * Can be a static string or a function that generates code based on build context.
2522
+ * Commonly used for copyright notices, license headers, or polyfill imports.
2502
2523
  *
2503
- * Content can be:
2504
- * - `string`: Text content (source code, JSON, CSS, etc.)
2505
- * - `Uint8Array`: Binary content (images, fonts, etc.)
2524
+ * @example
2525
+ * ```ts
2526
+ * banner: 'const x = "test"'
2527
+ * banner: (name, argv) => `const x = "Built: ${new Date().toISOString()}"`
2528
+ * ```
2529
+ *
2530
+ * @see {@link InjectableCodeType}
2531
+ *
2532
+ * @since 2.0.0
2533
+ */
2534
+ banner?: {
2535
+ [key: string]: InjectableCodeType;
2536
+ };
2537
+ /**
2538
+ * Code to inject at the end of each output file.
2539
+ *
2540
+ * @remarks
2541
+ * Can be a static string or a function that generates code based on build context.
2542
+ * Commonly used for initialization code, analytics, or polyfills.
2506
2543
  *
2507
2544
  * @example
2508
2545
  * ```ts
2509
- * // Transform string contents
2510
- * const transformed = context.contents.toString().replace(/old/g, 'new');
2546
+ * footer: '// End of bundle'
2547
+ * footer: (name, argv) => `console.log('Loaded ${name}');`
2548
+ * ```
2511
2549
  *
2512
- * // Check content type
2513
- * if (typeof context.contents === 'string') {
2514
- * // Handle text
2515
- * } else {
2516
- * // Handle binary
2517
- * }
2550
+ * @see {@link InjectableCodeType}
2551
+ *
2552
+ * @since 2.0.0
2553
+ */
2554
+ footer?: {
2555
+ [key: string]: InjectableCodeType;
2556
+ };
2557
+ /**
2558
+ * TypeScript declaration file generation configuration.
2559
+ *
2560
+ * @remarks
2561
+ * Controls whether and how TypeScript declaration files are generated.
2562
+ * - `true`: Generate declarations with default options
2563
+ * - `false` or omitted: Do not generate declarations
2564
+ * - Object: Generate with specific options like `outDir` and `bundle`
2565
+ *
2566
+ * @example
2567
+ * ```ts
2568
+ * declaration: true // Generate with default
2569
+ * declaration: { outDir: 'types', bundle: true } // Generate bundled in custom dir
2570
+ * declaration: false // Disable
2518
2571
  * ```
2519
2572
  *
2573
+ * @see {@link DeclarationOptionsInterface}
2574
+ *
2520
2575
  * @since 2.0.0
2521
2576
  */
2522
- contents: string | Uint8Array;
2577
+ declaration?: boolean | DeclarationOptionsInterface;
2523
2578
  }
2524
2579
  /**
2525
- * Handler function signature for `onStart` hooks executed when a build begins.
2526
- *
2527
- * @param context - Build context containing the esbuild build object, arguments, and stage state
2528
- *
2529
- * @returns Optional result containing errors and warnings to report, or void/null if none
2580
+ * Build configuration for a specific build variant including esbuild settings and entry points.
2581
+ * Extends base configuration with variant-specific esbuild options and required entry points.
2530
2582
  *
2531
2583
  * @remarks
2532
- * Start hooks are executed before any file processing occurs and receive a build context
2533
- * with access to the esbuild `PluginBuild` object. They can perform initialization tasks
2534
- * and return errors or warnings that will be aggregated with results from other start hooks.
2584
+ * A variant represents a distinct build target with its own entry points and esbuild configuration.
2585
+ * Variants inherit settings from the common configuration but can override any property.
2535
2586
  *
2536
- * Return value semantics:
2537
- * - Return `void` or `null` if the hook has nothing to report
2538
- * - Return `OnStartResult` with errors/warnings arrays to report issues
2539
- * - Can be synchronous or asynchronous (return a Promise)
2587
+ * The `esbuild` property excludes fields that are managed by the build system:
2588
+ * - `plugins`: Managed by the hook provider
2589
+ * - `define`, `banner`, `footer`: Managed by base configuration
2590
+ * - `entryPoints`: Required at variant level (non-nullable)
2591
+ *
2592
+ * Multiple variants enable building different outputs from the same codebase, such as
2593
+ * - Different module formats (ESM, CJS)
2594
+ * - Different targets (Node.js, browser)
2595
+ * - Different bundles (main, worker, tests)
2540
2596
  *
2541
2597
  * @example
2542
2598
  * ```ts
2543
- * const onStart: OnStartType = async (context) => {
2544
- * console.log(`Starting ${context.variantName} build`);
2545
- * context.stage.startTime = new Date();
2546
- *
2547
- * // Validate build configuration
2548
- * if (!context.build.initialOptions.outdir) {
2549
- * return {
2550
- * errors: [{
2551
- * text: 'Output directory not specified',
2552
- * location: null
2553
- * }]
2554
- * };
2555
- * }
2556
- *
2557
- * return { errors: [], warnings: [] };
2599
+ * const variant: VariantBuildInterface = {
2600
+ * esbuild: {
2601
+ * entryPoints: ['src/index.ts'],
2602
+ * outdir: 'dist/esm',
2603
+ * format: 'esm',
2604
+ * target: 'es2020'
2605
+ * },
2606
+ * types: true,
2607
+ * declaration: { bundle: true, outDir: 'dist/types' }
2558
2608
  * };
2559
2609
  * ```
2560
2610
  *
2561
- * @see {@link MaybeVoidPromiseType}
2562
- * @see {@link BuildContextInterface}
2563
- * @see {@link LifecycleProvider.onStart}
2611
+ * @see {@link VariantsType}
2612
+ * @see {@link CommonBuildInterface}
2613
+ * @see {@link BaseBuildDefinitionInterface}
2564
2614
  *
2565
2615
  * @since 2.0.0
2566
2616
  */
2567
- type OnStartType = (context: BuildContextInterface) => MaybeVoidPromiseType<OnStartResult>;
2617
+ interface VariantBuildInterface extends BaseBuildDefinitionInterface {
2618
+ /**
2619
+ * Esbuild-specific configuration for this variant including entry points.
2620
+ *
2621
+ * @remarks
2622
+ * Contains all esbuild options except those managed by the build system.
2623
+ * The `entryPoints` field is required and must be non-empty to define what to build.
2624
+ *
2625
+ * Common options include:
2626
+ * - `format`: Output format (esm, cjs, iife)
2627
+ * - `outdir` or `outfile`: Output location
2628
+ * - `target`: ECMAScript target version
2629
+ * - `platform`: Target platform (browser, node, neutral)
2630
+ * - `minify`: Whether to minify output
2631
+ * - `sourcemap`: Whether to generate source maps
2632
+ *
2633
+ * @example
2634
+ * ```ts
2635
+ * esbuild: {
2636
+ * entryPoints: ['src/index.ts', 'src/worker.ts'],
2637
+ * outdir: 'dist',
2638
+ * format: 'esm',
2639
+ * target: 'es2020',
2640
+ * minify: true,
2641
+ * sourcemap: true
2642
+ * }
2643
+ * ```
2644
+ *
2645
+ * @since 2.0.0
2646
+ */
2647
+ esbuild: Omit<BuildOptions, 'plugins' | 'define' | 'banner' | 'footer'>;
2648
+ }
2568
2649
  /**
2569
- * Handler function signature for `onEnd` and `onSuccess` hooks executed when a build completes.
2570
- *
2571
- * @param context - Result context containing the build result, duration, arguments, and stage state
2572
- *
2573
- * @returns Optional result containing additional errors and warnings to report, or void/null if none
2650
+ * Shared configuration applied to all build variants.
2651
+ * Extends base configuration with esbuild settings but without entry points.
2574
2652
  *
2575
2653
  * @remarks
2576
- * End hooks are executed after all build operations are complete, regardless of success or failure.
2577
- * They receive a result context with the final build outcome, calculated duration, and can perform
2578
- * cleanup, logging, or post-processing tasks.
2579
- *
2580
- * Success hooks use the same signature but only execute when `context.buildResult.errors.length === 0`,
2581
- * making them suitable for deployment or success-only operations.
2582
- *
2583
- * Return value semantics:
2584
- * - Return `void` or `null` if the hook has nothing to report
2585
- * - Return `OnEndResult` with errors/warnings arrays to add to build output
2586
- * - Can be synchronous or asynchronous (return a Promise)
2587
- *
2588
- * @example
2589
- * ```ts
2590
- * const onEnd: OnEndType = async (context) => {
2591
- * console.log(`${context.variantName} build completed in ${context.duration}ms`);
2654
+ * Common configuration provides default settings that apply to all variants unless overridden.
2655
+ * This reduces duplication when multiple variants share similar settings.
2592
2656
  *
2593
- * if (context.buildResult.errors.length > 0) {
2594
- * console.error(`Build failed with ${context.buildResult.errors.length} errors`);
2595
- * } else {
2596
- * console.log('Build succeeded!');
2597
- * }
2657
+ * The `esbuild` property excludes managed fields and `entryPoints` (which must be variant-specific).
2658
+ * Settings defined here are merged with variant-specific settings, with variants taking precedence.
2598
2659
  *
2599
- * // Clean up temporary files
2600
- * await cleanupTempFiles(context.stage.tempDir);
2601
- * };
2602
- * ```
2660
+ * Typical use cases:
2661
+ * - Shared compiler options (target, platform)
2662
+ * - Common minification and sourcemap settings
2663
+ * - Shared external dependencies
2664
+ * - Default output configuration
2603
2665
  *
2604
2666
  * @example
2605
2667
  * ```ts
2606
- * const onSuccess: OnEndType = async (context) => {
2607
- * console.log('Deploying build artifacts...');
2608
- * await deploy(context.buildResult.metafile);
2668
+ * const common: CommonBuildInterface = {
2669
+ * esbuild: {
2670
+ * target: 'es2020',
2671
+ * platform: 'node',
2672
+ * sourcemap: true,
2673
+ * external: ['react', 'react-dom']
2674
+ * },
2675
+ * types: { failOnError: true },
2676
+ * declaration: true
2609
2677
  * };
2610
2678
  * ```
2611
2679
  *
2612
- * @see {@link MaybeVoidPromiseType}
2613
- * @see {@link ResultContextInterface}
2614
- * @see {@link LifecycleProvider.onEnd}
2615
- * @see {@link LifecycleProvider.onSuccess}
2680
+ * @see {@link BaseBuildDefinitionInterface}
2681
+ * @see {@link VariantBuildInterface}
2682
+ * @see {@link BuildConfigInterface}
2616
2683
  *
2617
2684
  * @since 2.0.0
2618
2685
  */
2619
- type OnEndType = (context: ResultContextInterface) => MaybeVoidPromiseType<OnEndResult>;
2686
+ interface CommonBuildInterface extends BaseBuildDefinitionInterface {
2687
+ /**
2688
+ * Shared esbuild configuration for all variants.
2689
+ *
2690
+ * @remarks
2691
+ * Contains esbuild options that apply to all variants by default. Variants can override
2692
+ * any of these settings with their own specific values.
2693
+ *
2694
+ * Excludes managed fields and `entryPoints` since entry points must be variant-specific.
2695
+ *
2696
+ * @example
2697
+ * ```ts
2698
+ * esbuild: {
2699
+ * platform: 'node',
2700
+ * target: 'node18',
2701
+ * external: ['typescript']
2702
+ * }
2703
+ * ```
2704
+ *
2705
+ * @since 2.0.0
2706
+ */
2707
+ esbuild?: Omit<BuildOptions, 'plugins' | 'define' | 'banner' | 'footer'>;
2708
+ }
2620
2709
  /**
2621
- * Handler function signature for `onResolve` hooks executed during module path resolution.
2622
- *
2623
- * @param context - Resolve context containing resolution arguments, variant name, and stage state
2624
- *
2625
- * @returns Optional resolution result to override default resolution, or undefined/null for default behavior
2710
+ * Maps variant names to their build configurations.
2711
+ * Allows defining multiple build targets with different entry points and settings.
2626
2712
  *
2627
2713
  * @remarks
2628
- * Resolve hooks are executed when esbuild needs to resolve import paths to file system locations.
2629
- * They receive a resolve context with the import path, importer information, and can redirect imports,
2630
- * implement custom resolution algorithms, or provide virtual modules.
2631
- *
2632
- * Return value semantics:
2633
- * - Return `undefined` or `null` to allow default esbuild resolution
2634
- * - Return `OnResolveResult` to override with custom resolution (path, namespace, external flag, etc.)
2635
- * - Can be synchronous or asynchronous (return a Promise)
2714
+ * This type represents a collection of named build variants. Each key is a user-defined
2715
+ * variant name (e.g., 'esm', 'cjs', 'browser'), and each value is the complete build
2716
+ * configuration for that variant.
2636
2717
  *
2637
- * Multiple resolve hooks can execute, and their results are merged, with later hooks able to
2638
- * override properties set by earlier hooks.
2718
+ * Variant names are used for:
2719
+ * - CLI targeting specific builds
2720
+ * - Build output organization
2721
+ * - Logging and error reporting
2722
+ * - Parallel build coordination
2639
2723
  *
2640
2724
  * @example
2641
2725
  * ```ts
2642
- * const onResolve: OnResolveType = async (context) => {
2643
- * const { args, variantName } = context;
2644
- *
2645
- * // Redirect '@/' imports to 'src/'
2646
- * if (args.path.startsWith('@/')) {
2647
- * return {
2648
- * path: resolve('src', args.path.slice(2)),
2649
- * namespace: 'file'
2650
- * };
2651
- * }
2652
- *
2653
- * // Mark dependencies as external in production
2654
- * if (variantName === 'production' && args.path.startsWith('lodash')) {
2655
- * return { path: args.path, external: true };
2726
+ * const variants: VariantsType = {
2727
+ * esm: {
2728
+ * esbuild: {
2729
+ * entryPoints: ['src/index.ts'],
2730
+ * format: 'esm',
2731
+ * outdir: 'dist/esm'
2732
+ * }
2733
+ * },
2734
+ * cjs: {
2735
+ * esbuild: {
2736
+ * entryPoints: ['src/index.ts'],
2737
+ * format: 'cjs',
2738
+ * outdir: 'dist/cjs'
2739
+ * }
2656
2740
  * }
2657
- *
2658
- * // Allow default resolution
2659
- * return undefined;
2660
2741
  * };
2661
2742
  * ```
2662
2743
  *
2663
- * @see {@link ResolveContextInterface}
2664
- * @see {@link MaybeUndefinedPromiseType}
2665
- * @see {@link LifecycleProvider.onResolve}
2744
+ * @see {@link VariantBuildInterface}
2745
+ * @see {@link BuildConfigInterface}
2666
2746
  *
2667
2747
  * @since 2.0.0
2668
2748
  */
2669
- type OnResolveType = (context: ResolveContextInterface) => MaybeUndefinedPromiseType<OnResolveResult>;
2749
+ type VariantsType = {
2750
+ [variantName: string]: VariantBuildInterface;
2751
+ };
2670
2752
  /**
2671
- * Handler function signature for `onLoad` hooks executed when loading file contents.
2672
- *
2673
- * @param context - Load context containing current contents, loader, load arguments, and stage state
2674
- *
2675
- * @returns Optional load result to transform contents or change loader, or undefined/null for no changes
2753
+ * Complete build configuration including common settings, variants, and CLI options.
2754
+ * Serves as the root configuration object for the entire build system.
2676
2755
  *
2677
2756
  * @remarks
2678
- * Load hooks are executed when esbuild loads file contents and can transform the contents,
2679
- * change the loader type, or inject additional code. Multiple load hooks execute in a pipeline
2680
- * pattern where each hook receives the transformed output of previous hooks through the context.
2757
+ * This interface defines the complete structure of the build configuration file. It includes:
2758
+ * - Optional common settings shared across all variants
2759
+ * - Required variants mapping defining all build targets
2760
+ * - Optional verbose logging flag
2761
+ * - Optional custom command-line argument definitions
2681
2762
  *
2682
- * Return value semantics:
2683
- * - Return `undefined` or `null` to pass contents unchanged to the next hook
2684
- * - Return `OnLoadResult` with `contents` to transform file contents
2685
- * - Return `OnLoadResult` with `loader` to change the loader type
2686
- * - Can be synchronous or asynchronous (return a Promise)
2763
+ * The configuration is typically exported from a `build.config.ts` or similar file and
2764
+ * loaded by the build system at startup.
2687
2765
  *
2688
- * The `context.contents` property receives the output of previous hooks, and `context.loader`
2689
- * reflects any loader changes made by previous hooks.
2766
+ * Configuration resolution:
2767
+ * 1. Load the configuration file
2768
+ * 2. Parse command-line arguments using `userArgv` definitions
2769
+ * 3. Merge common settings with each variant
2770
+ * 4. Execute builds for all or selected variants
2690
2771
  *
2691
2772
  * @example
2692
2773
  * ```ts
2693
- * const onLoad: OnLoadType = async (context) => {
2694
- * const { contents, loader, args, variantName } = context;
2695
- *
2696
- * // Transform .custom files to TypeScript
2697
- * if (args.path.endsWith('.custom')) {
2698
- * return {
2699
- * contents: transformCustomSyntax(contents.toString()),
2700
- * loader: 'ts'
2701
- * };
2702
- * }
2703
- *
2704
- * // Inject environment variables in development
2705
- * if (variantName === 'development' && loader === 'js') {
2706
- * return {
2707
- * contents: `const ENV = '${variantName}';\n${contents}`,
2708
- * loader
2709
- * };
2774
+ * const config: BuildConfigInterface = {
2775
+ * verbose: true,
2776
+ * common: {
2777
+ * esbuild: {
2778
+ * platform: 'node',
2779
+ * target: 'node18'
2780
+ * },
2781
+ * types: true
2782
+ * },
2783
+ * variants: {
2784
+ * esm: {
2785
+ * esbuild: {
2786
+ * entryPoints: ['src/index.ts'],
2787
+ * format: 'esm',
2788
+ * outdir: 'dist/esm'
2789
+ * }
2790
+ * },
2791
+ * cjs: {
2792
+ * esbuild: {
2793
+ * entryPoints: ['src/index.ts'],
2794
+ * format: 'cjs',
2795
+ * outdir: 'dist/cjs'
2796
+ * }
2797
+ * }
2798
+ * },
2799
+ * userArgv: {
2800
+ * watch: { type: 'boolean', description: 'Watch for changes' }
2710
2801
  * }
2711
- *
2712
- * // Pass through unchanged
2713
- * return undefined;
2714
- * };
2715
- * ```
2716
- *
2717
- * @see {@link LoadContextInterface}
2718
- * @see {@link LifecycleProvider.onLoad}
2719
- * @see {@link MaybeUndefinedPromiseType}
2720
- *
2721
- * @since 2.0.0
2722
- */
2723
- type OnLoadType = (context: LoadContextInterface) => MaybeUndefinedPromiseType<OnLoadResult>;
2724
- /**
2725
- * Extended build result interface with normalized error and warning arrays.
2726
- *
2727
- * @remarks
2728
- * This interface extends esbuild's {@link BuildResult} while replacing the `errors` and `warnings`
2729
- * properties with normalized Error instances instead of esbuild's Message objects. This normalization
2730
- * provides consistent error handling throughout the xBuild system with proper stack traces, formatting,
2731
- * and error classification.
2732
- *
2733
- * **Key differences from esbuild's BuildResult**:
2734
- * - `errors`: Changed from `Message[]` to `Error[]` with normalized error types
2735
- * - `warnings`: Changed from `Message[]` to `Error[]` with normalized error types
2736
- * - All other properties (metafile, outputFiles, mangleCache) are preserved unchanged
2737
- *
2738
- * **Benefits of normalization**:
2739
- * - Consistent error handling across different error sources (esbuild, TypeScript, VM runtime)
2740
- * - Proper error inheritance and type checking
2741
- * - Rich stack trace information with source mapping
2742
- * - Formatted error output with syntax highlighting
2743
- * - Integration with xBuild's custom error classes
2744
- *
2745
- * The normalized errors may include:
2746
- * - {@link TypesError} for TypeScript type checking failures
2747
- * - {@link xBuildError} for text errors during build hooks
2748
- * - {@link esBuildError} for esbuild compilation errors with location information
2749
- * - {@link VMRuntimeError} for runtime errors during build hooks
2750
- * - {@link xBuildBaseError} for custom build system errors
2751
- *
2752
- * @example
2753
- * ```ts
2754
- * const result: BuildResultInterface = {
2755
- * errors: [
2756
- * new esBuildError(esbuildMessage),
2757
- * new TypesError('Type checking failed', diagnostics)
2758
- * ],
2759
- * warnings: [
2760
- * new xBuildError('Deprecation warning')
2761
- * ],
2762
- * metafile: { ... },
2763
- * outputFiles: [ ... ],
2764
- * mangleCache: { ... }
2765
2802
  * };
2766
2803
  * ```
2767
2804
  *
2768
- * @see {@link BuildResult} from esbuild for the base interface
2805
+ * @see {@link VariantsType}
2806
+ * @see {@link CommonBuildInterface}
2807
+ * @see {@link PartialBuildConfigType}
2769
2808
  *
2770
2809
  * @since 2.0.0
2771
2810
  */
2772
- interface BuildResultInterface extends Omit<BuildResult, 'errors' | 'warnings'> {
2811
+ interface BuildConfigInterface {
2773
2812
  /**
2774
- * Array of normalized error instances encountered during the build.
2813
+ * Shared configuration applied to all build variants.
2775
2814
  *
2776
2815
  * @remarks
2777
- * Contains Error instances converted from esbuild messages and other error sources.
2778
- * Unlike esbuild's native error array which contains Message objects, this array
2779
- * contains fully normalized Error instances with proper stack traces and formatting.
2816
+ * Optional common settings that are merged with each variant's configuration.
2817
+ * Variants can override these settings with their own specific values.
2780
2818
  *
2781
- * Errors in this array may originate from:
2782
- * - Compilation errors (syntax, resolution failures)
2783
- * - Type checking failures
2784
- * - Build hook execution errors
2785
- * - Plugin errors
2819
+ * @see {@link CommonBuildInterface}
2820
+ *
2821
+ * @since 2.0.0
2822
+ */
2823
+ common?: CommonBuildInterface;
2824
+ /**
2825
+ * Enable verbose logging output during builds.
2826
+ *
2827
+ * @remarks
2828
+ * When true, outputs detailed build information including file processing,
2829
+ * hook execution, and timing information. Useful for debugging build issues.
2786
2830
  *
2787
2831
  * @example
2788
2832
  * ```ts
2789
- * if (result.errors.length > 0) {
2790
- * console.error(`Build failed with ${result.errors.length} errors`);
2791
- * result.errors.forEach(err => console.error(err.stack));
2792
- * }
2833
+ * verbose: true // Detailed output
2834
+ * verbose: false // Minimal output
2793
2835
  * ```
2794
2836
  *
2795
2837
  * @since 2.0.0
2796
2838
  */
2797
- errors: Array<Error>;
2839
+ verbose?: boolean;
2798
2840
  /**
2799
- * Array of normalized warning instances encountered during the build.
2841
+ * Build variant definitions mapping names to configurations.
2800
2842
  *
2801
2843
  * @remarks
2802
- * Contains Error instances converted from esbuild warning messages and other warning sources.
2803
- * Unlike esbuild's native warning array which contains Message objects, this array
2804
- * contains fully normalized Error instances with proper stack traces and formatting.
2805
- *
2806
- * Warnings indicate non-fatal issues that don't prevent build completion but may
2807
- * require attention, such as:
2808
- * - Deprecated API usage
2809
- * - Type checking warnings
2810
- * - Performance concerns
2811
- * - Potential runtime issues
2844
+ * Required field defining all build targets. At least one variant must be defined.
2845
+ * Each variant specifies its own entry points and can override common settings.
2812
2846
  *
2813
- * @example
2814
- * ```ts
2815
- * if (result.warnings.length > 0) {
2816
- * console.warn(`Build completed with ${result.warnings.length} warnings`);
2817
- * result.warnings.forEach(warn => console.warn(warn.message));
2818
- * }
2819
- * ```
2847
+ * @see {@link VariantsType}
2820
2848
  *
2821
2849
  * @since 2.0.0
2822
2850
  */
2823
- warnings: Array<Error>;
2851
+ variants: VariantsType;
2824
2852
  }
2853
+ /**
2854
+ * Partial build configuration for incremental or programmatic configuration building.
2855
+ * Allows omitting variants and userArgv while making other fields optional.
2856
+ *
2857
+ * @remarks
2858
+ * This type is useful when building configuration programmatically or when providing
2859
+ * configuration fragments that will be merged with a base configuration. It makes
2860
+ * all properties optional except `variants` and `userArgv` which are completely omitted.
2861
+ *
2862
+ * Common use cases:
2863
+ * - Configuration presets or templates
2864
+ * - Programmatic configuration generation
2865
+ * - Configuration merging utilities
2866
+ * - Partial overrides in build scripts
2867
+ *
2868
+ * @example
2869
+ * ```ts
2870
+ * const preset: PartialBuildConfigType = {
2871
+ * verbose: true,
2872
+ * common: {
2873
+ * types: { failOnError: true },
2874
+ * declaration: true
2875
+ * }
2876
+ * };
2877
+ *
2878
+ * // Merge with full config
2879
+ * const fullConfig: BuildConfigInterface = {
2880
+ * ...preset,
2881
+ * variants: { ... }
2882
+ * };
2883
+ * ```
2884
+ *
2885
+ * @see {@link BuildConfigInterface}
2886
+ *
2887
+ * @since 2.0.0
2888
+ */
2889
+ type PartialBuildConfigType = Partial<BuildConfigInterface>;
2825
2890
  /**
2826
2891
  * Provides a file-watching service that tracks changes in the framework's root directory.
2827
2892
  *
@@ -3667,793 +3732,273 @@ declare function isBuildResultError(error: unknown): error is BuildResult;
3667
3732
  * console.error(error.stack);
3668
3733
  * ```
3669
3734
  *
3670
- * @see {@link xBuildBaseError}
3671
- * @see {@link getErrorMetadata}
3672
- * @see {@link formatStack}
3673
- *
3674
- * @since 2.0.0
3675
- */
3676
- declare class esBuildError extends xBuildBaseError {
3677
- /**
3678
- * Optional esbuild diagnostic identifier copied from `PartialMessage.id`.
3679
- *
3680
- * @remarks
3681
- * This value is useful for categorizing diagnostics by producer (for example,
3682
- * plugin- or phase-specific IDs). When absent in the source message, it defaults
3683
- * to an empty string.
3684
- *
3685
- * @since 2.0.0
3686
- */
3687
- readonly id: string;
3688
- /**
3689
- * Creates a new esbuild error with formatted output and metadata.
3690
- *
3691
- * @param message - The esbuild {@link PartialMessage} containing diagnostic details
3692
- * @param options - Optional stack parsing/formatting options used when deriving metadata
3693
- *
3694
- * @remarks
3695
- * The constructor:
3696
- * 1. Initializes the base error with `message.text ?? ''`
3697
- * 2. Persists `message.id ?? ''` on {@link id}
3698
- * 3. If `message.detail` is an `Error`, uses its `message` and `stack` as runtime values
3699
- * 4. Builds structured metadata from either the original message or `detail` error
3700
- * 5. Produces formatted output (stack replacement for message-based diagnostics, or
3701
- * formatted inspector output for `detail`-based diagnostics)
3702
- *
3703
- * The error name is always set to `'esBuildError'`. Formatted output includes:
3704
- * - Error name and message with color coding
3705
- * - Any diagnostic notes from esbuild
3706
- * - Highlighted code snippet showing the error location
3707
- * - Enhanced stack trace with file path and position
3708
- *
3709
- * @see {@link getErrorMetadata} for formatting logic
3710
- * @see {@link PartialMessage} for esbuild message structure
3711
- *
3712
- * @since 2.0.0
3713
- */
3714
- constructor(message: PartialMessage, options?: StackTraceInterface);
3715
- }
3716
- /**
3717
- * A base class for custom errors with enhanced stack trace formatting and source code information.
3718
- *
3719
- * @remarks
3720
- * The `xBuildBaseError` class extends the native `Error` class, adding functionality to:
3721
- * - Parse and store structured stack trace metadata via {@link StackInterface}
3722
- * - Format stack traces with syntax highlighting and source mapping
3723
- * - Provide enhanced console output through custom Node.js inspection
3724
- *
3725
- * This is particularly useful for debugging errors in compiled or transpiled code by providing
3726
- * clearer information about the original source of the error, including
3727
- * - Original source file paths (from source maps)
3728
- * - Highlighted code snippets showing the error location
3729
- * - Enhanced stack frame formatting with proper indentation
3730
- *
3731
- * @example
3732
- * ```ts
3733
- * class ValidationError extends xBuildBaseError {
3734
- * constructor(message: string, field: string) {
3735
- * super(message, 'ValidationError');
3736
- * this.reformatStack(this, { withFrameworkFrames: false });
3737
- * }
3738
- * }
3739
- *
3740
- * throw new ValidationError('Invalid email format', 'email');
3741
- * ```
3742
- *
3743
- * @see {@link formatStack} for stack formatting
3744
- * @see {@link getErrorMetadata} for stack parsing
3745
- * @see {@link StackInterface} for the metadata structure
3746
- * @see {@link StackTraceInterface} for formatting options
3747
- *
3748
- * @since 2.0.0
3749
- */
3750
- declare abstract class xBuildBaseError extends Error {
3751
- /**
3752
- * Structured metadata from the parsed stack trace.
3753
- *
3754
- * @remarks
3755
- * Contains the parsed stack information including
3756
- * - Original source code snippet
3757
- * - Line and column numbers
3758
- * - Source file path (from source maps)
3759
- * - Formatted stack frames
3760
- * - Syntax-highlighted code
3761
- *
3762
- * This property is populated by calling {@link reformatStack}.
3763
- *
3764
- * @since 2.0.0
3765
- */
3766
- protected errorMetadata: StackInterface | undefined;
3767
- /**
3768
- * Pre-formatted stack trace string ready for display.
3769
- *
3770
- * @remarks
3771
- * Contains the complete formatted output including
3772
- * - Error name and message
3773
- * - Syntax-highlighted code snippet (if available)
3774
- * - Enhanced stack trace with proper indentation
3775
- *
3776
- * This is generated by {@link formatStack} and used by the custom
3777
- * Node.js inspector for console output.
3778
- *
3779
- * @since 2.0.0
3780
- */
3781
- protected formattedStack: string | undefined;
3782
- /**
3783
- * Creates a new instance of the base error class.
3784
- *
3785
- * @param message - The error message describing the problem
3786
- * @param name - The error type name; defaults to `'xBuildBaseError'`
3787
- *
3788
- * @remarks
3789
- * This constructor:
3790
- * - Properly sets up the prototype chain to ensure `instanceof` checks work for derived classes
3791
- * - Captures the stack trace if supported by the runtime environment
3792
- * - Sets the error name for identification
3793
- *
3794
- * **Important:** This is a protected constructor and should only be called by derived classes.
3795
- * Subclasses should call {@link reformatStack} after construction to enable enhanced formatting.
3796
- *
3797
- * @example
3798
- * ```ts
3799
- * class DatabaseError extends xBuildBaseError {
3800
- * constructor(message: string, public readonly query: string) {
3801
- * super(message, 'DatabaseError');
3802
- * this.reformatStack(this);
3803
- * }
3804
- * }
3805
- * ```
3806
- *
3807
- * @since 2.0.0
3808
- */
3809
- protected constructor(message: string, name?: string);
3810
- /**
3811
- * Gets the structured stack trace metadata.
3812
- *
3813
- * @returns The parsed stack metadata, or `undefined` if {@link reformatStack} has not been called
3814
- *
3815
- * @remarks
3816
- * Provides read-only access to the error's structured stack information,
3817
- * which can be used for:
3818
- * - Custom error logging
3819
- * - Error reporting services
3820
- * - Debugging tools
3821
- * - Stack analysis
3822
- *
3823
- * @example
3824
- * ```ts
3825
- * try {
3826
- * throw new ValidationError('Invalid input');
3827
- * } catch (error) {
3828
- * if (error instanceof xBuildBaseError) {
3829
- * const meta = error.metadata;
3830
- * console.log(`Error at ${meta?.source}:${meta?.line}:${meta?.column}`);
3831
- * }
3832
- * }
3833
- * ```
3834
- *
3835
- * @since 2.0.0
3836
- */
3837
- get metadata(): StackInterface | undefined;
3838
- /**
3839
- * Parses the error stack trace and generates enhanced formatting with metadata.
3840
- *
3841
- * @param error - The error object to parse and format
3842
- * @param options - Optional configuration for stack trace parsing and formatting
3843
- *
3844
- * @remarks
3845
- * This method performs two operations:
3846
- * 1. Parses the error's stack trace using {@link getErrorMetadata} to extract structured metadata
3847
- * 2. Formats the metadata using {@link formatStack} to create a styled, human-readable output
3848
- *
3849
- * The parsed metadata is stored in {@link errorMetadata} and the formatted string in {@link formattedStack}.
3850
- *
3851
- * **Typical usage:** Call this method in the constructor of derived error classes to enable
3852
- * enhanced stack trace formatting.
3853
- *
3854
- * @example
3855
- * ```ts
3856
- * class NetworkError extends xBuildBaseError {
3857
- * constructor(message: string, public readonly statusCode: number) {
3858
- * super(message, 'NetworkError');
3859
- * // Enable enhanced formatting without framework frames
3860
- * this.reformatStack(this, {
3861
- * withFrameworkFrames: false,
3862
- * withNativeFrames: true
3863
- * });
3864
- * }
3865
- * }
3866
- * ```
3867
- *
3868
- * @example
3869
- * ```ts
3870
- * class CustomError extends xBuildBaseError {
3871
- * constructor(message: string) {
3872
- * super(message, 'CustomError');
3873
- * // Use default options
3874
- * this.reformatStack(this);
3875
- * }
3876
- * }
3877
- * ```
3878
- *
3879
- * @see {@link formatStack} for formatting logic
3880
- * @see {@link getErrorMetadata} for parsing logic
3881
- * @see {@link StackTraceInterface} for available options
3882
- *
3883
- * @since 2.0.0
3884
- */
3885
- protected reformatStack(error: Error, options?: StackTraceInterface): void;
3886
- }
3887
- /**
3888
- * Structured result of a parsed and formatted stack trace.
3889
- *
3890
- * @remarks
3891
- * This interface represents the finalized output from stack trace parsing and formatting,
3892
- * containing both the raw code context and fully formatted stack frames ready for display.
3893
- * Used as the return type for {@link getErrorMetadata}.
3894
- *
3895
- * @see getErrorMetadata
3896
- * @since 2.0.0
3897
- */
3898
- interface StackInterface {
3899
- /**
3900
- * Extracted source code snippet surrounding the error location.
3901
- *
3902
- * @remarks
3903
- * Contains multiple lines of code context (before and after the error line)
3904
- * as determined by the {@link StackTraceInterface.linesBefore} and
3905
- * {@link StackTraceInterface.linesAfter} options.
3906
- *
3907
- * @since 2.0.0
3908
- */
3909
- code: string;
3910
- /**
3911
- * Line number of the error within the source file.
3912
- *
3913
- * @remarks
3914
- * This line number reflects the original source position after source map resolution,
3915
- * with any {@link StackContextInterface.lineOffset} applied.
3916
- *
3917
- * @since 2.0.0
3918
- */
3919
- line: number;
3920
- /**
3921
- * Column number of the error within the source file.
3922
- *
3923
- * @remarks
3924
- * This column number reflects the original source position after source map resolution.
3925
- *
3926
- * @since 2.0.0
3927
- */
3928
- column: number;
3929
- /**
3930
- * Original source file path, if available.
3931
- *
3932
- * @remarks
3933
- * This is the resolved source file path from source maps or the original file name.
3934
- * May be undefined if no source information is available.
3935
- *
3936
- * @since 2.0.0
3937
- */
3938
- source?: string;
3939
- /**
3940
- * Array of formatted stack trace entries ready for display.
3941
- *
3942
- * @remarks
3943
- * Each string represents a single formatted stack frame, complete with
3944
- * function names, file paths, line/column numbers, and color formatting.
3945
- * Empty strings from filtered frames (native or framework) are excluded.
3946
- *
3947
- * @since 2.0.0
3948
- */
3949
- stacks: Array<string>;
3950
- /**
3951
- * Syntax-highlighted and formatted version of the source code snippet.
3952
- *
3953
- * @remarks
3954
- * Contains the {@link code} with applied syntax highlighting and error formatting,
3955
- * including line numbers and a marker indicating the exact error position.
3956
- * Generated by {@link highlightPositionCode} and cached during frame processing.
3957
- *
3958
- * @see highlightPositionCode
3959
- * @since 2.0.0
3960
- */
3961
- formatCode: string;
3962
- }
3963
- /**
3964
- * Configuration options for parsing and formatting stack traces.
3965
- *
3966
- * @remarks
3967
- * These options control how stack traces are parsed, what frames are included,
3968
- * and how much source code context is displayed. Used by {@link getErrorMetadata}
3969
- * and {@link stackEntry} to customize stack trace output.
3970
- *
3971
- * @see stackEntry
3972
- * @see getErrorMetadata
3973
- *
3974
- * @since 2.0.0
3975
- */
3976
- interface StackTraceInterface {
3977
- /**
3978
- * Number of lines of source code to include after the error line.
3979
- *
3980
- * @defaultValue 3
3981
- *
3982
- * @remarks
3983
- * Defaults to 3 if not specified. Used when extracting code context
3984
- * from source files or snapshots.
3985
- *
3986
- * @since 2.0.0
3987
- */
3988
- linesAfter?: number;
3989
- /**
3990
- * Number of lines of source code to include before the error line.
3991
- *
3992
- * @defaultValue 3
3993
- *
3994
- * @remarks
3995
- * Defaults to 3 if not specified. Used when extracting code context
3996
- * from source files or snapshots.
3997
- *
3998
- * @since 2.0.0
3999
- */
4000
- linesBefore?: number;
4001
- /**
4002
- * Whether to include native (built-in) stack frames in the output.
4003
- *
4004
- * @defaultValue Based on `ConfigurationService.verbose` setting
4005
- *
4006
- * @remarks
4007
- * Native frames are those marked with `frame.native === true`, typically
4008
- * representing Node.js internal functions. When false, these frames are
4009
- * filtered out during processing. Automatically set based on the `verbose`
4010
- * configuration setting if not explicitly provided.
4011
- *
4012
- * @since 2.0.0
4013
- */
4014
- withNativeFrames?: boolean;
4015
- /**
4016
- * Whether to include framework-internal stack frames in the output.
4017
- *
4018
- * @defaultValue Based on `ConfigurationService.verbose` setting
4019
- *
4020
- * @remarks
4021
- * Framework frames are identified by {@link isFrameworkFile}.
4022
- * When false, these frames are filtered out to reduce noise in stack traces.
4023
- * Automatically set based on the `verbose` configuration setting if not
4024
- * explicitly provided.
4025
- *
4026
- * @see isFrameworkFile
4027
- * @since 2.0.0
4028
- */
4029
- withFrameworkFrames?: boolean;
4030
- }
4031
- /**
4032
- * Internal runtime context used during stack trace parsing and formatting.
4033
- *
4034
- * @remarks
4035
- * This context extends {@link StackTraceInterface} with additional runtime state
4036
- * and service dependencies required during stack trace processing. It maintains
4037
- * mutable state as frames are processed, including the first encountered code snippet,
4038
- * line/column positions, and formatted output. Used internally by {@link stackEntry},
4039
- * {@link formatFrameWithPosition}, and related functions.
4040
- *
4041
- * @see stackEntry
4042
- * @see getErrorMetadata
4043
- * @see StackTraceInterface
4044
- *
4045
- * @since 2.0.0
4046
- */
4047
- interface StackContextInterface extends StackTraceInterface {
4048
- /**
4049
- * Cached source code snippet from the first processed frame with code context.
4050
- *
4051
- * @remarks
4052
- * Populated by {@link formatFrameWithPosition} on the first frame that has
4053
- * available code. Subsequent frames do not overwrite this value, ensuring
4054
- * the code displayed corresponds to the most relevant stack frame.
4055
- *
4056
- * @see formatFrameWithPosition
4057
- *
4058
- * @since 2.0.0
4059
- */
4060
- code: string;
4061
- /**
4062
- * Reference to the {@link FilesModel} service for accessing file snapshots.
4063
- *
4064
- * @remarks
4065
- * Used by {@link getSource} to retrieve file content when source maps are
4066
- * not available. Injected during context initialization in {@link getErrorMetadata}.
4067
- *
4068
- * @see getSource
4069
- * @see FilesModel
4070
- *
4071
- * @since 2.0.0
4072
- */
4073
- files: FilesModel;
4074
- /**
4075
- * Cached original source file path from the first processed frame.
4076
- *
4077
- * @remarks
4078
- * Populated by {@link formatFrameWithPosition} on the first frame that has
4079
- * a resolved source position. Corresponds to the file containing the {@link code}.
4080
- *
4081
- * @see formatFrameWithPosition
4082
- * @since 2.0.0
4083
- */
4084
- source: string;
4085
- /**
4086
- * Reference to the {@link FrameworkService} for resolving source maps and framework files.
4087
- *
4088
- * @remarks
4089
- * Used throughout stack processing to:
4090
- * - Retrieve source maps via {@link getSourceMap}
4091
- * - Identify framework files via {@link isFrameworkFile}
4092
- * - Resolve relative paths using {@link rootPath}
4093
- *
4094
- * Injected during context initialization in {@link getErrorMetadata}.
4095
- *
4096
- * @see getSource
4097
- * @see stackEntry
4098
- * @see FrameworkService
4099
- *
4100
- * @since 2.0.0
4101
- */
4102
- framework: FrameworkService;
4103
- /**
4104
- * Resolved line number from the most recently processed stack frame.
4105
- *
4106
- * @remarks
4107
- * Updated by {@link stackEntry} after resolving source positions.
4108
- * Includes any {@link lineOffset} adjustments. Used to populate the
4109
- * final {@link StackInterface.line} value.
4110
- *
4111
- * @see stackEntry
4112
- * @since 2.0.0
4113
- */
4114
- line: number;
3735
+ * @see {@link xBuildBaseError}
3736
+ * @see {@link getErrorMetadata}
3737
+ * @see {@link formatStack}
3738
+ *
3739
+ * @since 2.0.0
3740
+ */
3741
+ declare class esBuildError extends xBuildBaseError {
4115
3742
  /**
4116
- * Resolved column number from the most recently processed stack frame.
3743
+ * Optional esbuild diagnostic identifier copied from `PartialMessage.id`.
4117
3744
  *
4118
3745
  * @remarks
4119
- * Updated by {@link stackEntry} after resolving source positions.
4120
- * Used to populate the final {@link StackInterface.column} value.
3746
+ * This value is useful for categorizing diagnostics by producer (for example,
3747
+ * plugin- or phase-specific IDs). When absent in the source message, it defaults
3748
+ * to an empty string.
4121
3749
  *
4122
- * @see stackEntry
4123
3750
  * @since 2.0.0
4124
3751
  */
4125
- column: number;
3752
+ readonly id: string;
4126
3753
  /**
4127
- * Line number offset to apply to all resolved positions.
3754
+ * Creates a new esbuild error with formatted output and metadata.
4128
3755
  *
4129
- * @defaultValue 0
3756
+ * @param message - The esbuild {@link PartialMessage} containing diagnostic details
3757
+ * @param options - Optional stack parsing/formatting options used when deriving metadata
4130
3758
  *
4131
3759
  * @remarks
4132
- * Applied to `position.line`, `position.startLine`, and `position.endLine`
4133
- * in {@link stackEntry}. Useful for aligning stack trace line numbers with
4134
- * external systems or editors that use different line numbering schemes.
4135
- *
4136
- * @see stackEntry
4137
- * @since 2.0.0
4138
- */
4139
- lineOffset: number;
4140
- /**
4141
- * Cached syntax-highlighted code snippet from the first processed frame.
3760
+ * The constructor:
3761
+ * 1. Initializes the base error with `message.text ?? ''`
3762
+ * 2. Persists `message.id ?? ''` on {@link id}
3763
+ * 3. If `message.detail` is an `Error`, uses its `message` and `stack` as runtime values
3764
+ * 4. Builds structured metadata from either the original message or `detail` error
3765
+ * 5. Produces formatted output (stack replacement for message-based diagnostics, or
3766
+ * formatted inspector output for `detail`-based diagnostics)
4142
3767
  *
4143
- * @remarks
4144
- * Generated by {@link highlightPositionCode} and stored by {@link formatFrameWithPosition}
4145
- * on the first frame that has code context. This is the display-ready version of {@link code}
4146
- * with syntax highlighting, line numbers, and error position markers applied.
3768
+ * The error name is always set to `'esBuildError'`. Formatted output includes:
3769
+ * - Error name and message with color coding
3770
+ * - Any diagnostic notes from esbuild
3771
+ * - Highlighted code snippet showing the error location
3772
+ * - Enhanced stack trace with file path and position
4147
3773
  *
4148
- * @see highlightPositionCode
4149
- * @see formatFrameWithPosition
3774
+ * @see {@link getErrorMetadata} for formatting logic
3775
+ * @see {@link PartialMessage} for esbuild message structure
4150
3776
  *
4151
3777
  * @since 2.0.0
4152
3778
  */
4153
- formatCode: string;
3779
+ constructor(message: PartialMessage, options?: StackTraceInterface);
4154
3780
  }
4155
3781
  /**
4156
- * Provides access to the framework's file paths and associated source maps.
3782
+ * A base class for custom errors with enhanced stack trace formatting and source code information.
4157
3783
  *
4158
3784
  * @remarks
4159
- * This service manages the framework's source map files, including the main framework
4160
- * file and any additional source files. It caches initialized {@link SourceService}
4161
- * instances for performance.
3785
+ * The `xBuildBaseError` class extends the native `Error` class, adding functionality to:
3786
+ * - Parse and store structured stack trace metadata via {@link ResolveMetadataInterface}
3787
+ * - Format stack traces with syntax highlighting and source mapping
3788
+ * - Provide enhanced console output through custom Node.js inspection
3789
+ *
3790
+ * This is particularly useful for debugging errors in compiled or transpiled code by providing
3791
+ * clearer information about the original source of the error, including
3792
+ * - Original source file paths (from source maps)
3793
+ * - Highlighted code snippets showing the error location
3794
+ * - Enhanced stack frame formatting with proper indentation
4162
3795
  *
4163
3796
  * @example
4164
3797
  * ```ts
4165
- * const frameworkService = new FrameworkService();
4166
- * console.log(frameworkService.rootPath);
4167
- * const sourceMap = frameworkService.sourceMap(frameworkService.filePath);
3798
+ * class ValidationError extends xBuildBaseError {
3799
+ * constructor(message: string, field: string) {
3800
+ * super(message, 'ValidationError');
3801
+ * this.reformatStack(this, { withFrameworkFrames: false });
3802
+ * }
3803
+ * }
3804
+ *
3805
+ * throw new ValidationError('Invalid email format', 'email');
4168
3806
  * ```
4169
3807
  *
3808
+ * @see {@link formatStack} for stack formatting
3809
+ * @see {@link getErrorMetadata} for stack parsing
3810
+ * @see {@link StackTraceInterface} for formatting options
3811
+ * @see {@link ResolveMetadataInterface} for the metadata structure
3812
+ *
4170
3813
  * @since 2.0.0
4171
3814
  */
4172
- declare class FrameworkService {
4173
- /**
4174
- * Absolute path to the current file.
4175
- *
4176
- * @readonly
4177
- * @since 2.0.0
4178
- */
4179
- readonly filePath: string;
4180
- /**
4181
- * Absolute path to the distribution directory.
4182
- *
4183
- * @readonly
4184
- * @since 2.0.0
4185
- */
4186
- readonly distPath: string;
4187
- /**
4188
- * Absolute path to the project root directory.
4189
- *
4190
- * @readonly
4191
- * @since 2.0.0
4192
- */
4193
- readonly rootPath: string;
4194
- /**
4195
- * Cached {@link SourceService} instances for additional source files.
4196
- * @since 2.0.0
4197
- */
4198
- private readonly sourceMaps;
4199
- /**
4200
- * Initializes a new {@link FrameworkService} instance.
4201
- *
4202
- * @remarks
4203
- * Sets up the main framework source map, as well as root and distribution paths.
4204
- *
4205
- * @since 2.0.0
4206
- */
4207
- constructor();
4208
- /**
4209
- * Determines whether a given {@link PositionInterface} refers to a framework file.
4210
- *
4211
- * @param position - The position information to check
4212
- * @returns `true` if the position is from the framework (contains "xJet"), otherwise `false`
4213
- *
4214
- * @see PositionInterface
4215
- * @since 1.0.0
4216
- */
4217
- isFrameworkFile(position: PositionInterface): boolean;
3815
+ declare abstract class xBuildBaseError extends Error {
4218
3816
  /**
4219
- * Retrieves a cached {@link SourceService} for a given file path.
4220
- *
4221
- * @param path - Absolute path to the file
4222
- * @returns A {@link SourceService} instance if found, otherwise `undefined`
3817
+ * Structured metadata from the parsed stack trace.
4223
3818
  *
4224
3819
  * @remarks
4225
- * Paths are normalized before lookup. Only previously initialized source maps
4226
- * (via {@link setSource} or {@link setSourceFile}) are available in the cache.
4227
- *
4228
- * @see SourceService
4229
- * @since 2.0.0
4230
- */
4231
- getSourceMap(path: string): SourceService | undefined;
4232
- /**
4233
- * Registers and initializes a new {@link SourceService} for a provided source map string.
4234
- *
4235
- * @param source - The raw source map content
4236
- * @param path - Absolute file path associated with the source map
4237
- * @returns A new or cached {@link SourceService} instance
4238
- *
4239
- * @throws Error if initialization fails
3820
+ * Contains the parsed stack information including
3821
+ * - Original source code snippet
3822
+ * - Line and column numbers
3823
+ * - Source file path (from source maps)
3824
+ * - Formatted stack frames
3825
+ * - Syntax-highlighted code
4240
3826
  *
4241
- * @remarks
4242
- * If a source map for the given path is already cached, the cached instance is returned.
3827
+ * This property is populated by calling {@link reformatStack}.
4243
3828
  *
4244
- * @see SourceService
4245
3829
  * @since 2.0.0
4246
3830
  */
4247
- setSource(source: string, path: string): void;
3831
+ protected errorMetadata: ResolveMetadataInterface | undefined;
4248
3832
  /**
4249
- * Loads and initializes a {@link SourceService} for a file and its `.map` companion.
4250
- *
4251
- * @param path - Absolute path to the file
4252
- * @returns A new or cached {@link SourceService} instance
4253
- *
4254
- * @throws Error if the `.map` file cannot be read or parsed
3833
+ * Pre-formatted stack trace string ready for display.
4255
3834
  *
4256
3835
  * @remarks
4257
- * This method attempts to read the `.map` file located next to the provided file.
4258
- * If already cached, returns the existing {@link SourceService}.
4259
- *
4260
- * @see SourceService
4261
- * @since 2.0.0
4262
- */
4263
- setSourceFile(path: string): void;
4264
- /**
4265
- * Retrieves the project root directory.
4266
- * @returns Absolute path to the project root
3836
+ * Contains the complete formatted output including
3837
+ * - Error name and message
3838
+ * - Syntax-highlighted code snippet (if available)
3839
+ * - Enhanced stack trace with proper indentation
4267
3840
  *
4268
- * @since 2.0.0
4269
- */
4270
- private getRootDir;
4271
- /**
4272
- * Retrieves the distribution directory.
4273
- * @returns Absolute path to the distribution folder
3841
+ * This is generated by {@link formatStack} and used by the custom
3842
+ * Node.js inspector for console output.
4274
3843
  *
4275
3844
  * @since 2.0.0
4276
3845
  */
4277
- private getDistDir;
3846
+ protected formattedStack: string | undefined;
4278
3847
  /**
4279
- * Creates and caches a new {@link SourceService} instance for a given source map.
3848
+ * Creates a new instance of the base error class.
4280
3849
  *
4281
- * @param source - Raw source map content
4282
- * @param path - Normalized file path used as the cache key
4283
- * @returns The newly created {@link SourceService} instance
3850
+ * @param message - The error message describing the problem
3851
+ * @param name - The error type name; defaults to `'xBuildBaseError'`
4284
3852
  *
4285
3853
  * @remarks
4286
- * This method is only used internally by {@link setSource} and {@link setSourceFile}.
4287
- * The instance is cached in {@link sourceMaps} for reuse.
3854
+ * This constructor:
3855
+ * - Properly sets up the prototype chain to ensure `instanceof` checks work for derived classes
3856
+ * - Captures the stack trace if supported by the runtime environment
3857
+ * - Sets the error name for identification
4288
3858
  *
4289
- * @see SourceService
4290
- * @since 2.0.0
4291
- */
4292
- private initializeSourceMap;
4293
- }
4294
- /**
4295
- * In-memory cache that maintains lightweight snapshots of file contents (as TypeScript `IScriptSnapshot`)
4296
- * together with modification time and version counters.
4297
- *
4298
- * Primarily used by language servers, transpiler, and incremental build systems to avoid unnecessary
4299
- * file system reads and snapshot recreation when files have not changed.
4300
- *
4301
- * @since 2.0.0
4302
- */
4303
- declare class FilesModel {
4304
- /**
4305
- * Cache that maps original (possibly relative) paths → normalized absolute paths with forward slashes
4306
- * @since 2.0.0
4307
- */
4308
- private readonly resolvedPathCache;
4309
- /**
4310
- * Main storage: resolved absolute path → current file snapshot state
4311
- * @since 2.0.0
4312
- */
4313
- private readonly snapshotsByPath;
4314
- /**
4315
- * Removes all cached paths and snapshots.
4316
- * @since 2.0.0
4317
- */
4318
- clear(): void;
4319
- /**
4320
- * Returns the current known snapshot state for the given file path, or `undefined`
4321
- * if the file has never been touched/observed by this cache.
3859
+ * **Important:** This is a protected constructor and should only be called by derived classes.
3860
+ * Subclasses should call {@link reformatStack} after construction to enable enhanced formatting.
4322
3861
  *
4323
- * @param path - filesystem path (relative or absolute)
4324
- * @returns current snapshot data or `undefined` if not tracked yet
3862
+ * @example
3863
+ * ```ts
3864
+ * class DatabaseError extends xBuildBaseError {
3865
+ * constructor(message: string, public readonly query: string) {
3866
+ * super(message, 'DatabaseError');
3867
+ * this.reformatStack(this);
3868
+ * }
3869
+ * }
3870
+ * ```
4325
3871
  *
4326
3872
  * @since 2.0.0
4327
3873
  */
4328
- getSnapshot(path: string): FileSnapshotInterface | undefined;
3874
+ protected constructor(message: string, name?: string);
4329
3875
  /**
4330
- * Returns an existing snapshot entry for the given file path, or creates/updates it if not tracked yet.
3876
+ * Gets the structured stack trace metadata.
4331
3877
  *
4332
- * @param path - Filesystem path (relative or absolute).
4333
- * @returns The current snapshot entry for the file (existing or newly created).
3878
+ * @returns The parsed stack metadata, or `undefined` if {@link reformatStack} has not been called
4334
3879
  *
4335
3880
  * @remarks
4336
- * This is a convenience method combining:
4337
- * - {@link getSnapshot} (fast path when already tracked), and
4338
- * - {@link touchFile} (tracks the file, reads content if needed, updates version/mtime).
4339
- *
4340
- * Use this when you need a snapshot entry and don't want to handle the `undefined` case.
4341
- *
4342
- * @see {@link touchFile}
4343
- * @see {@link getSnapshot}
4344
- *
4345
- * @since 2.0.0
4346
- */
4347
- getOrTouchFile(path: string): FileSnapshotInterface;
4348
- /**
4349
- * Returns array containing all currently tracked resolved absolute paths.
3881
+ * Provides read-only access to the error's structured stack information,
3882
+ * which can be used for:
3883
+ * - Custom error logging
3884
+ * - Error reporting services
3885
+ * - Debugging tools
3886
+ * - Stack analysis
4350
3887
  *
4351
- * @returns list of normalized absolute paths (using forward slashes)
3888
+ * @example
3889
+ * ```ts
3890
+ * try {
3891
+ * throw new ValidationError('Invalid input');
3892
+ * } catch (error) {
3893
+ * if (error instanceof xBuildBaseError) {
3894
+ * const meta = error.metadata;
3895
+ * console.log(`Error at ${meta?.source}:${meta?.line}:${meta?.column}`);
3896
+ * }
3897
+ * }
3898
+ * ```
4352
3899
  *
4353
3900
  * @since 2.0.0
4354
3901
  */
4355
- getTrackedFilePaths(): Array<string>;
3902
+ get metadata(): ResolveMetadataInterface | undefined;
4356
3903
  /**
4357
- * Ensures the file is tracked and returns an up-to-date snapshot state.
3904
+ * Parses the error stack trace and generates enhanced formatting with metadata.
4358
3905
  *
4359
- * @param path - Filesystem path (relative or absolute)
4360
- * @returns Shallow copy of the current (possibly just updated) snapshot entry
3906
+ * @param error - The error object to parse and format
3907
+ * @param options - Optional configuration for stack trace parsing and formatting
4361
3908
  *
4362
3909
  * @remarks
4363
- * This method implements incremental file tracking with three possible outcomes:
4364
- *
4365
- * **Fast path (no changes):**
4366
- * - mtime hasn't changed → returns existing state without I/O
4367
- *
4368
- * **Update path (file changed):**
4369
- * - mtime changed or file is new → reads content and creates fresh `ScriptSnapshot`
4370
- * - Increments version number for TypeScript language service invalidation
4371
- *
4372
- * **Error path (file unavailable):**
4373
- * - File cannot be read (deleted/permission denied) → clears snapshot and bumps version
4374
- * - Version increment only occurs if there was previous content (prevents silent no-ops)
3910
+ * This method performs two operations:
3911
+ * 1. Parses the error's stack trace using {@link getErrorMetadata} to extract structured metadata
3912
+ * 2. Formats the metadata using {@link formatStack} to create a styled, human-readable output
4375
3913
  *
4376
- * Always returns a shallow copy to prevent accidental mutation of internal state.
3914
+ * The parsed metadata is stored in {@link errorMetadata} and the formatted string in {@link formattedStack}.
4377
3915
  *
4378
- * Typically used in watch mode to notify TypeScript of file changes without full rebuilds.
3916
+ * **Typical usage:** Call this method in the constructor of derived error classes to enable
3917
+ * enhanced stack trace formatting.
4379
3918
  *
4380
3919
  * @example
4381
3920
  * ```ts
4382
- * const snapshot = filesModel.touchFile('./src/index.ts');
4383
- *
4384
- * if (snapshot.contentSnapshot) {
4385
- * languageServiceHost.getScriptSnapshot = () => snapshot.contentSnapshot;
4386
- * languageServiceHost.getScriptVersion = () => String(snapshot.version);
3921
+ * class NetworkError extends xBuildBaseError {
3922
+ * constructor(message: string, public readonly statusCode: number) {
3923
+ * super(message, 'NetworkError');
3924
+ * // Enable enhanced formatting without framework frames
3925
+ * this.reformatStack(this, {
3926
+ * withFrameworkFrames: false,
3927
+ * withNativeFrames: true
3928
+ * });
3929
+ * }
4387
3930
  * }
4388
3931
  * ```
4389
3932
  *
4390
- * @see {@link getSnapshot}
4391
- * @see {@link FileSnapshotInterface}
4392
- *
4393
- * @since 2.0.0
4394
- */
4395
- touchFile(path: string): FileSnapshotInterface;
4396
- /**
4397
- * Normalizes the given path to an absolute path using forward slashes.
4398
- * Results are cached to avoid repeated `path.resolve` + replace calls.
3933
+ * @example
3934
+ * ```ts
3935
+ * class CustomError extends xBuildBaseError {
3936
+ * constructor(message: string) {
3937
+ * super(message, 'CustomError');
3938
+ * // Use default options
3939
+ * this.reformatStack(this);
3940
+ * }
3941
+ * }
3942
+ * ```
4399
3943
  *
4400
- * @param path - any filesystem path
4401
- * @returns normalized absolute path (always `/` separators)
3944
+ * @see {@link formatStack} for formatting logic
3945
+ * @see {@link getErrorMetadata} for parsing logic
3946
+ * @see {@link StackTraceInterface} for available options
4402
3947
  *
4403
3948
  * @since 2.0.0
4404
3949
  */
4405
- resolve(path: string): string;
3950
+ protected reformatStack(error: Error, options?: StackTraceInterface): void;
3951
+ }
3952
+ /**
3953
+ * Configuration options for parsing and formatting stack traces.
3954
+ *
3955
+ * @remarks
3956
+ * These options control how stack traces are parsed, what frames are included,
3957
+ * and how much source code context is displayed. Used by {@link getErrorMetadata}
3958
+ * to customize stack trace output.
3959
+ *
3960
+ * @see stackEntry
3961
+ * @see getErrorMetadata
3962
+ *
3963
+ * @since 2.0.0
3964
+ */
3965
+ interface StackTraceInterface extends Omit<ResolveOptionsInterface, 'getSource'> {
4406
3966
  /**
4407
- * Creates a new snapshot entry for a resolved file path and registers it in the cache.
3967
+ * Whether to include framework-internal stack frames in the output.
4408
3968
  *
4409
- * @param resolvedPath - Normalized absolute file path
4410
- * @returns A new {@link FileSnapshotInterface} with initial state (version 0, no content)
3969
+ * @defaultValue Based on `ConfigurationService.verbose` setting
4411
3970
  *
4412
3971
  * @remarks
4413
- * This method initializes a new file tracking entry with default values:
4414
- * - `version`: 0 (will increment on first read)
4415
- * - `mtimeMs`: 0 (will update on first sync)
4416
- * - `contentSnapshot`: undefined (will populate on first sync)
4417
- *
4418
- * The entry is immediately added to {@link snapshotsByPath} to prevent duplicate creation.
4419
- *
4420
- * Called internally by {@link touchFile} when encountering a previously unseen file path.
3972
+ * Framework frames are identified by {@link FrameworkService.isFrameworkFile}.
3973
+ * When false, these frames are filtered out to reduce noise in stack traces.
3974
+ * Automatically set based on the `verbose` configuration setting if not
3975
+ * explicitly provided.
4421
3976
  *
4422
- * @since 2.1.5
3977
+ * @see FrameworkService.isFrameworkFile
3978
+ * @since 2.0.0
4423
3979
  */
4424
- private createEntry;
3980
+ withFrameworkFrames?: boolean;
3981
+ }
3982
+ /**
3983
+ * Additional metadata used when resolving and formatting source output.
3984
+ *
3985
+ * @remarks
3986
+ * Extends the base xMap resolution metadata with optional formatted code text
3987
+ * that can be attached to the resolution result.
3988
+ *
3989
+ * @since 2.2.5
3990
+ */
3991
+ interface ResolveMetadataInterface extends xMapResolveMetadataInterface {
4425
3992
  /**
4426
- * Synchronizes a snapshot entry with the current file system state.
4427
- *
4428
- * @param resolvedPath - Normalized absolute path to the file
4429
- * @param entry - The snapshot entry to update
3993
+ * Formatted source code associated with the resolved item.
4430
3994
  *
4431
3995
  * @remarks
4432
- * This method performs efficient incremental updates:
4433
- *
4434
- * **Optimization check:**
4435
- * - Compares current mtime with cached mtime
4436
- * - Returns immediately if file hasn't changed (fast path)
4437
- *
4438
- * **Update logic:**
4439
- * - Reads file content only when mtime differs
4440
- * - Increments version for TypeScript invalidation
4441
- * - Updates mtime to current value
4442
- * - Creates TypeScript `ScriptSnapshot` from content
4443
- *
4444
- * **File descriptor handling:**
4445
- * - Opens file in read mode (`'r'`)
4446
- * - Ensures file descriptor closure via `finally` block
4447
- * - Throws on read errors (handled by caller)
4448
- *
4449
- * Empty file content results in `undefined` snapshot rather than empty snapshot,
4450
- * signaling that the file has no compilable content.
4451
- *
4452
- * @throws Will propagate file system errors (ENOENT, EACCES, etc.) to caller
3996
+ * Typically used when a resolved file needs to preserve or expose its
3997
+ * transformed code representation for later processing or display.
4453
3998
  *
4454
- * @since 2.1.5
3999
+ * @since 2.2.5
4455
4000
  */
4456
- private syncEntry;
4001
+ formatCode?: string;
4457
4002
  }
4458
4003
  /**
4459
4004
  * Separates glob patterns into include and exclude arrays.