@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/README.md +30 -4
- package/dist/bash.d.ts +3135 -0
- package/dist/bash.js +41 -66
- package/dist/bash.js.map +1 -1
- package/dist/index.d.ts +2774 -4978
- package/dist/index.js +23 -27
- package/dist/index.js.map +1 -1
- package/package.json +26 -16
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
|
+
};
|