@remotex-labs/xbuild 2.5.0 → 3.0.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/bash.d.ts CHANGED
@@ -3,3 +3,3138 @@
3
3
  * DO NOT EDIT MANUALLY.
4
4
  */
5
5
 
6
+ import { BuildOptions, BuildResult, Loader, Message, Metafile, OnLoadArgs, OnLoadResult, OnResolveArgs, OnResolveResult, OnStartResult, PartialMessage, Platform, PluginBuild } from 'esbuild';
7
+ import { NextType, Observable, ObserverInterface, UnsubscribeType } from '@remotex-labs/xobservable';
8
+ import { Options } from 'yargs';
9
+ import { Stats } from 'fs';
10
+ import { IncomingMessage, ServerResponse } from 'http';
11
+
12
+ /**
13
+ * Runs a whole configuration - every variant it declares, in the order their dependencies allow.
14
+ *
15
+ * @remarks
16
+ * Owns the configuration for a run and the event stream the variants report on,
17
+ * while each variant owns the build it runs.
18
+ * A variant is constructed for every entry the configuration declares and reused from then on,
19
+ * so re-reading an edited configuration adds what it gained and leaves the rest running.
20
+ *
21
+ * @example
22
+ * ```ts
23
+ * const build = new BuildService(config, { watch: true });
24
+ * build.subscribe(event => event.type); // 'start', then 'end'
25
+ *
26
+ * const results = await build.build();
27
+ * results.length; // 2 - one per variant
28
+ * ```
29
+ *
30
+ * @see VariantService
31
+ * @see ConfigurationInterface
32
+ *
33
+ * @since 3.0.0
34
+ */
35
+ declare class BuildService {
36
+ private argv;
37
+ /**
38
+ * The stream every variant reports its start and end on.
39
+ *
40
+ * @remarks
41
+ * Handed to each variant as it is constructed, so one stream carries the whole run
42
+ * rather than a reader subscribing to each variant in turn.
43
+ * Kept private and reached through `pipe` and `subscribe`,
44
+ * which is what keeps a reader from pushing an event of its own onto it.
45
+ *
46
+ * @see LifecycleEventsType
47
+ * @since 3.0.0
48
+ */
49
+ private readonly events$;
50
+ /**
51
+ * The configuration service this run reads and writes through.
52
+ *
53
+ * @remarks
54
+ * The injected instance rather than one of its own, and the same instance every variant selects from,
55
+ * so a change written here reaches the variants without being handed to them.
56
+ *
57
+ * @see ConfigurationService
58
+ * @since 3.0.0
59
+ */
60
+ private readonly config$;
61
+ /**
62
+ * Applies a configuration and constructs a variant for every entry it declares.
63
+ *
64
+ * @param config - Configuration to run, merged over whatever the service already holds
65
+ * @param argv - Parsed command line the build was started with, empty when the caller passes none
66
+ *
67
+ * @remarks
68
+ * The configuration is patched rather than put in place of what is there,
69
+ * so the built-in defaults survive underneath what a configuration file states.
70
+ * The subscription that follows is called at once with the merged configuration,
71
+ * which is what constructs the variants before the constructor returns,
72
+ * and it keeps them current with every later change.
73
+ *
74
+ * @example
75
+ * ```ts
76
+ * const build = new BuildService({ logLevel: 'warning', variants: { esm } }, { watch: true });
77
+ * ```
78
+ *
79
+ * @see ConfigurationService.patch
80
+ * @since 3.0.0
81
+ */
82
+ constructor(config: ConfigurationInterface, argv?: Record<string, unknown>);
83
+ /**
84
+ * The event stream's `pipe`, bound to the stream.
85
+ *
86
+ * @remarks
87
+ * Hands out the operator chain without handing out the subject,
88
+ * so a reader composes on the run's events and cannot report one of its own.
89
+ *
90
+ * @example
91
+ * ```ts
92
+ * const ended = build.pipe(filter(event => event.type === 'end'));
93
+ * ended.subscribe(report);
94
+ * ```
95
+ *
96
+ * @see BuildService.subscribe
97
+ * @since 3.0.0
98
+ */
99
+ get pipe(): typeof this.events$.pipe;
100
+ /**
101
+ * The event stream's `subscribe`, bound to the stream.
102
+ *
103
+ * @remarks
104
+ * The plain way to watch a run, for a reader wanting every event rather than a filtered view.
105
+ * Answers with the handle that ends the subscription, as the stream's own `subscribe` does.
106
+ *
107
+ * @example
108
+ * ```ts
109
+ * const unsubscribe = build.subscribe(event => event.type); // 'start', then 'end'
110
+ * unsubscribe();
111
+ * ```
112
+ *
113
+ * @see BuildService.pipe
114
+ * @since 3.0.0
115
+ */
116
+ get subscribe(): typeof this.events$.subscribe;
117
+ /**
118
+ * Starts the configuration again from the one this service was constructed with.
119
+ *
120
+ * @param config - Configuration to apply over the initial one
121
+ *
122
+ * @remarks
123
+ * Reloads rather than patches, so whatever accumulated since construction is dropped,
124
+ * and only the initial configuration survives underneath.
125
+ * That is what re-reading an edited file wants, since patching a list would extend it rather than replace it.
126
+ * Assigning is also what ends a variant,
127
+ * since one the new configuration no longer declares disposes of itself as the change reaches it.
128
+ *
129
+ * @example
130
+ * ```ts
131
+ * build.configuration = { common: { esbuild: { minify: false } } };
132
+ * ```
133
+ *
134
+ * @see ConfigurationService.reload
135
+ * @since 3.0.0
136
+ */
137
+ set configuration(config: DeepPartialType<ConfigurationInterface>);
138
+ /**
139
+ * Builds the variants named, or every variant the configuration declares, in the order `dependOn` asks for.
140
+ *
141
+ * @param names - Variants to build, building every variant the configuration declares when omitted
142
+ * @returns One result per variant asked for, in the order they were named
143
+ * @throws xBuildError - When a `dependOn` chain closes on itself, or names a variant that does not exist
144
+ *
145
+ * @remarks
146
+ * Naming variants builds those and whatever they wait for, leaving everything else alone.
147
+ * A name no variant answers to is passed over rather than reported as an error,
148
+ * so a list naming nothing this configuration declares builds nothing at all.
149
+ * A dependency built along the way reports on the event stream like any other build
150
+ * while staying out of the results, which carry the variants that were asked for.
151
+ * The whole graph is wired before any variant runs, and every variant waits on the same gate,
152
+ * so a chain that turns out to be broken builds nothing at all rather than part of the output.
153
+ * A variant that several others depend on is built once and its result shared,
154
+ * since the graph is walked through a cache keyed by name.
155
+ * A build that fails does not reject here - its errors arrive on its own result.
156
+ * A dependency counts as failed where it produced no output, whether it threw or only reported errors.
157
+ * The variant waiting on it is skipped rather than built,
158
+ * and the result {@link skipped} shapes carries no output either, so its own dependents skip in turn.
159
+ *
160
+ * @example
161
+ * ```ts
162
+ * const results = await build.build();
163
+ * results.length; // 2 - the types variant first, then the bundle that depends on it
164
+ *
165
+ * const [ app ] = await build.build([ 'app' ]); // types builds too, since app waits for it
166
+ * await build.build([ 'umd' ]); // [] - no variant answers to the name
167
+ * ```
168
+ *
169
+ * @see BuildResultInterface
170
+ * @since 3.0.0
171
+ */
172
+ build(names?: Array<string>): Promise<Array<BuildResultInterface>>;
173
+ /**
174
+ * Type-checks the variants named, or every variant the configuration declares, without building any of them.
175
+ *
176
+ * @param names - Variants to check, checking every variant the configuration declares when omitted
177
+ * @returns The messages each variant's check reported, keyed by the variant's name
178
+ *
179
+ * @remarks
180
+ * The variants are checked one at a time rather than together,
181
+ * since every variant carries a TypeScript program of its own.
182
+ * Each variant answers with the buckets a build would file its messages under,
183
+ * so a diagnostic reads at the level the configuration gives it rather than in the compiler's own shape.
184
+ * A variant that checks clean is present with its buckets empty rather than left out,
185
+ * so a reader tells a clean variant from one that was never checked.
186
+ * Only the variants named are checked, dependencies among them or not,
187
+ * since a variant is checked against the files its own build reaches,
188
+ * and what another variant reaches is that variant's own to report.
189
+ * A name is matched against the variants rather than looked up,
190
+ * so one no variant answers to is passed over,
191
+ * and a list naming nothing this configuration declares checks nothing at all.
192
+ *
193
+ * @example
194
+ * ```ts
195
+ * const { esm } = await build.typeChack();
196
+ * esm.error.length; // 0 - nothing to report
197
+ *
198
+ * await build.typeChack([ 'esm' ]); // { esm: { ... } } - cjs is left alone
199
+ * await build.typeChack([ 'umd' ]); // {} - no variant answers to the name
200
+ * ```
201
+ *
202
+ * @see LifecycleLogsType
203
+ * @since 3.0.0
204
+ */
205
+ typeChack(names?: Array<string>): Promise<Record<string, LifecycleLogsType>>;
206
+ /**
207
+ * Re-reads the TypeScript configuration from disk.
208
+ *
209
+ * @remarks
210
+ * Reparses the configuration so a later check or build reads it as it now stands,
211
+ * which is what a watch cycle needs after an edit to `tsconfig.json`.
212
+ * The list of files reparsed is dropped rather than passed on, so a caller learns only that the reparse ran.
213
+ * Nothing here waits on anything, so the promise settles at once.
214
+ *
215
+ * @example
216
+ * ```ts
217
+ * await build.reload(); // the TypeScript configuration is read again
218
+ * ```
219
+ *
220
+ * @see TypescriptService.reload
221
+ * @since 3.0.0
222
+ */
223
+ reload(): Promise<void>;
224
+ /**
225
+ * Constructs a variant for every entry the configuration declares.
226
+ *
227
+ * @param config - Configuration as it now stands
228
+ * @throws xBuildError - When there is no configuration to read variants from
229
+ *
230
+ * @remarks
231
+ * A name that already has a variant is passed over,
232
+ * so re-reading a configuration adds what it gained
233
+ * and leaves the variants it kept running rather than replacing them.
234
+ * Nothing is removed here,
235
+ * since a variant the configuration stopped declaring watches its own entry and disposes of itself.
236
+ *
237
+ * @see VariantService
238
+ * @since 3.0.0
239
+ */
240
+ private parseVariants;
241
+ /**
242
+ * Shapes the result of a variant that was skipped rather than run and reports it as an end.
243
+ *
244
+ * @param name - Variant that was not built
245
+ * @param dependencies - Names of the dependencies that failed, in the order the variant declared them
246
+ * @returns A result carrying one error naming them, and nothing at any other level
247
+ *
248
+ * @remarks
249
+ * Shaped as a build result rather than as a thrown error,
250
+ * so a skipped variant reads like a failed one to whatever reports the run.
251
+ * It carries no metafile, which is what makes its own dependents skip in turn,
252
+ * since a dependency that produced no output is what the graph reads as a failure.
253
+ * Nothing was compiled, so every bucket but `errors` comes back empty.
254
+ * The result is built from the buckets the context carries rather than from a second literal,
255
+ * so a level cannot be named in one and missing from the other,
256
+ * and a reader of the event and a reader of the result are looking at the same messages.
257
+ * The same result goes out on the event stream as an end,
258
+ * since a variant that never ran reports no end of its own.
259
+ * A reader would otherwise see the run finish, with one variant missing from the count.
260
+ * The context is assembled here rather than taken from a build,
261
+ * so its options are the ones the configuration states, and its duration is zero.
262
+ *
263
+ * @example
264
+ * ```ts
265
+ * const { errors } = this.skipped('app', [ 'types' ]);
266
+ * errors[0].text; // 'Variant "app" was not built, because "types" failed'
267
+ * ```
268
+ *
269
+ * @see BuildResultInterface
270
+ * @since 3.0.0
271
+ */
272
+ private skipped;
273
+ /**
274
+ * Returns the variants one variant waits for.
275
+ *
276
+ * @param name - Variant whose dependencies are wanted
277
+ * @returns The names it depends on, empty when it depends on none
278
+ *
279
+ * @remarks
280
+ * Read from the configuration as it stands rather than from a copy taken when the run began.
281
+ * A single name is flattened into a list, so both forms `dependOn` accepts read the same way here.
282
+ *
283
+ * @see VariantConfigurationInterface
284
+ * @since 3.0.0
285
+ */
286
+ private getDependOn;
287
+ }
288
+ /**
289
+ * The messages a build has collected, filed under the level each was reported at.
290
+ *
291
+ * @remarks
292
+ * Keyed by every level but `silent`, since a message reported at `silent` is dropped rather than kept.
293
+ * Each bucket holds esbuild messages in the order they arrived,
294
+ * so a reporter reads the level it cares about instead of filtering the rest out itself.
295
+ *
296
+ * @example
297
+ * ```ts
298
+ * const logs: LifecycleLogsType = { debug: [], info: [], warning: [], error: [] };
299
+ * logs.error.length; // 0 - nothing has failed yet
300
+ * ```
301
+ *
302
+ * @see LogLevelType
303
+ * @see PartialMessage
304
+ *
305
+ * @since 3.0.0
306
+ */
307
+ type LifecycleLogsType = Record<Exclude<LogLevelType, 'silent'>, Array<PartialMessage>>;
308
+ /**
309
+ * The scratch state the hooks of a single build share.
310
+ *
311
+ * @remarks
312
+ * Reset at the start of every build, with the time it began stamped and its two sets empty,
313
+ * so nothing carries over from the build before it.
314
+ * The index signature is what lets one hook leave a value behind for a later one to read.
315
+ *
316
+ * @example
317
+ * ```ts
318
+ * context.stage.startTime; // when this build began
319
+ * context.stage.loaded = 12; // read back in a later hook
320
+ * ```
321
+ *
322
+ * @see LifecycleContextInterface
323
+ * @since 2.0.0
324
+ */
325
+ interface LifecycleStageInterface {
326
+ /**
327
+ * When the build began.
328
+ *
329
+ * @remarks
330
+ * Stamped as the build starts and left alone afterward,
331
+ * so a hook needing an elapsed time subtracts it rather than timing the build itself.
332
+ *
333
+ * @example
334
+ * ```ts
335
+ * Date.now() - context.stage.startTime.getTime(); // 1284
336
+ * ```
337
+ *
338
+ * @since 2.0.0
339
+ */
340
+ startTime: Date;
341
+ /**
342
+ * The names of the macro bindings in this build are to drop.
343
+ *
344
+ * @remarks
345
+ * What {@link analyzeMacros} collected from the build's inputs, left here for the stages that run after it,
346
+ * so a hook rewriting a source reads the set rather than analyzing the file for itself.
347
+ * Empty when no input declares a conditional macro.
348
+ *
349
+ * @example
350
+ * ```ts
351
+ * context.stage.dropped.has('$$dev'); // true - its flag resolved to 'false'
352
+ * ```
353
+ *
354
+ * @see analyzeMacros
355
+ * @since 3.0.0
356
+ */
357
+ dropped: Set<string>;
358
+ /**
359
+ * The inputs this build reaches, as the dependency scan named them.
360
+ *
361
+ * @remarks
362
+ * The setup stage collects them from a scan of the entry points with the plugins stripped,
363
+ * so a hook needing the whole input list reads the set rather than walking the graph itself.
364
+ * {@link analyzeMacros} reads the same set,
365
+ * which is what resolves a conditional binding against every file the build reaches.
366
+ * Filled for a bundled build and an unbundled one alike, and empty until the setup stage fills it.
367
+ *
368
+ * @example
369
+ * ```ts
370
+ * context.stage.reachableFiles.has('src/index.ts'); // true
371
+ * ```
372
+ *
373
+ * @see analyzeMacros
374
+ * @since 3.0.0
375
+ */
376
+ reachableFiles: Set<string>;
377
+ /**
378
+ * Any other value a hook chooses to leave on the stage.
379
+ *
380
+ * @remarks
381
+ * Typed as `unknown`, so whatever reads a key back narrows it before use.
382
+ *
383
+ * @example
384
+ * ```ts
385
+ * context.stage.loaded = 12;
386
+ * context.stage.loaded as number; // 12
387
+ * ```
388
+ *
389
+ * @since 2.0.0
390
+ */
391
+ [key: string]: unknown;
392
+ }
393
+ /**
394
+ * An esbuild build result, widened with the levels esbuild does not report on one.
395
+ *
396
+ * @remarks
397
+ * esbuild returns `errors` and `warnings` alone.
398
+ * The two fields beside them carry the messages collected at the quieter levels,
399
+ * so an end hook sees everything the build said and not only what failed it.
400
+ *
401
+ * @example
402
+ * ```ts
403
+ * const result: BuildResultInterface = { ...buildResult, info: [], debugs: [] };
404
+ * result.errors.length; // 0
405
+ * result.debugs.length; // 4
406
+ * ```
407
+ *
408
+ * @see BuildResultType
409
+ * @see EndContextInterface
410
+ *
411
+ * @since 3.0.0
412
+ */
413
+ interface BuildResultInterface extends BuildResultType {
414
+ /**
415
+ * The messages this build reported at the `info` level.
416
+ *
417
+ * @remarks
418
+ * Carries no fault, so a reader printing a build summary shows these without treating the build as broken.
419
+ *
420
+ * @example
421
+ * ```ts
422
+ * result.info.length; // 3
423
+ * ```
424
+ *
425
+ * @since 3.0.0
426
+ */
427
+ info: Array<Message>;
428
+ /**
429
+ * The messages this build reported at the `debug` level.
430
+ *
431
+ * @remarks
432
+ * The quietest level, kept for a run asking to see it and ignored by everything else.
433
+ *
434
+ * @example
435
+ * ```ts
436
+ * result.debugs.map(message => message.text); // [ 'resolved src/index.ts' ]
437
+ * ```
438
+ *
439
+ * @since 3.0.0
440
+ */
441
+ verbose: Array<Message>;
442
+ }
443
+ /**
444
+ * What every hook of a build is handed, whichever stage it runs in.
445
+ *
446
+ * @remarks
447
+ * One object for the whole build, so a value a hook writes onto `stage` is still there for the next one.
448
+ * Everything beside `stage` describes the build itself:
449
+ * which variant it is, the options it runs under, the arguments that started it, and what it has reported so far.
450
+ *
451
+ * @example
452
+ * ```ts
453
+ * const lifecycle: LifecycleHooksInterface = {
454
+ * onStart: ({ context }) => {
455
+ * context.variantName; // 'esm'
456
+ * context.stage.count = 0;
457
+ * }
458
+ * };
459
+ * ```
460
+ *
461
+ * @see LifecycleHooksInterface
462
+ * @see LifecycleStageInterface
463
+ *
464
+ * @since 3.0.0
465
+ */
466
+ interface LifecycleContextInterface {
467
+ /**
468
+ * The arguments the build was started with.
469
+ *
470
+ * @remarks
471
+ * The parsed command line, so a hook follows a flag without reading `process.argv` itself.
472
+ *
473
+ * @example
474
+ * ```ts
475
+ * context.argv; // { watch: true, build: 'esm' }
476
+ * ```
477
+ *
478
+ * @since 2.0.0
479
+ */
480
+ argv: Record<string, unknown>;
481
+ /**
482
+ * The name of the variant being built.
483
+ *
484
+ * @remarks
485
+ * The key the variant is written under in the configuration,
486
+ * which is also what labels its messages and what the `--build` flag selects.
487
+ *
488
+ * @example
489
+ * ```ts
490
+ * context.variantName; // 'esm'
491
+ * ```
492
+ *
493
+ * @since 2.0.0
494
+ */
495
+ variantName: string;
496
+ /**
497
+ * The esbuild options this build runs under.
498
+ *
499
+ * @remarks
500
+ * The common block and the variant are already merged,
501
+ * so it reads as what esbuild was given rather than as what the configuration file wrote.
502
+ *
503
+ * @example
504
+ * ```ts
505
+ * context.options.format; // 'esm'
506
+ * context.options.outdir; // 'dist/esm'
507
+ * ```
508
+ *
509
+ * @since 2.2.0
510
+ */
511
+ options: BuildOptions;
512
+ /**
513
+ * The messages this build has collected so far.
514
+ *
515
+ * @remarks
516
+ * Filled as the build runs, so a hook reading it early sees only what has been reported up to that point.
517
+ *
518
+ * @example
519
+ * ```ts
520
+ * context.logs.warning.length; // 2
521
+ * context.logs.error.length; // 0 - nothing has failed yet
522
+ * ```
523
+ *
524
+ * @see LifecycleLogsType
525
+ * @since 3.0.0
526
+ */
527
+ logs: LifecycleLogsType;
528
+ /**
529
+ * The scratch state this build's hooks share.
530
+ *
531
+ * @remarks
532
+ * The one part of the context a hook is meant to write to, and the only one reset between builds.
533
+ *
534
+ * @example
535
+ * ```ts
536
+ * context.stage.startTime; // when this build began
537
+ * ```
538
+ *
539
+ * @see LifecycleStageInterface
540
+ * @since 2.0.0
541
+ */
542
+ stage: LifecycleStageInterface;
543
+ /**
544
+ * The level each esbuild message is reported at, keyed by its message id or by a pattern matching one.
545
+ *
546
+ * @remarks
547
+ * Lifts or lowers one message without moving the level everything else is reported at,
548
+ * and `silent` drops it rather than filing it under a bucket.
549
+ * The table is the one the configuration declared, read as written rather than in a form prepared for the build,
550
+ * so a hook inspecting it sees the keys a reader of the configuration file would.
551
+ * Each key is matched against a message id once per build and the outcome held,
552
+ * so an entry added while a build runs governs only the ids that the build has yet to report.
553
+ *
554
+ * @example
555
+ * ```ts
556
+ * context.overrides['unsupported-require-call']; // 'silent'
557
+ * ```
558
+ *
559
+ * @see LogOverridesType
560
+ * @since 3.0.0
561
+ */
562
+ overrides: LogOverridesType;
563
+ }
564
+ /**
565
+ * What an `onStart` hook is handed.
566
+ *
567
+ * @remarks
568
+ * Adds esbuild itself to the shared context, so a start hook can transform or build something of its own
569
+ * before the run it belongs to reads a file.
570
+ * It is the only stage given esbuild, since the ones after it run while the build is already under way.
571
+ *
572
+ * @example
573
+ * ```ts
574
+ * const onStart: LifecycleHooksInterface['onStart'] = async ({ esbuild, context }) => {
575
+ * const out = await esbuild.transform('let a = 1', { minify: true });
576
+ * out.code; // 'let a=1;\n'
577
+ * };
578
+ * ```
579
+ *
580
+ * @see LifecycleContextInterface
581
+ * @since 3.0.0
582
+ */
583
+ interface StartContextInterface {
584
+ /**
585
+ * The esbuild module driving this build.
586
+ *
587
+ * @remarks
588
+ * The instance the build resolved, so a hook calling `transform` or `build` on it works against
589
+ * the same version rather than the one it imported for itself.
590
+ *
591
+ * @example
592
+ * ```ts
593
+ * const out = await esbuild.transform('let a = 1', { minify: true });
594
+ * out.code; // 'let a=1;\n'
595
+ * ```
596
+ *
597
+ * @since 3.0.0
598
+ */
599
+ esbuild: PluginBuild['esbuild'];
600
+ /**
601
+ * The context shared by every hook of this build.
602
+ *
603
+ * @remarks
604
+ * Already populated when a start hook runs, `stage` carrying the time the build began
605
+ * along with what the setup stage left on it.
606
+ *
607
+ * @example
608
+ * ```ts
609
+ * context.variantName; // 'esm'
610
+ * ```
611
+ *
612
+ * @see LifecycleContextInterface
613
+ * @since 3.0.0
614
+ */
615
+ context: LifecycleContextInterface;
616
+ }
617
+ /**
618
+ * What an `onEnd` or an `onSuccess` hook is handed.
619
+ *
620
+ * @remarks
621
+ * Adds the finished result and the time it took to the shared context.
622
+ * `onEnd` receives it. However, the build turned out `onSuccess` only when nothing failed,
623
+ * so a hook reading `buildResult.errors` is guarding the first case rather than the second.
624
+ *
625
+ * @example
626
+ * ```ts
627
+ * const onEnd: LifecycleHooksInterface['onEnd'] = ({ duration, buildResult }) => {
628
+ * `${ buildResult.errors.length } errors in ${ duration }ms`; // '0 errors in 1284ms'
629
+ * };
630
+ * ```
631
+ *
632
+ * @see BuildResultInterface
633
+ * @see LifecycleContextInterface
634
+ *
635
+ * @since 3.0.0
636
+ */
637
+ interface EndContextInterface {
638
+ /**
639
+ * The context shared by every hook of this build.
640
+ *
641
+ * @remarks
642
+ * Carries whatever the earlier stages left on `stage`, which is how an end hook reaches what they counted.
643
+ *
644
+ * @example
645
+ * ```ts
646
+ * context.stage.loaded; // 12
647
+ * ```
648
+ *
649
+ * @see LifecycleContextInterface
650
+ * @since 3.0.0
651
+ */
652
+ context: LifecycleContextInterface;
653
+ /**
654
+ * How long the build took, in milliseconds.
655
+ *
656
+ * @remarks
657
+ * Measured from `context.stage.startTime` to the moment the build finished,
658
+ * so a hook reports the figure rather than timing the build itself.
659
+ *
660
+ * @example
661
+ * ```ts
662
+ * duration; // 1284
663
+ * ```
664
+ *
665
+ * @since 3.0.0
666
+ */
667
+ duration: number;
668
+ /**
669
+ * The finished build, with every level of message it produced.
670
+ *
671
+ * @remarks
672
+ * esbuild's own result, widened with the quieter levels it does not return on one.
673
+ *
674
+ * @example
675
+ * ```ts
676
+ * buildResult.errors.length; // 0
677
+ * buildResult.warnings.length; // 2
678
+ * ```
679
+ *
680
+ * @see BuildResultInterface
681
+ * @since 3.0.0
682
+ */
683
+ buildResult: BuildResultInterface;
684
+ }
685
+ /**
686
+ * What an `onLoad` hook is handed.
687
+ *
688
+ * @remarks
689
+ * Carries the contents and the loader as they stand at this point in the chain,
690
+ * so a hook returning a new pair of hands it to the hook after it rather than straight back to esbuild.
691
+ * Returning nothing leaves both as they are.
692
+ *
693
+ * @example
694
+ * ```ts
695
+ * const onLoad: LifecycleHooksInterface['onLoad'] = ({ args, contents, loader }) => {
696
+ * args.path; // '/src/index.ts'
697
+ * return { contents: contents.trim(), loader };
698
+ * };
699
+ * ```
700
+ *
701
+ * @see LifecycleContextInterface
702
+ * @since 3.0.0
703
+ */
704
+ interface LoadContextInterface {
705
+ /**
706
+ * The file esbuild is loading.
707
+ *
708
+ * @remarks
709
+ * Names the path and the namespace it is loaded under, along with anything a resolve hook attached to it.
710
+ *
711
+ * @example
712
+ * ```ts
713
+ * args.path; // '/src/index.ts'
714
+ * args.namespace; // 'file'
715
+ * ```
716
+ *
717
+ * @since 2.0.0
718
+ */
719
+ args: OnLoadArgs;
720
+ /**
721
+ * The loader the contents are to be read with.
722
+ *
723
+ * @remarks
724
+ * `undefined` until something in the chain names one,
725
+ * after which esbuild reads the contents as that language instead of inferring it from the extension.
726
+ *
727
+ * @example
728
+ * ```ts
729
+ * loader; // undefined - esbuild picks one from the extension
730
+ * ```
731
+ *
732
+ * @since 2.0.0
733
+ */
734
+ loader: Loader | undefined;
735
+ /**
736
+ * The context shared by every hook of this build.
737
+ *
738
+ * @remarks
739
+ * The same object on every file loaded, which is what makes `stage` a place to count them.
740
+ *
741
+ * @example
742
+ * ```ts
743
+ * context.variantName; // 'esm'
744
+ * ```
745
+ *
746
+ * @see LifecycleContextInterface
747
+ * @since 3.0.0
748
+ */
749
+ context: LifecycleContextInterface;
750
+ /**
751
+ * The source as it stands at this point in the chain.
752
+ *
753
+ * @remarks
754
+ * The file as it was read for the first hook, and whatever the hook before returned for the ones after it.
755
+ *
756
+ * @example
757
+ * ```ts
758
+ * contents.includes('export default'); // true
759
+ * ```
760
+ *
761
+ * @since 3.0.0
762
+ */
763
+ contents: string;
764
+ }
765
+ /**
766
+ * What an `onResolve` hook is handed.
767
+ *
768
+ * @remarks
769
+ * Carries the import as it was written and the file that wrote it,
770
+ * which is what a hook needs to point a path elsewhere, mark it externally, or move it into a namespace of its own.
771
+ * Returning nothing leaves the path to esbuild.
772
+ *
773
+ * @example
774
+ * ```ts
775
+ * const onResolve: LifecycleHooksInterface['onResolve'] = ({ args }) => {
776
+ * if (!args.path.startsWith('node:')) return undefined;
777
+ *
778
+ * return { path: args.path, external: true }; // left as an import in the output
779
+ * };
780
+ * ```
781
+ *
782
+ * @see LifecycleContextInterface
783
+ * @since 3.0.0
784
+ */
785
+ interface ResolveContextInterface {
786
+ /**
787
+ * The import being resolved.
788
+ *
789
+ * @remarks
790
+ * Names the path as written, the file importing it, the directory a relative path resolves from,
791
+ * and the kind of import it came from.
792
+ *
793
+ * @example
794
+ * ```ts
795
+ * args.path; // './utils'
796
+ * args.importer; // '/src/index.ts'
797
+ * ```
798
+ *
799
+ * @since 2.0.0
800
+ */
801
+ args: OnResolveArgs;
802
+ /**
803
+ * The context shared by every hook of this build.
804
+ *
805
+ * @remarks
806
+ * The same object on every import resolved, so a hook deciding by variant reads `variantName` off it.
807
+ *
808
+ * @example
809
+ * ```ts
810
+ * context.variantName; // 'esm'
811
+ * ```
812
+ *
813
+ * @see LifecycleContextInterface
814
+ * @since 3.0.0
815
+ */
816
+ context: LifecycleContextInterface;
817
+ }
818
+ /**
819
+ * A build starting or finishing, tagged with which of the two it is.
820
+ *
821
+ * @remarks
822
+ * Discriminated on `type`, so narrowing on it gives the fields of the matching stage.
823
+ * The two per-build stages alone are in the union,
824
+ * since load and resolve fire once per file and have nothing to say about the build as a whole.
825
+ *
826
+ * @example
827
+ * ```ts
828
+ * const event: LifecycleEventsType = { type: 'end', context, duration: 1284, buildResult };
829
+ * event.type === 'end' && event.duration; // 1284
830
+ * ```
831
+ *
832
+ * @see EndContextInterface
833
+ * @see StartContextInterface
834
+ *
835
+ * @since 3.0.0
836
+ */
837
+ type LifecycleEventsType = EndContextInterface & {
838
+ type: 'end';
839
+ } | StartContextInterface & {
840
+ type: 'start';
841
+ };
842
+ /**
843
+ * The hooks a configuration attaches to a build.
844
+ *
845
+ * @remarks
846
+ * Every hook is optional, and each runs at one point of the build:
847
+ * `onStart` before any file is read, `onResolve` as each import is resolved, `onLoad` as each file is loaded,
848
+ * and `onEnd` once the build has finished.
849
+ * `onSuccess` takes the same context as `onEnd` and runs only when the build produced no errors.
850
+ *
851
+ * @example
852
+ * ```ts
853
+ * const lifecycle: LifecycleHooksInterface = {
854
+ * onStart: ({ context }) => {
855
+ * context.stage.loaded = 0;
856
+ * },
857
+ * onLoad: ({ context, contents, loader }) => ({
858
+ * contents: contents.replaceAll('__DEV__', 'false'),
859
+ * loader
860
+ * }),
861
+ * onEnd: ({ duration }) => {
862
+ * `done in ${ duration }ms`; // 'done in 1284ms'
863
+ * }
864
+ * };
865
+ * ```
866
+ *
867
+ * @see LifecycleContextInterface
868
+ * @since 3.0.0
869
+ */
870
+ interface LifecycleHooksInterface {
871
+ /**
872
+ * Runs once the build has finished. However, it turned out.
873
+ *
874
+ * @remarks
875
+ * The place to report on a build or clean up after it, since it is handed the result and the elapsed time.
876
+ * Work that only makes sense when nothing failed belongs on `onSuccess` instead.
877
+ *
878
+ * @example
879
+ * ```ts
880
+ * onEnd: ({ duration, buildResult }) => {
881
+ * `${ buildResult.errors.length } errors in ${ duration }ms`; // '0 errors in 1284ms'
882
+ * }
883
+ * ```
884
+ *
885
+ * @see EndContextInterface
886
+ * @since 3.0.0
887
+ */
888
+ onEnd?: (options: EndContextInterface) => MaybeVoidPromiseType<void>;
889
+ /**
890
+ * Runs once the build has finished with no errors.
891
+ *
892
+ * @remarks
893
+ * The same context as `onEnd`, narrowed to the case where nothing failed,
894
+ * so a hook publishing or deploying the output does not check `buildResult.errors` for itself.
895
+ *
896
+ * @example
897
+ * ```ts
898
+ * onSuccess: async ({ context }) => {
899
+ * await publish(context.options.outdir); // 'dist/esm'
900
+ * }
901
+ * ```
902
+ *
903
+ * @see EndContextInterface
904
+ * @since 3.0.0
905
+ */
906
+ onSuccess?: (options: EndContextInterface) => MaybeVoidPromiseType<void>;
907
+ /**
908
+ * Runs before the build reads its first file.
909
+ *
910
+ * @remarks
911
+ * The place to prepare whatever the later stages read, since it runs once and before anything is resolved.
912
+ * Returning an `OnStartResult` reports errors or warnings against the build instead of throwing at it.
913
+ *
914
+ * @example
915
+ * ```ts
916
+ * onStart: ({ context }) => {
917
+ * if (context.options.outdir) return undefined;
918
+ *
919
+ * return { errors: [{ text: 'no outdir' }] }; // the build reports it and stops
920
+ * }
921
+ * ```
922
+ *
923
+ * @see StartContextInterface
924
+ * @since 3.0.0
925
+ */
926
+ onStart?: (options: StartContextInterface) => MaybeVoidPromiseType<OnStartResult>;
927
+ /**
928
+ * Runs as each file is read, before esbuild parses it.
929
+ *
930
+ * @remarks
931
+ * Handed the contents and the loader as they stand, and may return a new pair,
932
+ * which is how a hook rewrites a source or teaches the build an extension it does not know.
933
+ * Returning nothing leaves both untouched.
934
+ *
935
+ * @example
936
+ * ```ts
937
+ * onLoad: ({ contents, loader }) => ({
938
+ * contents: contents.replaceAll('__DEV__', 'false'), // the next hook sees the replaced source
939
+ * loader
940
+ * })
941
+ * ```
942
+ *
943
+ * @see LoadContextInterface
944
+ * @since 3.0.0
945
+ */
946
+ onLoad?: (options: LoadContextInterface) => MaybeUndefinedPromiseType<OnLoadResult>;
947
+ /**
948
+ * Runs as each import is resolved, before esbuild looks for it on disk.
949
+ *
950
+ * @remarks
951
+ * Returning a path takes the resolution over, whether to redirect it, mark it externally,
952
+ * or move it into a namespace the build serves itself.
953
+ * Returning nothing leaves esbuild to resolve it.
954
+ *
955
+ * @example
956
+ * ```ts
957
+ * onResolve: ({ args }) => args.path.startsWith('node:')
958
+ * ? { path: args.path, external: true } // left as an import in the output
959
+ * : undefined
960
+ * ```
961
+ *
962
+ * @see ResolveContextInterface
963
+ * @since 3.0.0
964
+ */
965
+ onResolve?: (options: ResolveContextInterface) => MaybeUndefinedPromiseType<OnResolveResult>;
966
+ }
967
+ /**
968
+ * A named set of lifecycle hooks, packaged so several can stand beside one another on one build.
969
+ *
970
+ * @remarks
971
+ * The hooks of {@link LifecycleHooksInterface}, with a name to report them under and two of its own.
972
+ * `onSetup` runs before every build of the variant,
973
+ * and it is the one place a plugin changes the options a build receives.
974
+ * `onDispose` runs once as the variant goes away.
975
+ * Reach for a plugin where the hooks are shared between builds or projects and want naming,
976
+ * and for `lifecycle` where they belong to a single configuration.
977
+ *
978
+ * @example
979
+ * ```ts
980
+ * const timing: LifecyclePluginInterface = {
981
+ * name: 'timing',
982
+ * onSetup: ({ options }) => {
983
+ * options.minify = false; // this build runs unminified
984
+ * },
985
+ * onEnd: ({ duration }) => {
986
+ * `done in ${ duration }ms`; // 'done in 1284ms'
987
+ * }
988
+ * };
989
+ * ```
990
+ *
991
+ * @see LifecycleHooksInterface
992
+ * @see LifecycleContextInterface
993
+ *
994
+ * @since 3.0.0
995
+ */
996
+ interface LifecyclePluginInterface extends LifecycleHooksInterface {
997
+ /**
998
+ * The name this plugin is known by.
999
+ *
1000
+ * @remarks
1001
+ * Labels the plugin wherever a build reports it,
1002
+ * so a message coming out of one set of hooks names the set it came from.
1003
+ *
1004
+ * @example
1005
+ * ```ts
1006
+ * plugin.name; // 'timing'
1007
+ * ```
1008
+ *
1009
+ * @since 3.0.0
1010
+ */
1011
+ name: string;
1012
+ /**
1013
+ * Runs before each build of the variant.
1014
+ *
1015
+ * @remarks
1016
+ * Handed the context that the rest of the build's hooks share, while it is still open to change,
1017
+ * so writing to `options` here decides the options esbuild receives.
1018
+ * It runs on every build rather than once, which is what lets a watch cycle rebuild under different options.
1019
+ * A hook that shapes the build belongs here, and one that only runs at its start belongs on `onStart`.
1020
+ * Returning a promise holds the build until it settles.
1021
+ *
1022
+ * @example
1023
+ * ```ts
1024
+ * onSetup: ({ options, stage }) => {
1025
+ * options.minify = false; // this build runs unminified
1026
+ * stage.loaded = 0; // every later hook of this build reads it back
1027
+ * }
1028
+ * ```
1029
+ *
1030
+ * @see LifecycleContextInterface
1031
+ * @since 3.0.0
1032
+ */
1033
+ onSetup?: (setup: LifecycleContextInterface) => MaybeVoidPromiseType;
1034
+ }
1035
+ /**
1036
+ * The severity a build message is reported under.
1037
+ *
1038
+ * @remarks
1039
+ * `verbose` and `info` are for messages that carry no fault, `warning` and `error` for the ones that do,
1040
+ * and `silent` drops the message instead of collecting it.
1041
+ * The other four name the buckets a collected message is filed under,
1042
+ * which is why the log record excludes `silent` from its keys.
1043
+ *
1044
+ * @example
1045
+ * ```ts
1046
+ * const level: LogLevelType = 'warning';
1047
+ * ```
1048
+ *
1049
+ * @see LogOverridesType
1050
+ * @since 3.0.0
1051
+ */
1052
+ type LogLevelType = 'verbose' | 'info' | 'warning' | 'error' | 'silent';
1053
+ /**
1054
+ * The level a message is reported under, keyed by the id it is reported with.
1055
+ *
1056
+ * @remarks
1057
+ * A key is read as a whole id first, so an id written out verbatim stands for itself and is matched by name alone.
1058
+ * A key carrying regular-expression syntax is read as an anchored pattern instead,
1059
+ * which is how one entry can claim a family of ids.
1060
+ * Verbatim keys win over patterns, and the first pattern a configuration declared wins over the ones after it.
1061
+ *
1062
+ * @example
1063
+ * ```ts
1064
+ * const overrides: LogOverridesType = {
1065
+ * 'direct-eval': 'silent', // this id alone
1066
+ * 'TS-2\\d{3}': 'warning' // every TypeScript diagnostic in the 2000 range
1067
+ * };
1068
+ * ```
1069
+ *
1070
+ * @see LogLevelType
1071
+ * @see resolveLevel
1072
+ *
1073
+ * @since 3.0.0
1074
+ */
1075
+ type LogOverridesType = Record<string, LogLevelType>;
1076
+ /**
1077
+ * A copy of a type with every property optional, all the way down.
1078
+ *
1079
+ * @remarks
1080
+ * Recurses into object properties rather than stopping at the top level,
1081
+ * which is what lets a patch name one deeply nested setting and leave its siblings standing.
1082
+ * It is the shape a partial update takes, not the shape anything is stored in.
1083
+ *
1084
+ * @example
1085
+ * ```ts
1086
+ * type Config = { common: { esbuild: { minify: boolean, outdir: string } } };
1087
+ *
1088
+ * const patch: DeepPartialType<Config> = { common: { esbuild: { minify: false } } };
1089
+ * ```
1090
+ *
1091
+ * @since 2.0.0
1092
+ */
1093
+ type DeepPartialType<T> = {
1094
+ [K in keyof T]?: T[K] extends object ? DeepPartialType<T[K]> : T[K];
1095
+ };
1096
+ /**
1097
+ * Any value that is not an object.
1098
+ *
1099
+ * @remarks
1100
+ * The whole set of primitives, `null` and `undefined` among them,
1101
+ * so a value of this type compares with `===` and carries nothing worth walking.
1102
+ *
1103
+ * @example
1104
+ * ```ts
1105
+ * const port: PrimitiveType = 8080;
1106
+ * const absent: PrimitiveType = null;
1107
+ * ```
1108
+ *
1109
+ * @see PrimitiveOrObjectType
1110
+ * @since 3.0.0
1111
+ */
1112
+ type PrimitiveType = string | number | boolean | bigint | symbol | null | undefined;
1113
+ /**
1114
+ * A function that supplies a value when the build runs rather than when it is configured.
1115
+ *
1116
+ * @remarks
1117
+ * Receives the name it is producing a value for and the arguments the build was given,
1118
+ * so a setting can follow a flag without the configuration file reading the command line itself.
1119
+ * The result is primitive, since what it produces is substituted into the source as a literal.
1120
+ *
1121
+ * @example
1122
+ * ```ts
1123
+ * const release: RuntimeHandlerType = (name, args) => args.production === true;
1124
+ * ```
1125
+ *
1126
+ * @see PrimitiveType
1127
+ * @since 3.0.0
1128
+ */
1129
+ type RuntimeHandlerType = (name: string, args: Record<string, unknown>) => PrimitiveType;
1130
+ /**
1131
+ * A primitive, or a plain object keyed by name or symbol.
1132
+ *
1133
+ * @remarks
1134
+ * Widens {@link PrimitiveType} to cover a value that is substituted whole rather than as a single literal.
1135
+ *
1136
+ * @example
1137
+ * ```ts
1138
+ * const flag: PrimitiveOrObjectType = true;
1139
+ * const table: PrimitiveOrObjectType = { region: 'eu', retries: 3 };
1140
+ * ```
1141
+ *
1142
+ * @see PrimitiveType
1143
+ * @since 3.0.0
1144
+ */
1145
+ type PrimitiveOrObjectType = PrimitiveType | object | Record<string | symbol, unknown>;
1146
+ /**
1147
+ * What a hook returns when answering is optional.
1148
+ *
1149
+ * @typeParam T - The value a hook returns when it has one
1150
+ *
1151
+ * @remarks
1152
+ * Accepts the value itself, `void`, or a promise of either,
1153
+ * so a hook can be written synchronously or asynchronously and can decline to answer either way.
1154
+ * `null` belongs to the union only where `T` names it, which is what the default `T = null` does,
1155
+ * so the bare form describes a hook that never has an answer to give.
1156
+ *
1157
+ * @example
1158
+ * ```ts
1159
+ * const onStart: () => MaybeVoidPromiseType<OnStartResult> = () => undefined;
1160
+ * const onStartAsync: () => MaybeVoidPromiseType<OnStartResult> = async () => ({ warnings: [] });
1161
+ * const setup: () => MaybeVoidPromiseType = () => null;
1162
+ * ```
1163
+ *
1164
+ * @see MaybeUndefinedPromiseType
1165
+ * @since 3.0.0
1166
+ */
1167
+ type MaybeVoidPromiseType<T = null> = void | T | Promise<void | T>;
1168
+ /**
1169
+ * The same as {@link MaybeVoidPromiseType}, for a hook whose empty answer is `undefined`.
1170
+ *
1171
+ * @remarks
1172
+ * Used where esbuild reads the absence of a result as "carry on with the default",
1173
+ * which its load and resolve callbacks spell as `undefined` rather than as `void`.
1174
+ *
1175
+ * @example
1176
+ * ```ts
1177
+ * const onLoad: () => MaybeUndefinedPromiseType<OnLoadResult> = () => undefined;
1178
+ * ```
1179
+ *
1180
+ * @see MaybeVoidPromiseType
1181
+ * @since 2.0.0
1182
+ */
1183
+ type MaybeUndefinedPromiseType<T> = undefined | null | T | Promise<undefined | null | T>;
1184
+ /**
1185
+ * The result shape every build helper in this package returns.
1186
+ *
1187
+ * @remarks
1188
+ * Each helper fixes `metafile: true` after the caller's options, so a metafile is always there at runtime.
1189
+ * The type does not say so, since esbuild only drops the `undefined` from `metafile` when the options it is given
1190
+ * carry the literal `true`, which `BuildOptions & Metafile` does not.
1191
+ * A caller reading the field therefore still asserts it.
1192
+ *
1193
+ * @example
1194
+ * ```ts
1195
+ * const result: BuildResultType = await buildFiles({ entryPoints: [ 'src/index.ts' ] });
1196
+ * Object.keys(result.metafile!.inputs); // [ 'src/index.ts' ]
1197
+ * ```
1198
+ *
1199
+ * @see buildFiles
1200
+ * @since 3.0.0
1201
+ */
1202
+ type BuildResultType = BuildResult<BuildOptions & Metafile>;
1203
+ /**
1204
+ * The esbuild options a configuration is allowed to state.
1205
+ *
1206
+ * @remarks
1207
+ * esbuild's own options, less the ones this package assembles itself.
1208
+ * Plugins, defines, banners, footers, and the two logging settings are all built from the fields beside `esbuild`,
1209
+ * so a build has a single place to state each of them and no way to state one twice.
1210
+ *
1211
+ * @example
1212
+ * ```ts
1213
+ * const options: EsbuildOptionsType = { minify: true, format: 'esm', target: 'node20' };
1214
+ * ```
1215
+ *
1216
+ * @see BaseConfigurationInterface
1217
+ * @since 3.0.0
1218
+ */
1219
+ type EsbuildOptionsType = Omit<BuildOptions, 'plugins' | 'define' | 'banner' | 'footer' | 'logOverride' | 'logLevel'>;
1220
+ /**
1221
+ * Code injected into the output, either written out or produced when the build runs.
1222
+ *
1223
+ * @remarks
1224
+ * A string is injected as it stands, while a function is called at build time and its result injected instead,
1225
+ * which is what lets a banner carry a version or a timestamp the configuration file cannot know.
1226
+ *
1227
+ * @example
1228
+ * ```ts
1229
+ * const fixed: InjectableCodeType = '#!/usr/bin/env node';
1230
+ * const dynamic: InjectableCodeType = (name, args) => args.production === true;
1231
+ * ```
1232
+ *
1233
+ * @see RuntimeHandlerType
1234
+ * @since 3.0.0
1235
+ */
1236
+ type InjectableCodeType = string | RuntimeHandlerType;
1237
+ /**
1238
+ * How declaration files are emitted for a build that wants more than on or off.
1239
+ *
1240
+ * @remarks
1241
+ * The long form of `declaration`, reached only when the plain boolean will not do.
1242
+ *
1243
+ * @example
1244
+ * ```ts
1245
+ * const declaration: DeclarationOptionsInterface = { outDir: 'types' };
1246
+ * ```
1247
+ *
1248
+ * @see BaseConfigurationInterface
1249
+ * @since 2.0.0
1250
+ */
1251
+ interface DeclarationOptionsInterface {
1252
+ /**
1253
+ * Directory the declarations are written to.
1254
+ *
1255
+ * @remarks
1256
+ * Overrides what the TypeScript configuration would have chosen, so declarations can land apart from the code
1257
+ * without editing `tsconfig.json`.
1258
+ *
1259
+ * @example
1260
+ * ```ts
1261
+ * { outDir: 'types' } // dist/index.js beside types/index.d.ts
1262
+ * ```
1263
+ *
1264
+ * @since 2.0.0
1265
+ */
1266
+ outDir?: string;
1267
+ }
1268
+ /**
1269
+ * How type checking behaves for a build that wants more than on or off.
1270
+ *
1271
+ * @remarks
1272
+ * The long form of `types`, reached only when the plain boolean will not do.
1273
+ *
1274
+ * @example
1275
+ * ```ts
1276
+ * const types: TypeCheckOptionsInterface = { failOnError: true };
1277
+ * ```
1278
+ *
1279
+ * @see BaseConfigurationInterface
1280
+ * @since 2.0.0
1281
+ */
1282
+ interface TypeCheckOptionsInterface {
1283
+ /**
1284
+ * Whether a type error stops the build rather than only being reported.
1285
+ *
1286
+ * @remarks
1287
+ * Left off, a build carries on and emits despite the errors, which suits a watch cycle where the report is enough.
1288
+ *
1289
+ * @example
1290
+ * ```ts
1291
+ * { failOnError: true } // a type error fails the run
1292
+ * ```
1293
+ *
1294
+ * @since 2.0.0
1295
+ */
1296
+ failOnError?: boolean;
1297
+ }
1298
+ /**
1299
+ * The settings a build understands, shared by the common block and every variant.
1300
+ *
1301
+ * @remarks
1302
+ * Every field is optional here, so a variant states only what it changes and inherits the rest from `common`.
1303
+ * The esbuild options it carries are stripped of the ones this package owns, since those are assembled from the
1304
+ * fields beside them rather than passed through.
1305
+ *
1306
+ * @example
1307
+ * ```ts
1308
+ * const common: BaseConfigurationInterface = {
1309
+ * types: true,
1310
+ * declaration: { outDir: 'types' },
1311
+ * esbuild: { minify: true, target: 'esnext' }
1312
+ * };
1313
+ * ```
1314
+ *
1315
+ * @see VariantConfigurationInterface
1316
+ * @since 3.0.0
1317
+ */
1318
+ interface BaseConfigurationInterface {
1319
+ /**
1320
+ * Whether the build type-checks and how strictly.
1321
+ *
1322
+ * @remarks
1323
+ * `true` checks and reports. The object form also decides whether an error stops the build.
1324
+ *
1325
+ * @example
1326
+ * ```ts
1327
+ * { types: true } // check and report
1328
+ * { types: { failOnError: true } } // check and fail on an error
1329
+ * ```
1330
+ *
1331
+ * @see TypeCheckOptionsInterface
1332
+ * @since 2.0.0
1333
+ */
1334
+ types?: boolean | TypeCheckOptionsInterface;
1335
+ /**
1336
+ * The hooks this configuration attaches to a build.
1337
+ *
1338
+ * @remarks
1339
+ * One set per configuration, merged hook by hook with whatever `common` supplied,
1340
+ * so a variant naming a hook replaces that hook alone and leaves the rest of the shared set standing.
1341
+ * Where a build wants several named sets instead, `plugins` takes a list of them.
1342
+ * {@link LifecycleHooksInterface} documents what each hook receives and when it runs.
1343
+ *
1344
+ * @example
1345
+ * ```ts
1346
+ * { lifecycle: { onEnd: ({ duration }) => report(duration) } }
1347
+ * ```
1348
+ *
1349
+ * @see LifecycleHooksInterface
1350
+ * @since 3.0.0
1351
+ */
1352
+ lifecycle?: LifecycleHooksInterface;
1353
+ /**
1354
+ * The plugins this configuration attaches to a build.
1355
+ *
1356
+ * @remarks
1357
+ * Each is a named set of the same hooks that `lifecycle` takes, and the list applies in the order written.
1358
+ * A variant appends to the list `common` supplied rather than replacing it,
1359
+ * so a shared plugin runs ahead of the one a variant adds for itself.
1360
+ *
1361
+ * @example
1362
+ * ```ts
1363
+ * { plugins: [ timing, copyAssets ] } // timing first, then copyAssets
1364
+ * ```
1365
+ *
1366
+ * @see LifecyclePluginInterface
1367
+ * @since 3.0.0
1368
+ */
1369
+ plugins?: Array<LifecyclePluginInterface>;
1370
+ /**
1371
+ * Values substituted into the source wherever their name appears.
1372
+ *
1373
+ * @remarks
1374
+ * A plain value is substituted as written, while a function is called at build time and its result substituted
1375
+ * instead, so a substituted value can follow a flag.
1376
+ *
1377
+ * @example
1378
+ * ```ts
1379
+ * { define: { __VERSION: '1.0.0', __DEV: (name, args) => args.watch === true } }
1380
+ * ```
1381
+ *
1382
+ * @see RuntimeHandlerType
1383
+ * @since 3.0.0
1384
+ */
1385
+ define?: Record<string, PrimitiveOrObjectType | RuntimeHandlerType>;
1386
+ /**
1387
+ * Code placed at the top of each output file, keyed by the format it belongs to.
1388
+ *
1389
+ * @example
1390
+ * ```ts
1391
+ * { banner: { js: '#!/usr/bin/env node' } }
1392
+ * ```
1393
+ *
1394
+ * @see InjectableCodeType
1395
+ * @since 2.0.0
1396
+ */
1397
+ banner?: Record<string, InjectableCodeType>;
1398
+ /**
1399
+ * Code placed at the bottom of each output file, keyed by the format it belongs to.
1400
+ *
1401
+ * @example
1402
+ * ```ts
1403
+ * { footer: { js: '//# sourceMappingURL=index.js.map' } }
1404
+ * ```
1405
+ *
1406
+ * @see InjectableCodeType
1407
+ * @since 2.0.0
1408
+ */
1409
+ footer?: Record<string, InjectableCodeType>;
1410
+ /**
1411
+ * Severity to report a given esbuild message under.
1412
+ *
1413
+ * @remarks
1414
+ * Keyed by esbuild's own message name, so a warning a project has decided to live with can be silenced without
1415
+ * silencing the rest.
1416
+ * A key carrying regular-expression syntax is read as an anchored pattern instead of as a name,
1417
+ * which is how a family of messages is claimed by one entry.
1418
+ *
1419
+ * @example
1420
+ * ```ts
1421
+ * { logOverride: { 'direct-eval': 'silent' } } // this message alone
1422
+ * { logOverride: { 'TS-2\\d{3}': 'warning' } } // every TypeScript diagnostic in the 2000 range
1423
+ * ```
1424
+ *
1425
+ * @see LogOverridesType
1426
+ * @since 3.0.0
1427
+ */
1428
+ logOverride?: LogOverridesType;
1429
+ /**
1430
+ * Whether declaration files are emitted and how.
1431
+ *
1432
+ * @remarks
1433
+ * `true` emits them beside the code, following what the TypeScript configuration chose.
1434
+ * The object form also decides where they land.
1435
+ *
1436
+ * @example
1437
+ * ```ts
1438
+ * { declaration: true } // beside the code
1439
+ * { declaration: { outDir: 'types' } } // apart from it
1440
+ * ```
1441
+ *
1442
+ * @see DeclarationOptionsInterface
1443
+ * @since 2.0.0
1444
+ */
1445
+ declaration?: boolean | DeclarationOptionsInterface;
1446
+ /**
1447
+ * esbuild options passed through to the bundler.
1448
+ *
1449
+ * @remarks
1450
+ * Optional here, unlike on a variant, since the common block states what every variant starts from
1451
+ * rather than a build of its own.
1452
+ *
1453
+ * @example
1454
+ * ```ts
1455
+ * { esbuild: { minify: true, format: 'esm', target: 'node20' } }
1456
+ * ```
1457
+ *
1458
+ * @see EsbuildOptionsType
1459
+ * @since 3.0.0
1460
+ */
1461
+ esbuild?: EsbuildOptionsType;
1462
+ }
1463
+ /**
1464
+ * One named build, with everything it does not state inherited from the common block.
1465
+ *
1466
+ * @remarks
1467
+ * The same settings as {@link BaseConfigurationInterface}, except that `esbuild` is required,
1468
+ * since a variant exists to produce an output and needs at least the options describing it.
1469
+ *
1470
+ * @example
1471
+ * ```ts
1472
+ * const esm: VariantConfigurationInterface = {
1473
+ * esbuild: { format: 'esm', outdir: 'dist/esm' }
1474
+ * };
1475
+ * ```
1476
+ *
1477
+ * @see BaseConfigurationInterface
1478
+ * @since 3.0.0
1479
+ */
1480
+ interface VariantConfigurationInterface extends BaseConfigurationInterface {
1481
+ /**
1482
+ * Variants that must finish before this one starts.
1483
+ *
1484
+ * @remarks
1485
+ * Names another variant, or several, so a build that consumes the output of an earlier one runs after it rather
1486
+ * than beside it.
1487
+ *
1488
+ * @example
1489
+ * ```ts
1490
+ * { dependOn: 'types', esbuild: { outdir: 'dist' } }
1491
+ * ```
1492
+ *
1493
+ * @since 2.0.0
1494
+ */
1495
+ dependOn?: string | Array<string>;
1496
+ /**
1497
+ * esbuild options this variant builds under.
1498
+ *
1499
+ * @remarks
1500
+ * Required rather than optional, unlike on the common block, and merged over whatever `common` supplied.
1501
+ *
1502
+ * @example
1503
+ * ```ts
1504
+ * { esbuild: { format: 'cjs', outdir: 'dist/cjs' } }
1505
+ * ```
1506
+ *
1507
+ * @see EsbuildOptionsType
1508
+ * @since 3.0.0
1509
+ */
1510
+ esbuild: EsbuildOptionsType;
1511
+ }
1512
+ /**
1513
+ * A whole xBuild configuration, as a configuration file, exports it.
1514
+ *
1515
+ * @remarks
1516
+ * `variants` is what the build runs, one output per entry, while `common` is what each of them starts from.
1517
+ * A configuration with a single variant is the ordinary case, several being for a package that ships more than one
1518
+ * module format.
1519
+ *
1520
+ * @example
1521
+ * ```ts
1522
+ * const config: ConfigurationInterface = {
1523
+ * common: { types: true, esbuild: { minify: true } },
1524
+ * variants: {
1525
+ * esm: { esbuild: { format: 'esm', outdir: 'dist/esm' } },
1526
+ * cjs: { esbuild: { format: 'cjs', outdir: 'dist/cjs' } }
1527
+ * }
1528
+ * };
1529
+ * ```
1530
+ *
1531
+ * @see ConfigurationService
1532
+ * @see VariantConfigurationInterface
1533
+ *
1534
+ * @since 3.0.0
1535
+ */
1536
+ interface ConfigurationInterface {
1537
+ /**
1538
+ * Settings every variant inherits.
1539
+ *
1540
+ * @remarks
1541
+ * Merged under each variant, so a variant naming the same setting wins and one that stays quiet takes this.
1542
+ *
1543
+ * @example
1544
+ * ```ts
1545
+ * { common: { types: true, esbuild: { minify: true } } }
1546
+ * ```
1547
+ *
1548
+ * @see BaseConfigurationInterface
1549
+ * @since 2.0.0
1550
+ */
1551
+ common?: BaseConfigurationInterface;
1552
+ /**
1553
+ * The builds to run, keyed by the name each is known by.
1554
+ *
1555
+ * @remarks
1556
+ * The key names the variant in logs, in `dependOn`, and on the `--build` flag that selects one.
1557
+ *
1558
+ * @example
1559
+ * ```ts
1560
+ * { variants: { esm: { esbuild: { format: 'esm' } } } }
1561
+ * ```
1562
+ *
1563
+ * @see VariantConfigurationInterface
1564
+ * @since 3.0.0
1565
+ */
1566
+ variants: Record<string, VariantConfigurationInterface>;
1567
+ }
1568
+ /**
1569
+ * A configuration with every top-level field optional.
1570
+ *
1571
+ * @remarks
1572
+ * What a partly filled configuration is typed as, the built-in defaults among them,
1573
+ * since those describe `common` alone and name no variants at all.
1574
+ *
1575
+ * @example
1576
+ * ```ts
1577
+ * const defaults: PartialConfigurationType = { common: { types: true } };
1578
+ * ```
1579
+ *
1580
+ * @see ConfigurationInterface
1581
+ * @since 3.0.0
1582
+ */
1583
+ type PartialConfigurationType = Partial<ConfigurationInterface>;
1584
+ /**
1585
+ * Turns what a run reports into what a terminal shows.
1586
+ *
1587
+ * @remarks
1588
+ * Every event of a run arrives here: a build starting and ending, a server answering, a check reporting.
1589
+ * Each one becomes a printed line, the groups of messages under it, and a word on the status line,
1590
+ * so the scrollback carries the whole run while the bar carries only what is happening now.
1591
+ * A singleton, since a run has one terminal and the level it reports at is read from every corner of it.
1592
+ *
1593
+ * @example
1594
+ * ```ts
1595
+ * const screen = inject(Screen, () => build.build());
1596
+ * build.subscribe(screen.buildEvent.bind(screen));
1597
+ *
1598
+ * screen.toggleVerbose(); // 'verbose' - and the bar says so
1599
+ * ```
1600
+ *
1601
+ * @see LifecycleEventsType
1602
+ * @since 3.0.0
1603
+ */
1604
+ declare class Screen {
1605
+ private readonly build;
1606
+ /**
1607
+ * The configuration service the reporting level is read and written through.
1608
+ *
1609
+ * @remarks
1610
+ * The injected instance rather than one of its own,
1611
+ * so a level a key changes here is the level every other reader of the configuration sees.
1612
+ *
1613
+ * @example
1614
+ * ```ts
1615
+ * screen.config$.getValue().logLevel; // 'info'
1616
+ * ```
1617
+ *
1618
+ * @see ConfigurationService
1619
+ * @since 3.0.0
1620
+ */
1621
+ readonly config$: ConfigurationService<Required<import("../providers/interfaces/config-file-provider.interface").xBuildConfigInterface>>;
1622
+ /**
1623
+ * The address a running server answers on, absent while none is running.
1624
+ *
1625
+ * @remarks
1626
+ * Written as the server reports its start and cleared as it stops,
1627
+ * so the status line offers a URL only while there is one to open.
1628
+ *
1629
+ * @since 3.0.0
1630
+ */
1631
+ private serverUrl?;
1632
+ /**
1633
+ * The level to go back to once reporting is turned down again.
1634
+ *
1635
+ * @remarks
1636
+ * Held so that turning `verbose` off restores the level the run was started at rather than a default,
1637
+ * which is what makes the toggle reversible for a run started at `error`.
1638
+ *
1639
+ * @since 3.0.0
1640
+ */
1641
+ private restoreLevel;
1642
+ /**
1643
+ * Takes the build a key or a watch asks for, and settles the level to fall back to.
1644
+ *
1645
+ * @param build - What to run when a rebuild is asked for
1646
+ *
1647
+ * @remarks
1648
+ * The build arrives as a callback rather than as a service,
1649
+ * so the screen starts a run without knowing what a run is made of.
1650
+ * A run already started at `verbose` has no quieter level to remember, so `info` stands in as the one to return to.
1651
+ *
1652
+ * @example
1653
+ * ```ts
1654
+ * const screen = inject(Screen, runBuild); // runBuild is what a key or a watch will call
1655
+ * ```
1656
+ *
1657
+ * @since 3.0.0
1658
+ */
1659
+ constructor(build: () => Promise<void>);
1660
+ /**
1661
+ * Sets the level the run reports at.
1662
+ *
1663
+ * @param value - Level to report at from now on
1664
+ *
1665
+ * @remarks
1666
+ * Written through the configuration rather than held here,
1667
+ * so a variant reading the level for its own messages and the screen reading it for its groups agree.
1668
+ *
1669
+ * @example
1670
+ * ```ts
1671
+ * screen.logLevel = 'warning'; // info and verbose stop printing
1672
+ * ```
1673
+ *
1674
+ * @see LogLevelType
1675
+ * @since 3.0.0
1676
+ */
1677
+ set logLevel(value: LogLevelType);
1678
+ /**
1679
+ * The level the run is reporting at.
1680
+ *
1681
+ * @returns The configured level, `info` where the configuration names none
1682
+ *
1683
+ * @example
1684
+ * ```ts
1685
+ * screen.logLevel; // 'info'
1686
+ * ```
1687
+ *
1688
+ * @see LogLevelType
1689
+ * @since 3.0.0
1690
+ */
1691
+ get logLevel(): LogLevelType;
1692
+ /**
1693
+ * The address the running server answers on.
1694
+ *
1695
+ * @returns The URL, empty while no server is running
1696
+ *
1697
+ * @remarks
1698
+ * Empty rather than absent, so a caller writing it into a line needs no guard of its own.
1699
+ *
1700
+ * @example
1701
+ * ```ts
1702
+ * screen.url; // 'http://localhost:3000'
1703
+ * ```
1704
+ *
1705
+ * @since 3.0.0
1706
+ */
1707
+ get url(): string;
1708
+ /**
1709
+ * Records the address a server has begun answering on.
1710
+ *
1711
+ * @param value - URL the server bound to
1712
+ *
1713
+ * @example
1714
+ * ```ts
1715
+ * screen.url = 'http://localhost:3000';
1716
+ * ```
1717
+ *
1718
+ * @since 3.0.0
1719
+ */
1720
+ set url(value: string);
1721
+ /**
1722
+ * Reports either end of a build: its start or its finish.
1723
+ *
1724
+ * @param event - What the variant reported, carrying its context and, at the end, its result
1725
+ *
1726
+ * @remarks
1727
+ * A start says which variant is building and no more, since nothing has been found out yet.
1728
+ * An end prints the messages first and the outcome last,
1729
+ * so a reader scrolling up meets the verdict before its reasons.
1730
+ * A build that wrote no output is the failing case, whether it threw or only reported errors,
1731
+ * and it sets the exit code, which is what lets a pipeline read the run without reading its output.
1732
+ * Reporting at `verbose` lists every output rather than the largest few.
1733
+ *
1734
+ * @example
1735
+ * ```ts
1736
+ * build.subscribe(screen.buildEvent.bind(screen));
1737
+ * // [xBuild] → build esm
1738
+ * // [xBuild] ✓ esm in 128 ms
1739
+ * ```
1740
+ *
1741
+ * @see LifecycleEventsType
1742
+ * @since 3.0.0
1743
+ */
1744
+ buildEvent(event: LifecycleEventsType): void;
1745
+ /**
1746
+ * Reports what the development server is doing.
1747
+ *
1748
+ * @param event - What the server reported: its start, its stop, a request, or a failure
1749
+ *
1750
+ * @remarks
1751
+ * A start is where the address comes from, and a stop is what takes it away again,
1752
+ * so the status line offers the URL for exactly as long as something answers on it.
1753
+ * A stop is reported only where a server was running, since a stop is worth a line only where something was answering.
1754
+ * Requests are reported only at `verbose`, one line being worth little against a page that fetches thirty files.
1755
+ * A failed `favicon.ico` is dropped whatever the level, since browsers ask for one unprompted on every visit.
1756
+ *
1757
+ * @example
1758
+ * ```ts
1759
+ * server.subscribe(screen.serverEvent.bind(screen));
1760
+ * // [xBuild] → serve http://localhost:3000
1761
+ * ```
1762
+ *
1763
+ * @see ServerEventsType
1764
+ * @since 3.0.0
1765
+ */
1766
+ serverEvent(event: ServerEventsType): void;
1767
+ /**
1768
+ * Reports a type check and ends the process on what it found.
1769
+ *
1770
+ * @param diagnostics - Messages each variant's check reported, keyed by the variant's name
1771
+ *
1772
+ * @remarks
1773
+ * Every variant gets a heading carrying what it found, followed by its groups,
1774
+ * so a clean variant is still reported rather than left out of a run that named it.
1775
+ * The count is of everything the check reported rather than of what the level prints,
1776
+ * which is what keeps a quiet run from reading as a clean one.
1777
+ * The process leaves from here, and an error anywhere leaves with `1`,
1778
+ * since a check is the whole of what a run asking for one wanted.
1779
+ *
1780
+ * @example
1781
+ * ```ts
1782
+ * screen.diagnostics(await build.typeChack());
1783
+ * // [xBuild] → type-check esm 2 to look at
1784
+ * ```
1785
+ *
1786
+ * @see LifecycleLogsType
1787
+ * @since 3.0.0
1788
+ */
1789
+ diagnostics(diagnostics: Record<string, LifecycleLogsType>): void;
1790
+ /**
1791
+ * Clears what the last build left, takes up any configuration change, says what asked for this build, and runs it.
1792
+ *
1793
+ * @param reason - What asked for the build, such as the files that changed or the key that was pressed
1794
+ * @param force - Whether every TypeScript project reparses its configuration even where its file has not moved
1795
+ *
1796
+ * @remarks
1797
+ * Every rebuild of a watch goes through here, so the screen is cleared and the run announced the same way
1798
+ * whichever asked for it.
1799
+ * The build itself is the one the run handed over when the screen was made.
1800
+ * The TypeScript configurations are reloaded here rather than by the watch,
1801
+ * so a rebuild started by a key reads them as freshly as one started by a changed file.
1802
+ * A configuration that has stayed put costs a lookup and nothing more.
1803
+ * Forcing reparses every project regardless, which is what the reload key asks for
1804
+ * and what catches a change the configuration file's own version misses.
1805
+ *
1806
+ * @example
1807
+ * ```ts
1808
+ * await screen.rebuild('2 files changed'); // [xBuild] rebuild 2 files changed
1809
+ * await screen.rebuild('reloading', true); // the same, with every tsconfig reparsed first
1810
+ * ```
1811
+ *
1812
+ * @see TypescriptService.reload
1813
+ * @since 3.0.0
1814
+ */
1815
+ rebuild(reason: string, force?: boolean): Promise<void>;
1816
+ /**
1817
+ * Turns reporting all the way up, or back to what it was before it was turned up.
1818
+ *
1819
+ * @returns The level the run now reports at
1820
+ *
1821
+ * @remarks
1822
+ * The level the run was set to is remembered rather than assumed,
1823
+ * so a run started at `error` goes back to `error` rather than to the default.
1824
+ * The level is written back through the configuration, so everything reading it follows in the same breath.
1825
+ *
1826
+ * @example
1827
+ * ```ts
1828
+ * screen.toggleVerbose(); // 'verbose'
1829
+ * screen.toggleVerbose(); // 'info' - what it was before
1830
+ * ```
1831
+ *
1832
+ * @since 3.0.0
1833
+ */
1834
+ toggleVerbose(): LogLevelType;
1835
+ /**
1836
+ * Writes a line to the scrollback and says the same thing on the status line.
1837
+ *
1838
+ * @param activity - What is happening, as the bar says it
1839
+ * @param line - The line printed to the scrollback
1840
+ *
1841
+ * @remarks
1842
+ * The two are worded apart rather than shared, since the bar carries no prefix and has one row to say it in,
1843
+ * while the printed line stands on its own long after the run has moved past it.
1844
+ *
1845
+ * @see setActivity
1846
+ * @since 3.0.0
1847
+ */
1848
+ private say;
1849
+ /**
1850
+ * Prints the message groups the current level allows.
1851
+ *
1852
+ * @param logs - Messages to print, filed under the level each was reported at
1853
+ *
1854
+ * @remarks
1855
+ * The groups run loudest first, so what failed a build is read before what merely remarked on it.
1856
+ * Each group is compared against the level the run is set to,
1857
+ * which is what leaves a quiet run its errors and drops everything under them.
1858
+ * An error always carries its code window and its trace, since that is what an error is read for,
1859
+ * while the quieter groups carry theirs only at `verbose`.
1860
+ *
1861
+ * @see Levels
1862
+ * @see printGroup
1863
+ *
1864
+ * @since 3.0.0
1865
+ */
1866
+ private groups;
1867
+ }
1868
+ /**
1869
+ * Holds the build configuration and lets the rest of the build watch it change.
1870
+ *
1871
+ * @typeParam T - Shape of the configuration, at least a {@link ConfigurationInterface}
1872
+ *
1873
+ * @remarks
1874
+ * The configuration is not settled once and read forever: a watch reloads the file behind it, so whatever depends on
1875
+ * a setting has to be told when it moves rather than reading it once at startup.
1876
+ * That is what {@link select} is for - it reports only when the value that a caller actually asked for has changed,
1877
+ * so a change elsewhere in the configuration wakes nobody.
1878
+ * Updates merge rather than replace, so an update says what changes and leaves the rest standing.
1879
+ * Registered as a singleton, so every consumer reads and watches the same configuration.
1880
+ *
1881
+ * @example
1882
+ * ```ts
1883
+ * const configuration = inject(ConfigurationService);
1884
+ *
1885
+ * configuration.getValue(config => config.logLevel); // info
1886
+ * configuration.select(config => config.variants)
1887
+ * .subscribe(variants => rebuild(variants)); // told whenever the variants change
1888
+ * configuration.patch({ verbose: true }); // the variant's watcher hears nothing
1889
+ * ```
1890
+ *
1891
+ * @see xBuildConfigInterface
1892
+ * @see ConfigurationInterface
1893
+ *
1894
+ * @since 2.0.0
1895
+ */
1896
+ declare class ConfigurationService<T extends ConfigurationInterface = Required<xBuildConfigInterface>> {
1897
+ private initialConfig;
1898
+ /**
1899
+ * The configuration and everything watching it.
1900
+ *
1901
+ * @remarks
1902
+ * A behavior subject rather than a plain one, so a subscriber arriving late is handed the configuration as it
1903
+ * stands instead of waiting for the next change.
1904
+ *
1905
+ * @since 2.0.0
1906
+ */
1907
+ private readonly config$;
1908
+ /**
1909
+ * Creates the service around a starting configuration.
1910
+ *
1911
+ * @param initialConfig - Configuration to start from the built-in defaults when omitted
1912
+ *
1913
+ * @remarks
1914
+ * The configuration is copied on the way in, so the object handed over is never written to - which is what makes
1915
+ * the frozen defaults usable as a starting point.
1916
+ * It is also kept as it was passed, since {@link reload} needs something to return to.
1917
+ *
1918
+ * @example
1919
+ * ```ts
1920
+ * const configuration = new ConfigurationService({ variants: { esm: { esbuild: { format: 'esm' } } } });
1921
+ * configuration.getValue().variants.esm; // { esbuild: { format: 'esm' } }
1922
+ * ```
1923
+ *
1924
+ * @see DefaultsCommonConfig
1925
+ * @since 2.0.0
1926
+ */
1927
+ constructor(initialConfig?: T);
1928
+ /**
1929
+ * Reads the whole configuration as it stands.
1930
+ *
1931
+ * @returns The current configuration
1932
+ *
1933
+ * @example
1934
+ * ```ts
1935
+ * configuration.getValue().verbose; // false
1936
+ * ```
1937
+ *
1938
+ * @since 2.0.0
1939
+ */
1940
+ getValue(): T;
1941
+ /**
1942
+ * Reads one value out of the configuration as it stands.
1943
+ *
1944
+ * @typeParam R - What the selector returns
1945
+ * @param selector - Picks the value to read
1946
+ * @returns Whatever the selector returned
1947
+ *
1948
+ * @remarks
1949
+ * The one-off counterpart of {@link select}: it answers once and never again, which suits a decision taken at a
1950
+ * point in time rather than something that has to follow the configuration.
1951
+ *
1952
+ * @example
1953
+ * ```ts
1954
+ * configuration.getValue(config => Object.keys(config.variants)); // [ 'esm', 'cjs' ]
1955
+ * ```
1956
+ *
1957
+ * @since 2.0.0
1958
+ */
1959
+ getValue<R>(selector: (config: T) => R): R;
1960
+ /**
1961
+ * Watches the whole configuration.
1962
+ *
1963
+ * @param observer - Called with the configuration, now and on every change
1964
+ * @returns A function that stops the watching
1965
+ *
1966
+ * @remarks
1967
+ * Called straight away with the configuration as it stands, so a subscriber needs no separate first read.
1968
+ * It hears every change, whatever moved, which is why {@link select} is the better choice for anything that cares
1969
+ * about one corner of the configuration.
1970
+ *
1971
+ * @example
1972
+ * ```ts
1973
+ * const stop = configuration.subscribe(config => console.log(config.verbose)); // logs at once
1974
+ * configuration.patch({ verbose: true }); // logs again
1975
+ * stop();
1976
+ * ```
1977
+ *
1978
+ * @see select
1979
+ * @since 1.0.0
1980
+ */
1981
+ subscribe(observer: (value: T) => void): UnsubscribeType;
1982
+ /**
1983
+ * Watches one value in the configuration.
1984
+ *
1985
+ * @typeParam R - What the selector returns
1986
+ * @param selector - Picks the value to watch
1987
+ * @returns A stream of that value, reporting only when it has actually changed
1988
+ *
1989
+ * @remarks
1990
+ * The selector runs on every change, but its result is compared against the one before and only a real difference
1991
+ * is passed on - so a change elsewhere costs a comparison rather than the work behind a subscriber.
1992
+ * The comparison is structural, so a selector that builds an equal object each time still reports nothing.
1993
+ *
1994
+ * @example
1995
+ * ```ts
1996
+ * configuration.select(config => config.common?.esbuild?.minify)
1997
+ * .subscribe(minify => console.log(minify)); // true, then again only when it changes
1998
+ *
1999
+ * configuration.patch({ verbose: true }); // nothing reported - minify did not move
2000
+ * ```
2001
+ *
2002
+ * @see equals
2003
+ * @see subscribe
2004
+ *
2005
+ * @since 2.0.0
2006
+ */
2007
+ select<R>(selector: (config: T) => R): Observable<R>;
2008
+ /**
2009
+ * Merges changes into the configuration and reports them.
2010
+ *
2011
+ * @param partial - The parts to change, nested as deeply as needed
2012
+ *
2013
+ * @remarks
2014
+ * Merged over what is there now, so anything left out keeps its value and only the corners named are touched.
2015
+ * Arrays are concatenated rather than replaced, so patching a list adds to it - which is a reason to reach for
2016
+ * {@link reload} when a list has to be replaced rather than extended.
2017
+ * Every subscriber is told, while a {@link select} passes it on only if the value it picked actually moved.
2018
+ *
2019
+ * @example
2020
+ * ```ts
2021
+ * configuration.patch({ common: { esbuild: { minify: false } } });
2022
+ * configuration.getValue().common?.esbuild?.format; // 'cjs' - untouched
2023
+ * ```
2024
+ *
2025
+ * @see reload
2026
+ * @since 1.0.0
2027
+ */
2028
+ patch(partial: DeepPartialType<T>): void;
2029
+ /**
2030
+ * Starts again from the initial configuration, with the given one merged over it.
2031
+ *
2032
+ * @param config - Configuration to apply over the initial one
2033
+ *
2034
+ * @remarks
2035
+ * Not a replacement: the result is the configuration this service was constructed with,
2036
+ * merged with what is passed here.
2037
+ * What the initial configuration carried therefore survives, and only what accumulated since is dropped.
2038
+ * That is what re-reading an edited file wants, since a patch has no way to take something back.
2039
+ * To be rid of the initial configuration too, construct another service.
2040
+ *
2041
+ * @example
2042
+ * ```ts
2043
+ * configuration.patch({ verbose: true });
2044
+ * configuration.reload({ common: { types: false } });
2045
+ * configuration.getValue().verbose; // false again - the patch is gone
2046
+ * ```
2047
+ *
2048
+ * @see patch
2049
+ * @since 2.0.0
2050
+ */
2051
+ reload(config: DeepPartialType<T>): void;
2052
+ }
2053
+ /**
2054
+ * The shape a configuration file exports.
2055
+ *
2056
+ * @remarks
2057
+ * Every field of a whole configuration, each one optional,
2058
+ * so a file may state one setting and leave the rest to the defaults.
2059
+ * The four fields beside them are the ones only a file carries:
2060
+ * the reporting level, the command line options it declares, the server it asks for, and the watcher it tunes.
2061
+ *
2062
+ * @example
2063
+ * ```ts
2064
+ * const config: xBuildConfigInterface = {
2065
+ * common: { types: true },
2066
+ * watch: { debounce: 50 },
2067
+ * userArgv: { release: { type: 'boolean' } }
2068
+ * };
2069
+ * ```
2070
+ *
2071
+ * @see configFileProvider
2072
+ * @see PartialConfigurationType
2073
+ *
2074
+ * @since 3.0.0
2075
+ */
2076
+ interface xBuildConfigInterface extends PartialConfigurationType {
2077
+ /**
2078
+ * The reporting level for the whole run.
2079
+ *
2080
+ * @remarks
2081
+ * It sits on the file itself rather than inside `common` or a variant,
2082
+ * so one level covers every variant the file declares.
2083
+ * The esbuild options a file passes through do not accept a `logLevel`, which is why the setting lives here.
2084
+ * `silent` drops a message rather than filing it under a bucket.
2085
+ *
2086
+ * @example
2087
+ * ```ts
2088
+ * { logLevel: 'warning' } // warnings and errors alone
2089
+ * ```
2090
+ *
2091
+ * @see LogLevelType
2092
+ * @since 3.0.0
2093
+ */
2094
+ logLevel?: LogLevelType;
2095
+ /**
2096
+ * The command line options this configuration declares.
2097
+ *
2098
+ * @remarks
2099
+ * Each entry is a yargs option keyed by the flag it defines,
2100
+ * so a project can take a flag of its own and read the parsed value back through the `argv` of a lifecycle hook.
2101
+ *
2102
+ * @example
2103
+ * ```ts
2104
+ * { userArgv: { release: { type: 'boolean', describe: 'build for release' } } }
2105
+ * ```
2106
+ *
2107
+ * @see LifecycleContextInterface
2108
+ * @since 2.0.0
2109
+ */
2110
+ userArgv?: Record<string, Options>;
2111
+ /**
2112
+ * The static server this configuration asks for.
2113
+ *
2114
+ * @remarks
2115
+ * `dir` names the directory served, and it is required rather than inferred from the build output.
2116
+ * `start` asks for the server to come up with the build rather than wait to be started.
2117
+ *
2118
+ * @example
2119
+ * ```ts
2120
+ * { serve: { dir: 'dist', start: true } }
2121
+ * ```
2122
+ *
2123
+ * @since 2.0.0
2124
+ */
2125
+ serve?: ServerConfigurationInterface & {
2126
+ dir: string;
2127
+ start?: boolean;
2128
+ };
2129
+ /**
2130
+ * The watcher settings configuration tunes.
2131
+ *
2132
+ * @remarks
2133
+ * Every setting of the watcher is optional, so a file names only what it changes - the debounce window, the
2134
+ * recursion, the dotfiles, or the filters - and whatever it leaves out keeps its default.
2135
+ * A `filter` named here joins the two globs {@link configFileProvider} supplies rather than replacing them.
2136
+ *
2137
+ * @example
2138
+ * ```ts
2139
+ * { watch: { debounce: 50, recursive: true } }
2140
+ * ```
2141
+ *
2142
+ * @see configFileProvider
2143
+ * @see WatchOptionsInterface
2144
+ *
2145
+ * @since 3.0.0
2146
+ */
2147
+ watch?: WatchOptionsInterface;
2148
+ }
2149
+ /**
2150
+ * The kind of change carried by a watch event.
2151
+ *
2152
+ * @remarks
2153
+ * The union of the numeric codes exposed by {@link ChangeTypes}.
2154
+ *
2155
+ * @example
2156
+ * ```ts
2157
+ * const type: ChangeType = ChangeTypes.Added; // 0
2158
+ * ```
2159
+ *
2160
+ * @see ChangeTypes
2161
+ * @since 3.0.0
2162
+ */
2163
+ type ChangeType = typeof ChangeTypes[keyof typeof ChangeTypes];
2164
+ /**
2165
+ * A single entry describing what happened to one watched path.
2166
+ *
2167
+ * @remarks
2168
+ * Used as the value side of {@link WatchEventType}, keyed by the path relative to the watched base.
2169
+ *
2170
+ * @example
2171
+ * ```ts
2172
+ * const change: WatchChangeInterface = { type: ChangeTypes.Change, stats };
2173
+ * ```
2174
+ *
2175
+ * @see ChangeType
2176
+ * @since 3.0.0
2177
+ */
2178
+ interface WatchChangeInterface {
2179
+ /**
2180
+ * The kind of change that occurred.
2181
+ *
2182
+ * @example
2183
+ * ```ts
2184
+ * if (change.type === ChangeTypes.Deleted) forget(path);
2185
+ * ```
2186
+ *
2187
+ * @see ChangeType
2188
+ * @since 3.0.0
2189
+ */
2190
+ type: ChangeType;
2191
+ /**
2192
+ * The followed `stat` result for the path at the time of the event.
2193
+ *
2194
+ * @remarks
2195
+ * Reflects the symlink target rather than the link itself.
2196
+ * Absent for a deleted entry, whose path no longer resolves.
2197
+ *
2198
+ * @example
2199
+ * ```ts
2200
+ * change.stats?.mtimeMs; // 1754000000000
2201
+ * change.stats; // undefined - the path was deleted
2202
+ * ```
2203
+ *
2204
+ * @since 3.0.0
2205
+ */
2206
+ stats?: Stats;
2207
+ }
2208
+ /**
2209
+ * A batch of path changes accumulated within one debounce window.
2210
+ *
2211
+ * @remarks
2212
+ * Keys are paths relative to the watched base, and each value describes the change on that path.
2213
+ * One object is emitted per flush, coalescing every event seen since the previous emission.
2214
+ *
2215
+ * @example
2216
+ * ```ts
2217
+ * watcher.subscribe((batch: WatchEventType) => {
2218
+ * Object.keys(batch); // [ 'src/index.ts', 'src/app.ts' ]
2219
+ * });
2220
+ * ```
2221
+ *
2222
+ * @see WatchChangeInterface
2223
+ * @since 3.0.0
2224
+ */
2225
+ type WatchEventType = Record<string, WatchChangeInterface>;
2226
+ /**
2227
+ * The subscriber form accepted when observing the watch stream.
2228
+ *
2229
+ * @remarks
2230
+ * Either a full {@link ObserverInterface} carrying `next`, `error`, and `complete`,
2231
+ * or a bare `next` callback that receives each emitted {@link WatchEventType} batch.
2232
+ * A callback form leaves `error` and `complete` to be supplied as separate arguments.
2233
+ *
2234
+ * @example
2235
+ * ```ts
2236
+ * watcher.subscribe((batch) => rebuild(batch)); // the callback form
2237
+ * watcher.subscribe({ next: rebuild, error: report }); // the observer form
2238
+ * ```
2239
+ *
2240
+ * @see WatchEventType
2241
+ * @since 3.0.0
2242
+ */
2243
+ type ObserverType = ObserverInterface<WatchEventType> | NextType<WatchEventType>;
2244
+ /**
2245
+ * Options controlling which paths a watcher tracks and how it reports them.
2246
+ *
2247
+ * @remarks
2248
+ * Every field is optional, so an omitted object watches the base itself,
2249
+ * emits every non-dot path it sees, and coalesces those events over 150 milliseconds.
2250
+ *
2251
+ * @example
2252
+ * ```ts
2253
+ * new WatchService('src', { recursive: true, filter: [ '**\/*.ts' ], debounce: 100 });
2254
+ * ```
2255
+ *
2256
+ * @see WatchService
2257
+ * @since 3.0.0
2258
+ */
2259
+ interface WatchOptionsInterface {
2260
+ /**
2261
+ * Whether to include dotfiles and dot-directories.
2262
+ *
2263
+ * @remarks
2264
+ * When `false` or omitted, any path with a segment beginning with `.` is skipped and the filter hides dotfiles.
2265
+ * When `true`, dot paths are watched and eligible to match the filter.
2266
+ *
2267
+ * @example
2268
+ * ```ts
2269
+ * new WatchService('.', { dot: true }); // reports changes under .github
2270
+ * ```
2271
+ *
2272
+ * @since 3.0.0
2273
+ */
2274
+ dot?: boolean;
2275
+ /**
2276
+ * Glob patterns selecting which paths emit change events.
2277
+ *
2278
+ * @remarks
2279
+ * A leading `!` marks an exclusion.
2280
+ * A path passes when it matches an include and no exclusion.
2281
+ * An empty or omitted list matches every path.
2282
+ *
2283
+ * @example
2284
+ * ```ts
2285
+ * new WatchService('src', { filter: [ '**\/*.ts', '!**\/*.spec.ts' ] });
2286
+ * ```
2287
+ *
2288
+ * @see createMatcher
2289
+ * @since 3.0.0
2290
+ */
2291
+ filter?: Array<string>;
2292
+ /**
2293
+ * Milliseconds to coalesce events before emitting a batch.
2294
+ *
2295
+ * @remarks
2296
+ * Each event restarts the window, so a burst of rapid changes yields a single {@link WatchEventType} emission.
2297
+ * Defaults to 150 when omitted.
2298
+ *
2299
+ * @example
2300
+ * ```ts
2301
+ * new WatchService('src', { debounce: 0 }); // emit as soon as the event loop allows
2302
+ * ```
2303
+ *
2304
+ * @since 3.0.0
2305
+ */
2306
+ debounce?: number;
2307
+ /**
2308
+ * Whether to watch nested directories as well as the base.
2309
+ *
2310
+ * @example
2311
+ * ```ts
2312
+ * new WatchService('src', { recursive: true }); // src/models/files.model.ts reports too
2313
+ * ```
2314
+ *
2315
+ * @since 3.0.0
2316
+ */
2317
+ recursive?: boolean;
2318
+ /**
2319
+ * Whether to place additional watchers on symbolic links.
2320
+ *
2321
+ * @remarks
2322
+ * `fs.watch` does not follow links,
2323
+ * so when `true` the base is scanned once, and every symlink found is watched directly.
2324
+ * Links appearing later are picked up from their parent directory's events.
2325
+ *
2326
+ * @example
2327
+ * ```ts
2328
+ * new WatchService('src', { followSymlinks: true }); // a linked package reports its own changes
2329
+ * ```
2330
+ *
2331
+ * @since 3.0.0
2332
+ */
2333
+ followSymlinks?: boolean;
2334
+ }
2335
+ /**
2336
+ * Numeric codes for the kind of change reported for a watched path.
2337
+ *
2338
+ * @remarks
2339
+ * A `const enum`, so every reference inlines to its literal value at compile time, and no runtime object is emitted.
2340
+ * Used internally by the watcher on the event path.
2341
+ * The runtime-visible counterpart consumers import is {@link ChangeTypes}.
2342
+ *
2343
+ * @example
2344
+ * ```ts
2345
+ * if (change.type === ChangeCode.Deleted) forget(path);
2346
+ * ```
2347
+ *
2348
+ * @see ChangeTypes
2349
+ * @since 3.0.0
2350
+ */
2351
+ declare const enum ChangeCode {
2352
+ /**
2353
+ * A path seen for the first time, recognized by its `birthtime` and `mtime` being equal.
2354
+ *
2355
+ * @since 3.0.0
2356
+ */
2357
+ Added = 0,
2358
+ /**
2359
+ * A later modification to a path the watcher already knew about.
2360
+ *
2361
+ * @since 3.0.0
2362
+ */
2363
+ Change = 1,
2364
+ /**
2365
+ * A path that no longer resolves on the disk, after which its watcher is closed.
2366
+ *
2367
+ * @since 3.0.0
2368
+ */
2369
+ Deleted = 2
2370
+ }
2371
+ /**
2372
+ * Runtime map of watch change kinds, keyed by name.
2373
+ *
2374
+ * @remarks
2375
+ * Mirrors {@link ChangeCode} as a real exported object,
2376
+ * so consumers can reference the codes at runtime - to validate or label the `type` of an emitted
2377
+ * {@link WatchChangeInterface}, among other uses.
2378
+ * The companion {@link ChangeType} type narrows to the union of these codes.
2379
+ *
2380
+ * @example
2381
+ * ```ts
2382
+ * ChangeTypes.Added; // 0
2383
+ * ChangeTypes.Deleted; // 2
2384
+ * ```
2385
+ *
2386
+ * @see ChangeCode
2387
+ * @since 3.0.0
2388
+ */
2389
+ declare const ChangeTypes: {
2390
+ /**
2391
+ * A path seen for the first time.
2392
+ *
2393
+ * @see ChangeCode.Added
2394
+ * @since 3.0.0
2395
+ */
2396
+ readonly Added: ChangeCode.Added;
2397
+ /**
2398
+ * A later modification to a path already known.
2399
+ *
2400
+ * @see ChangeCode.Change
2401
+ * @since 3.0.0
2402
+ */
2403
+ readonly Change: ChangeCode.Change;
2404
+ /**
2405
+ * A path that no longer resolves on the disk.
2406
+ *
2407
+ * @see ChangeCode.Deleted
2408
+ * @since 3.0.0
2409
+ */
2410
+ readonly Deleted: ChangeCode.Deleted;
2411
+ };
2412
+ /**
2413
+ * How a server listens and what it does with requests.
2414
+ *
2415
+ * @remarks
2416
+ * Every field is optional, a server with no configuration at all listening on a system-assigned port of `localhost`
2417
+ * and serving its root directory as it stands.
2418
+ * The object is kept by the server rather than copied, and written back to: the defaults land on it when the server
2419
+ * is constructed, and the port does once it is listening.
2420
+ *
2421
+ * @example
2422
+ * ```ts
2423
+ * const config: ServerConfigurationInterface = { port: 0, verbose: true };
2424
+ * const server = new ServerModule(config, 'dist');
2425
+ *
2426
+ * await server.start();
2427
+ * config.port; // 54321 - no longer the 0 that was passed in
2428
+ * ```
2429
+ *
2430
+ * @since 2.0.0
2431
+ */
2432
+ interface ServerConfigurationInterface {
2433
+ /**
2434
+ * Port to listen on, or `0` to let the system choose one.
2435
+ *
2436
+ * @remarks
2437
+ * Defaults to `0`, which is also what an explicit `0` means: the operating system picks a free port, and it is
2438
+ * written back here once bound, so this field is how the chosen port is read afterward.
2439
+ * That is the value to leave it at when several servers run at once and a fixed port would collide.
2440
+ *
2441
+ * @example
2442
+ * ```ts
2443
+ * config.port; // 0 before starting, 54321 after
2444
+ * ```
2445
+ *
2446
+ * @since 2.0.0
2447
+ */
2448
+ port?: number;
2449
+ /**
2450
+ * Interface to bind to.
2451
+ *
2452
+ * @remarks
2453
+ * Defaults to `localhost`, which accepts only connections from the machine itself.
2454
+ * `0.0.0.0` binds every interface, which is what makes the server reachable from another device or from outside a
2455
+ * container - and worth choosing deliberately, the directory being served to whoever can reach the port.
2456
+ *
2457
+ * @example
2458
+ * ```ts
2459
+ * config.host; // 'localhost'
2460
+ * ```
2461
+ *
2462
+ * @since 2.0.0
2463
+ */
2464
+ host?: string;
2465
+ /**
2466
+ * Path of the private key to serve HTTPS with.
2467
+ *
2468
+ * @remarks
2469
+ * Read once at startup, and only when {@link https} is set.
2470
+ * Left out, the key shipped with the framework stands in.
2471
+ *
2472
+ * @example
2473
+ * ```ts
2474
+ * config.key; // './certs/server.key'
2475
+ * ```
2476
+ *
2477
+ * @see cert
2478
+ * @since 2.0.0
2479
+ */
2480
+ key?: string;
2481
+ /**
2482
+ * Path of the certificate to serve HTTPS with.
2483
+ *
2484
+ * @remarks
2485
+ * Read once at startup, and only when {@link https} is set.
2486
+ * Left out, the certificate shipped with the framework stands in - self-signed, so a browser will ask before
2487
+ * trusting it.
2488
+ *
2489
+ * @example
2490
+ * ```ts
2491
+ * config.cert; // './certs/server.crt'
2492
+ * ```
2493
+ *
2494
+ * @see key
2495
+ * @since 2.0.0
2496
+ */
2497
+ cert?: string;
2498
+ /**
2499
+ * Whether to serve over HTTPS rather than HTTP.
2500
+ *
2501
+ * @remarks
2502
+ * Decides which server is created, and so which scheme the `onStart` hook reports.
2503
+ * Neither {@link key} nor {@link cert} is required alongside it, the framework's own pair standing in.
2504
+ *
2505
+ * @example
2506
+ * ```ts
2507
+ * config.https; // true - onStart reports a https:// url
2508
+ * ```
2509
+ *
2510
+ * @since 2.0.0
2511
+ */
2512
+ https?: boolean;
2513
+ /**
2514
+ * Whether to log every request as it arrives.
2515
+ *
2516
+ * @remarks
2517
+ * Logs the requested url and nothing else, so the output stays readable while a page loads its assets.
2518
+ *
2519
+ * @example
2520
+ * ```ts
2521
+ * config.verbose; // true - '[xBuild] Request /index.js' per request
2522
+ * ```
2523
+ *
2524
+ * @since 2.0.0
2525
+ */
2526
+ verbose?: boolean;
2527
+ /**
2528
+ * Hook given every request before the server handles it.
2529
+ *
2530
+ * @param req - Request as it arrived
2531
+ * @param res - Response to write to
2532
+ * @param next - The static-file handling, to call or to skip
2533
+ *
2534
+ * @remarks
2535
+ * Calling `next` hands the request back to the server.
2536
+ * Not calling it takes the request over entirely, which is how a route or a single-page fallback is served
2537
+ * alongside the files.
2538
+ * It runs before the path is resolved, so a request that would be refused as outside the root still reaches it.
2539
+ *
2540
+ * @example
2541
+ * ```ts
2542
+ * config.onRequest = (req, res, next) => {
2543
+ * if (req.url !== '/api/health') return next();
2544
+ * res.end('ok');
2545
+ * };
2546
+ * ```
2547
+ *
2548
+ * @since 2.0.0
2549
+ */
2550
+ onRequest?: (req: IncomingMessage, res: ServerResponse, next: () => void) => void;
2551
+ /**
2552
+ * Hook called once the server is listening.
2553
+ *
2554
+ * @remarks
2555
+ * Runs from the listen callback, after the assigned port has been written back,
2556
+ * so what it is handed is what was actually bound rather than what was asked for.
2557
+ * That is how the url of a server given port `0` is learned.
2558
+ *
2559
+ * @example
2560
+ * ```ts
2561
+ * config.onStart = ({ url }) => console.log(url); // 'http://localhost:54321'
2562
+ * ```
2563
+ *
2564
+ * @since 2.0.0
2565
+ */
2566
+ onStart?: (config: ServerAddressInterface) => void;
2567
+ }
2568
+ /**
2569
+ * Where a server ended up listening.
2570
+ *
2571
+ * @remarks
2572
+ * What a port of `0` resolves to is known only once the system has answered,
2573
+ * so this is how a caller learns what was bound rather than what was asked for.
2574
+ *
2575
+ * @example
2576
+ * ```ts
2577
+ * const address: ServerAddressInterface = { host: 'localhost', port: 61355, url: 'http://localhost:61355' };
2578
+ * ```
2579
+ *
2580
+ * @since 3.0.0
2581
+ */
2582
+ interface ServerAddressInterface {
2583
+ /**
2584
+ * Host the server is listening on.
2585
+ *
2586
+ * @since 3.0.0
2587
+ */
2588
+ host: string;
2589
+ /**
2590
+ * Port it was given, which is the one the system assigned where none was asked for.
2591
+ *
2592
+ * @since 3.0.0
2593
+ */
2594
+ port: number;
2595
+ /**
2596
+ * The two above as an address, under the scheme the server was started with.
2597
+ *
2598
+ * @since 3.0.0
2599
+ */
2600
+ url: string;
2601
+ }
2602
+ /**
2603
+ * Something the server did, tagged with which of the four it is.
2604
+ *
2605
+ * @remarks
2606
+ * The server says what happened and writes none of it, so what reaches a terminal - and whether anything does -
2607
+ * is the reader's to decide rather than the server's.
2608
+ * Discriminated on `type`, so narrowing on it gives the fields of the matching event:
2609
+ *
2610
+ * - **start** - listening, carrying the address it settled on
2611
+ * - **stop** - closed, `running` telling a server that was up from one that never was
2612
+ * - **request** - a request arrived, named by what it asked for
2613
+ * - **error** - a request failed or reached nothing, carrying the failure and what was asked for
2614
+ *
2615
+ * @example
2616
+ * ```ts
2617
+ * server.subscribe(event => {
2618
+ * if (event.type === 'start') event.url; // 'http://localhost:61355'
2619
+ * });
2620
+ * ```
2621
+ *
2622
+ * @see ServerModule.subscribe
2623
+ * @since 3.0.0
2624
+ */
2625
+ type ServerEventsType = ServerAddressInterface & {
2626
+ type: 'start';
2627
+ } | {
2628
+ type: 'stop';
2629
+ running: boolean;
2630
+ } | {
2631
+ type: 'request';
2632
+ url: string;
2633
+ } | {
2634
+ type: 'error';
2635
+ error: Error;
2636
+ url?: string;
2637
+ };
2638
+ /**
2639
+ * Options a configuration file adds to the command line.
2640
+ *
2641
+ * @remarks
2642
+ * Each key becomes a flag and each value declares it the way yargs does, so a configuration reaches the same type,
2643
+ * alias, and validation handling xBuild's own options get.
2644
+ * They are registered alongside the built-in options and listed under a heading of their own in help, which is what
2645
+ * keeps a project's flags distinguishable from the tool's.
2646
+ *
2647
+ * @example
2648
+ * ```ts
2649
+ * const userExtensions: UserExtensionInterface = {
2650
+ * env: { describe: 'Build environment', type: 'string', choices: [ 'dev', 'prod' ] }
2651
+ * };
2652
+ *
2653
+ * argv.enhancedParse(process.argv, userExtensions).env; // 'prod'
2654
+ * ```
2655
+ *
2656
+ * @see ArgumentsInterface
2657
+ * @since 2.0.0
2658
+ */
2659
+ interface UserExtensionInterface {
2660
+ /**
2661
+ * Declaration of one added flag, named by its key.
2662
+ *
2663
+ * @remarks
2664
+ * A yargs `Options` object, so type, alias, default, and choices all mean what they mean there.
2665
+ *
2666
+ * @example
2667
+ * ```ts
2668
+ * userExtensions.env; // { describe: 'Build environment', type: 'string', choices: [ 'dev', 'prod' ] }
2669
+ * ```
2670
+ *
2671
+ * @since 2.0.0
2672
+ */
2673
+ [key: string]: Options;
2674
+ }
2675
+ /**
2676
+ * What every parse produces, whatever options were declared.
2677
+ *
2678
+ * @remarks
2679
+ * The two fields yargs always fills, plus an index signature for the flags a given pass happened to declare.
2680
+ * It is what the early passes return, their option set being deliberately partial, and what
2681
+ * {@link ArgumentsInterface} builds on once the whole set is known.
2682
+ *
2683
+ * @example
2684
+ * ```ts
2685
+ * // xBuild src/app.ts src/worker.ts
2686
+ * args._; // [ 'src/app.ts', 'src/worker.ts' ]
2687
+ * args.$0; // 'xBuild'
2688
+ * ```
2689
+ *
2690
+ * @see ArgumentsInterface
2691
+ * @since 2.0.0
2692
+ */
2693
+ interface BaseArgumentsInterface {
2694
+ /**
2695
+ * Values given without a flag in front of them.
2696
+ *
2697
+ * @remarks
2698
+ * Numbers as well as strings, yargs converting a value that reads as one.
2699
+ * In the full parse these are claimed by the default command and surface as `entryPoints` instead, so what
2700
+ * remains here is whatever that command did not take.
2701
+ *
2702
+ * @example
2703
+ * ```ts
2704
+ * args._; // [ 'src/app.ts' ]
2705
+ * ```
2706
+ *
2707
+ * @since 2.0.0
2708
+ */
2709
+ _: Array<string | number>;
2710
+ /**
2711
+ * Name the script was invoked as.
2712
+ *
2713
+ * @remarks
2714
+ * Filled by yargs and used in the usage line it prints.
2715
+ *
2716
+ * @example
2717
+ * ```ts
2718
+ * args.$0; // 'xBuild'
2719
+ * ```
2720
+ *
2721
+ * @since 2.0.0
2722
+ */
2723
+ $0: string;
2724
+ /**
2725
+ * Any other flag the parse declared.
2726
+ *
2727
+ * @remarks
2728
+ * Open-ended because a configuration file can add flags this package never sees, so what a result carries is
2729
+ * decided at run time rather than by this declaration.
2730
+ *
2731
+ * @example
2732
+ * ```ts
2733
+ * args['env']; // 'prod' - a flag a configuration added
2734
+ * ```
2735
+ *
2736
+ * @since 2.0.0
2737
+ */
2738
+ [argName: string]: unknown;
2739
+ }
2740
+ /**
2741
+ * The result of the full parse, with xBuild's own options named.
2742
+ *
2743
+ * @remarks
2744
+ * Every field is optional: an option that was not typed is absent rather than defaulted, defaults being applied while
2745
+ * the configuration is resolved, so this type describes what was asked for rather than what the build settles on.
2746
+ * Flags a configuration file added are reachable through the inherited index signature.
2747
+ *
2748
+ * @example
2749
+ * ```ts
2750
+ * // xBuild src/index.ts --bundle --minify --format esm
2751
+ * args.entryPoints; // [ 'src/index.ts' ]
2752
+ * args.bundle; // true
2753
+ * args.watch; // undefined - not typed, not defaulted
2754
+ * ```
2755
+ *
2756
+ * @see ArgsDefaultOptions
2757
+ * @see BaseArgumentsInterface
2758
+ *
2759
+ * @since 2.0.0
2760
+ */
2761
+ interface ArgumentsInterface extends BaseArgumentsInterface {
2762
+ /**
2763
+ * Entry points reserved for development builds.
2764
+ *
2765
+ * @remarks
2766
+ * Declared for configuration handling to read.
2767
+ * No command-line flag produces it, so it never arrives from a parse.
2768
+ *
2769
+ * @example
2770
+ * ```ts
2771
+ * args.dev; // [ 'src/dev-tools.ts' ]
2772
+ * ```
2773
+ *
2774
+ * @since 2.0.0
2775
+ */
2776
+ dev?: Array<string>;
2777
+ /**
2778
+ * Whether to type check while building.
2779
+ *
2780
+ * @remarks
2781
+ * Runs the checker alongside the build rather than instead of it, which is what separates it from
2782
+ * {@link typeCheck}.
2783
+ * Whether a reported error stops the build is {@link failOnError}'s to decide.
2784
+ *
2785
+ * @example
2786
+ * ```ts
2787
+ * args.types; // true - typed as --types or --btc
2788
+ * ```
2789
+ *
2790
+ * @since 2.0.0
2791
+ */
2792
+ types?: boolean;
2793
+ /**
2794
+ * Entry points reserved for debug builds.
2795
+ *
2796
+ * @remarks
2797
+ * Declared for configuration handling to read.
2798
+ * No command-line flag produces it, so it never arrives from a parse.
2799
+ *
2800
+ * @example
2801
+ * ```ts
2802
+ * args.debug; // [ 'src/debug-logger.ts' ]
2803
+ * ```
2804
+ *
2805
+ * @since 2.0.0
2806
+ */
2807
+ debug?: Array<string>;
2808
+ /**
2809
+ * Directory to serve the build output from.
2810
+ *
2811
+ * @remarks
2812
+ * Carries the directory rather than a flag, so serving and choosing where to serve from are the one option.
2813
+ *
2814
+ * @example
2815
+ * ```ts
2816
+ * args.serve; // 'dist'
2817
+ * ```
2818
+ *
2819
+ * @since 2.0.0
2820
+ */
2821
+ serve?: string;
2822
+ /**
2823
+ * Directory the build output is written to.
2824
+ *
2825
+ * @remarks
2826
+ * Overrides whatever the configuration set, the command line being the later word.
2827
+ *
2828
+ * @example
2829
+ * ```ts
2830
+ * args.outdir; // 'dist'
2831
+ * ```
2832
+ *
2833
+ * @since 2.0.0
2834
+ */
2835
+ outdir?: string;
2836
+ /**
2837
+ * Whether to rebuild as files change.
2838
+ *
2839
+ * @example
2840
+ * ```ts
2841
+ * args.watch; // true
2842
+ * ```
2843
+ *
2844
+ * @since 2.0.0
2845
+ */
2846
+ watch?: boolean;
2847
+ /**
2848
+ * Path of the configuration file to load.
2849
+ *
2850
+ * @remarks
2851
+ * The one option read before the others, {@link ArgsConfigPath} standing in when it is not typed, so it is always
2852
+ * present in a parsed result.
2853
+ *
2854
+ * @example
2855
+ * ```ts
2856
+ * args.config; // 'config.xbuild.ts'
2857
+ * ```
2858
+ *
2859
+ * @since 2.0.0
2860
+ */
2861
+ config?: string;
2862
+ /**
2863
+ * Whether to minify the output.
2864
+ *
2865
+ * @example
2866
+ * ```ts
2867
+ * args.minify; // true
2868
+ * ```
2869
+ *
2870
+ * @since 2.0.0
2871
+ */
2872
+ minify?: boolean;
2873
+ /**
2874
+ * Whether to pull imported modules into the output.
2875
+ *
2876
+ * @remarks
2877
+ * Left unset, the module structure is preserved and the imports have to resolve at run time instead.
2878
+ *
2879
+ * @example
2880
+ * ```ts
2881
+ * args.bundle; // true
2882
+ * ```
2883
+ *
2884
+ * @since 2.0.0
2885
+ */
2886
+ bundle?: boolean;
2887
+ /**
2888
+ * Module format the output is written in.
2889
+ *
2890
+ * @remarks
2891
+ * Checked while parsing, so a value outside the three fails on the command line rather than in the build.
2892
+ *
2893
+ * @example
2894
+ * ```ts
2895
+ * args.format; // 'esm'
2896
+ * ```
2897
+ *
2898
+ * @since 2.0.0
2899
+ */
2900
+ format?: 'cjs' | 'esm' | 'iife';
2901
+ /**
2902
+ * Whether to report errors with their stack traces.
2903
+ *
2904
+ * @example
2905
+ * ```ts
2906
+ * args.verbose; // true
2907
+ * ```
2908
+ *
2909
+ * @since 2.0.0
2910
+ */
2911
+ verbose?: boolean;
2912
+ /**
2913
+ * Runtime the output targets.
2914
+ *
2915
+ * @remarks
2916
+ * Decides how modules resolve and which built-ins are assumed, `neutral` assuming neither browser nor Node.
2917
+ * Checked while parsing, like {@link format}.
2918
+ *
2919
+ * @example
2920
+ * ```ts
2921
+ * args.platform; // 'node'
2922
+ * ```
2923
+ *
2924
+ * @since 2.0.0
2925
+ */
2926
+ platform?: Platform;
2927
+ /**
2928
+ * Path of the TypeScript configuration to use.
2929
+ *
2930
+ * @remarks
2931
+ * Governs both the type check and the declarations, the two coming from the same compiler.
2932
+ *
2933
+ * @example
2934
+ * ```ts
2935
+ * args.tsconfig; // 'tsconfig.build.json'
2936
+ * ```
2937
+ *
2938
+ * @since 2.0.0
2939
+ */
2940
+ tsconfig?: string;
2941
+ /**
2942
+ * Whether to type check instead of building.
2943
+ *
2944
+ * @remarks
2945
+ * Nothing is emitted, which is what separates it from {@link types}.
2946
+ *
2947
+ * @example
2948
+ * ```ts
2949
+ * args.typeCheck; // true - typed as --typeCheck or --tc
2950
+ * ```
2951
+ *
2952
+ * @since 2.0.0
2953
+ */
2954
+ typeCheck?: boolean;
2955
+ /**
2956
+ * Whether to emit declaration files beside the output.
2957
+ *
2958
+ * @example
2959
+ * ```ts
2960
+ * args.declaration; // true
2961
+ * ```
2962
+ *
2963
+ * @since 2.0.0
2964
+ */
2965
+ declaration?: boolean;
2966
+ /**
2967
+ * Files to build, glob patterns included.
2968
+ *
2969
+ * @remarks
2970
+ * Filled from the files named without a flag as well as from `--entryPoints`, so the usual invocation needs no
2971
+ * flag at all.
2972
+ *
2973
+ * @example
2974
+ * ```ts
2975
+ * args.entryPoints; // [ 'src/index.ts' ]
2976
+ * ```
2977
+ *
2978
+ * @since 2.0.0
2979
+ */
2980
+ entryPoints?: Array<string>;
2981
+ /**
2982
+ * Whether a type error should stop the build.
2983
+ *
2984
+ * @remarks
2985
+ * Reads on the errors {@link types} produces: left unset they are reported and the build carries on.
2986
+ *
2987
+ * @example
2988
+ * ```ts
2989
+ * args.failOnError; // true - typed as --failOnError or --foe
2990
+ * ```
2991
+ *
2992
+ * @since 2.0.0
2993
+ */
2994
+ failOnError?: boolean;
2995
+ /**
2996
+ * Names of the configuration's build variants to run.
2997
+ *
2998
+ * @remarks
2999
+ * Left unset, every variant the configuration defines is built.
3000
+ * Naming some builds only those, which is what a pipeline that ships one target at a time wants.
3001
+ * Repeat the flag to name more than one.
3002
+ *
3003
+ * @example
3004
+ * ```ts
3005
+ * // xBuild --build development --xb staging
3006
+ * args.build; // [ 'development', 'staging' ]
3007
+ * ```
3008
+ *
3009
+ * @see ArgsConfigPath
3010
+ * @since 2.0.0
3011
+ */
3012
+ build?: Array<string>;
3013
+ /**
3014
+ * Whether to clear the artifacts of an earlier build before this one runs.
3015
+ *
3016
+ * @remarks
3017
+ * The one option the parser gives a default,
3018
+ * so a result carries `false` where the flag was not typed rather than leaving it out as the others do.
3019
+ * Nothing reads it yet, so typing it changes a parsed result and nothing else.
3020
+ *
3021
+ * @example
3022
+ * ```ts
3023
+ * args.clean; // true - typed as --clean
3024
+ * ```
3025
+ *
3026
+ * @since 3.0.0
3027
+ */
3028
+ clean?: boolean;
3029
+ }
3030
+ /**
3031
+ * Replaces the declared variants with one built from the entry points the command line named.
3032
+ *
3033
+ * @param config - Configuration read from the file, modified in place
3034
+ * @param args - Parsed command line the run was started with
3035
+ *
3036
+ * @remarks
3037
+ * Files named on the command line are a run of their own rather than an addition to what the file declares,
3038
+ * so the variants it declares are put aside, and a single variant named `argv` takes their place.
3039
+ * A command line naming no entry point leaves the configuration as the file wrote it.
3040
+ *
3041
+ * @example
3042
+ * ```ts
3043
+ * // xBuild src/index.ts
3044
+ * configureEntryPoints(config, args);
3045
+ * config.variants; // { argv: { esbuild: { entryPoints: [ 'src/index.ts' ] } } }
3046
+ * ```
3047
+ *
3048
+ * @since 3.0.0
3049
+ */
3050
+ declare function configureEntryPoints(config: xBuildConfigInterface, args: ArgumentsInterface): void;
3051
+ /**
3052
+ * Writes the flags the command line typed onto every variant.
3053
+ *
3054
+ * @param config - Configuration the overrides are written onto, modified in place
3055
+ * @param args - Parsed command line the run was started with
3056
+ *
3057
+ * @remarks
3058
+ * A flag left untyped is left alone rather than written as its default,
3059
+ * so what a configuration file states survives everything the command line did not say.
3060
+ * The overrides reach every variant, since a flag names what the run is for rather than which variant it is about.
3061
+ * Each output directory is also excluded from the watch as it is settled,
3062
+ * without which a build would write into the tree it is watching and set off the next one.
3063
+ *
3064
+ * @example
3065
+ * ```ts
3066
+ * // xBuild --outdir build --minify
3067
+ * applyCommandLineOverrides(config, args);
3068
+ * config.watch.filter; // [ '!build/**' ]
3069
+ * ```
3070
+ *
3071
+ * @since 3.0.0
3072
+ */
3073
+ declare function applyCommandLineOverrides(config: xBuildConfigInterface, args: ArgumentsInterface): void;
3074
+ /**
3075
+ * Starts the development server where either the command line or the configuration asks for one.
3076
+ *
3077
+ * @param config - Configuration read for its `serve` block
3078
+ * @param args - Parsed command line the run was started with
3079
+ * @param screen - Screen the server reports through
3080
+ * @returns A promise settling once the server is listening, at once when none was asked for
3081
+ *
3082
+ * @remarks
3083
+ * `--serve` carries the directory to serve, so asking for a server and choosing what it serves are the one flag,
3084
+ * and a configuration that starts one of its own is honored even where the flag is absent.
3085
+ * The directory falls back to the configured one and then to `dist`, which is where a build writes by default.
3086
+ * The server reports through the screen rather than to the console,
3087
+ * so its address reaches the status line and its requests are held to the level the run reports at.
3088
+ *
3089
+ * @example
3090
+ * ```ts
3091
+ * // xBuild --serve dist
3092
+ * await startServer(config, args, screen);
3093
+ * // [xBuild] → serve http://localhost:3000
3094
+ * ```
3095
+ *
3096
+ * @see ServerModule
3097
+ * @since 3.0.0
3098
+ */
3099
+ declare function startServer(config: xBuildConfigInterface, args: ArgumentsInterface, screen: Screen): Promise<void>;
3100
+ /**
3101
+ * Watches the project, rebuilds on a change, and takes the terminal for the shortcuts.
3102
+ *
3103
+ * @param buildService - Service the rebuilds run through
3104
+ * @param config - Configuration read for its `watch` block, and replaced when its file changes
3105
+ * @param args - Parsed command line the run was started with
3106
+ * @param screen - Screen the rebuilds are announced on
3107
+ * @returns A promise settling once the keys are listened for, at once when no watch was asked for
3108
+ *
3109
+ * @remarks
3110
+ * A run is watched where `--watch` asked for it, and also where a server is serving,
3111
+ * since output nobody rebuilds is not worth serving.
3112
+ * A change refreshes the file model before anything is rebuilt,
3113
+ * so the rebuild reads the files as they now are rather than as they were read the first time.
3114
+ * Reloading the TypeScript configuration belongs to the screen rather than to the watch,
3115
+ * which puts a rebuild started by a key on the same footing as one started by a change.
3116
+ * The configuration file is watched by its own version rather than by its path,
3117
+ * so an edit to it is reparsed and reapplied while every other change goes straight to a rebuild.
3118
+ * The shortcuts are listened for last, since they take the last row of the terminal,
3119
+ * and a run that never reaches here leaves the terminal as it found it.
3120
+ *
3121
+ * @example
3122
+ * ```ts
3123
+ * // xBuild --watch
3124
+ * await startWatchMode(build, config, args, screen);
3125
+ * // [xBuild] ↻ rebuild 2 files changed
3126
+ * ```
3127
+ *
3128
+ * @see WatchService
3129
+ * @see startInteractive
3130
+ *
3131
+ * @since 3.0.0
3132
+ */
3133
+ declare function startWatchMode(buildService: BuildService, config: xBuildConfigInterface, args: ArgumentsInterface, screen: Screen): Promise<void>;
3134
+
3135
+ export {
3136
+ applyCommandLineOverrides,
3137
+ configureEntryPoints,
3138
+ startServer,
3139
+ startWatchMode
3140
+ };