@calmdown/rolldown-workspace 1.0.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +392 -0
- package/dist/index.js +1 -0
- package/package.json +29 -0
- package/readme.md +168 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
import { InputOptions, LogLevel as LogLevel$1, OutputOptions, Plugin } from "rolldown";
|
|
2
|
+
import { WriteStream } from "node:tty";
|
|
3
|
+
|
|
4
|
+
//#region src/build/Activity.d.ts
|
|
5
|
+
interface Activity {
|
|
6
|
+
readonly isActive: boolean;
|
|
7
|
+
readonly completed: Promise<void>;
|
|
8
|
+
ensureActive(): void;
|
|
9
|
+
}
|
|
10
|
+
declare function activity(block: (stop: () => void) => void | Promise<unknown>): Activity;
|
|
11
|
+
declare namespace activity {
|
|
12
|
+
var untilSignal: (signal0: NodeJS.Signals, ...rest: NodeJS.Signals[]) => Activity;
|
|
13
|
+
var completed: Activity;
|
|
14
|
+
}
|
|
15
|
+
//#endregion
|
|
16
|
+
//#region src/cli/command.d.ts
|
|
17
|
+
interface Command<TArgs extends { [TName in string]?: ArgumentInfo<TName, any, any, boolean> }, TOpts extends { [TName in string]?: OptionInfo<TName, any, any, boolean> }> {
|
|
18
|
+
readonly args: readonly TArgs[string][];
|
|
19
|
+
readonly opts: readonly TOpts[string][];
|
|
20
|
+
readonly optMap: { [K in string]?: TOpts[string] };
|
|
21
|
+
}
|
|
22
|
+
interface ParsedCommand<TArgs extends { [TName in string]?: ArgumentInfo<TName, any, any, boolean> }, TOpts extends { [TName in string]?: OptionInfo<TName, any, any, boolean> }> {
|
|
23
|
+
readonly args: { [K in keyof TArgs]: TArgs[K] extends ArgumentInfo<any, infer TValue, infer TDefault, infer TRequired> ? true extends TRequired ? TValue : (TValue | undefined) & TDefault : unknown };
|
|
24
|
+
readonly opts: { [K in keyof TOpts]: TOpts[K] extends OptionInfo<any, infer TValue, infer TDefault, infer TMultiple> ? true extends TMultiple ? TValue[] : (TValue | undefined) & TDefault : unknown };
|
|
25
|
+
}
|
|
26
|
+
interface RequiredArgumentSetup<TValue> {
|
|
27
|
+
read: (value: string) => TValue;
|
|
28
|
+
required?: true;
|
|
29
|
+
}
|
|
30
|
+
interface OptionalArgumentSetup<TValue, TDefault extends TValue | undefined> {
|
|
31
|
+
read: (value: string) => TValue;
|
|
32
|
+
required: false;
|
|
33
|
+
default?: TDefault;
|
|
34
|
+
}
|
|
35
|
+
interface ArgumentInfo<TName extends string, TValue, TDefault, TRequired extends boolean> {
|
|
36
|
+
read: (value: string) => TValue;
|
|
37
|
+
required: TRequired;
|
|
38
|
+
name: TName;
|
|
39
|
+
default?: TDefault;
|
|
40
|
+
}
|
|
41
|
+
interface BooleanOptionSetup {
|
|
42
|
+
alias?: string[];
|
|
43
|
+
flag?: string;
|
|
44
|
+
}
|
|
45
|
+
interface ValueOptionSetup<TValue, TDefault extends TValue | undefined> {
|
|
46
|
+
read: (value: string) => TValue;
|
|
47
|
+
alias?: string[];
|
|
48
|
+
flag?: string;
|
|
49
|
+
default?: TDefault;
|
|
50
|
+
multiple?: false;
|
|
51
|
+
}
|
|
52
|
+
interface MultiValueOptionSetup<TValue> {
|
|
53
|
+
read: (value: string) => TValue;
|
|
54
|
+
alias?: string[];
|
|
55
|
+
flag?: string;
|
|
56
|
+
multiple: true;
|
|
57
|
+
}
|
|
58
|
+
interface OptionInfo<TName extends string, TValue, TDefault, TMultiple extends boolean> {
|
|
59
|
+
name: TName;
|
|
60
|
+
read?: (value: string) => TValue;
|
|
61
|
+
default?: TDefault;
|
|
62
|
+
multiple: TMultiple;
|
|
63
|
+
}
|
|
64
|
+
interface CommandBuilder<TArgs extends { [TName in string]?: ArgumentInfo<TName, any, any, boolean> }> {
|
|
65
|
+
arg<TName extends string, TValue>(name: TName, setup: RequiredArgumentSetup<TValue>): CommandBuilder<TArgs & { [K in TName]: ArgumentInfo<TName, TValue, undefined, true> }>;
|
|
66
|
+
arg<TName extends string, TValue, TDefault extends TValue | undefined>(name: TName, setup: OptionalArgumentSetup<TValue, TDefault>): CommandBuilder<TArgs & { [K in TName]: ArgumentInfo<TName, TValue, TDefault, false> }>;
|
|
67
|
+
opt<TName extends string>(name: TName, setup?: BooleanOptionSetup): CommandBuilderWithArgs<TArgs, { [K in TName]: OptionInfo<TName, boolean, boolean, false> }>;
|
|
68
|
+
opt<TName extends string, TValue, TDefault extends TValue | undefined>(name: TName, setup: ValueOptionSetup<TValue, TDefault>): CommandBuilderWithArgs<TArgs, { [K in TName]: OptionInfo<TName, TValue, TDefault, false> }>;
|
|
69
|
+
opt<TName extends string, TValue>(name: TName, setup: MultiValueOptionSetup<TValue>): CommandBuilderWithArgs<TArgs, { [K in TName]: OptionInfo<TName, TValue, [], true> }>;
|
|
70
|
+
build(): Command<TArgs, {}>;
|
|
71
|
+
}
|
|
72
|
+
interface CommandBuilderWithArgs<TArgs extends { [TName in string]?: ArgumentInfo<TName, any, any, boolean> }, TOpts extends { [TName in string]?: OptionInfo<TName, any, any, boolean> }> {
|
|
73
|
+
opt<TName extends string>(name: TName, setup?: BooleanOptionSetup): CommandBuilderWithArgs<TArgs, TOpts & { [K in TName]: OptionInfo<TName, boolean, boolean, false> }>;
|
|
74
|
+
opt<TName extends string, TValue, TDefault extends TValue | undefined>(name: TName, setup: ValueOptionSetup<TValue, TDefault>): CommandBuilderWithArgs<TArgs, TOpts & { [K in TName]: OptionInfo<TName, TValue, TDefault, false> }>;
|
|
75
|
+
opt<TName extends string, TValue>(name: TName, setup: MultiValueOptionSetup<TValue>): CommandBuilderWithArgs<TArgs, TOpts & { [K in TName]: OptionInfo<TName, TValue, [], true> }>;
|
|
76
|
+
build(): Command<TArgs, TOpts>;
|
|
77
|
+
}
|
|
78
|
+
declare function buildCommand(): CommandBuilder<{}>;
|
|
79
|
+
declare function parseArgs<TArgs extends { [TName in string]?: ArgumentInfo<TName, any, any, boolean> }, TOpts extends { [TName in string]?: OptionInfo<TName, any, any, boolean> }>(command: Command<TArgs, TOpts>, argv?: readonly string[]): ParsedCommand<TArgs, TOpts>;
|
|
80
|
+
//#endregion
|
|
81
|
+
//#region src/FileSystem.d.ts
|
|
82
|
+
interface FileSystem {
|
|
83
|
+
glob: (patterns: string | readonly string[], options: GlobOptions) => AsyncIterableIterator<string, undefined, any>;
|
|
84
|
+
readFile: (path: string, encoding: "utf8") => Promise<string>;
|
|
85
|
+
}
|
|
86
|
+
interface GlobOptions {
|
|
87
|
+
cwd: string;
|
|
88
|
+
}
|
|
89
|
+
declare function defaultFileSystem(): Promise<FileSystem>;
|
|
90
|
+
//#endregion
|
|
91
|
+
//#region src/workspace/Package.d.ts
|
|
92
|
+
interface PackageDeclaration {
|
|
93
|
+
[key: string]: unknown;
|
|
94
|
+
readonly name: string;
|
|
95
|
+
readonly version?: string;
|
|
96
|
+
readonly workspaces?: readonly string[];
|
|
97
|
+
readonly dependencies?: DependencyMap;
|
|
98
|
+
readonly devDependencies?: DependencyMap;
|
|
99
|
+
readonly peerDependencies?: DependencyMap;
|
|
100
|
+
readonly optionalDependencies?: DependencyMap;
|
|
101
|
+
}
|
|
102
|
+
type DependencyMap = { [TName in string]?: string };
|
|
103
|
+
interface DiscoverPackageOptions {
|
|
104
|
+
/** the directory where to start the discovery, defaults to `process.cwd()` */
|
|
105
|
+
cwd?: string;
|
|
106
|
+
/** the file system override to use, defaults to `node:fs/promises` */
|
|
107
|
+
fs?: FileSystem;
|
|
108
|
+
/** sets a "jail" directory to which the discovery algorithm will be constrained, defaults to `undefined` i.e. unconstrained search */
|
|
109
|
+
jail?: string;
|
|
110
|
+
/** glob pattern to match build config filed, defaults to: `build.config.{js,mjs}` */
|
|
111
|
+
buildConfigGlob?: string;
|
|
112
|
+
}
|
|
113
|
+
declare class Package {
|
|
114
|
+
/** the absolute path to the base directory of this Package */
|
|
115
|
+
readonly directory: string;
|
|
116
|
+
/** the raw contents of package.json for this Package */
|
|
117
|
+
readonly declaration: PackageDeclaration;
|
|
118
|
+
/** path to the build config of this Package, if any */
|
|
119
|
+
readonly buildConfigPath?: string | undefined;
|
|
120
|
+
/**
|
|
121
|
+
* list of downstream workspace dependencies, i.e. other ws packages this one depends on, but not any 3rd-party ones
|
|
122
|
+
*/
|
|
123
|
+
readonly downstreamDependencies: Package[];
|
|
124
|
+
/**
|
|
125
|
+
* list of upstream workspace dependents, i.e. other ws packages that depend on this one, but not any 3rd-party ones
|
|
126
|
+
*/
|
|
127
|
+
readonly upstreamDependents: Package[];
|
|
128
|
+
private constructor();
|
|
129
|
+
private static readonly cache;
|
|
130
|
+
static discover(options?: DiscoverPackageOptions): Promise<Package | null>;
|
|
131
|
+
}
|
|
132
|
+
//#endregion
|
|
133
|
+
//#region src/workspace/Workspace.d.ts
|
|
134
|
+
interface DiscoverWorkspaceOptions extends DiscoverPackageOptions {
|
|
135
|
+
/** list of package names to exclude from discovery, defaults to `[ "build-logic" ]` */
|
|
136
|
+
exclude?: string[];
|
|
137
|
+
/** the kinds of dependencies to follow, defaults to: `Runtime, Development, Peer` */
|
|
138
|
+
followDeps?: DependencyKind[];
|
|
139
|
+
/** filters the refs to consider as workspace refs, defaults to: `ref => ref.startsWith("workspace:")` */
|
|
140
|
+
refFilter?: (ref: string) => boolean;
|
|
141
|
+
}
|
|
142
|
+
interface DiscoverWorkspaceResult {
|
|
143
|
+
currentPackage: Package | null;
|
|
144
|
+
workspace: Workspace | null;
|
|
145
|
+
}
|
|
146
|
+
declare enum DependencyKind {
|
|
147
|
+
Runtime = "dependencies",
|
|
148
|
+
Development = "devDependencies",
|
|
149
|
+
Peer = "peerDependencies",
|
|
150
|
+
Optional = "optionalDependencies"
|
|
151
|
+
}
|
|
152
|
+
declare class Workspace {
|
|
153
|
+
readonly packages: readonly Package[];
|
|
154
|
+
readonly workspaceRoot: Package;
|
|
155
|
+
private constructor();
|
|
156
|
+
static discover(options?: DiscoverWorkspaceOptions): Promise<DiscoverWorkspaceResult>;
|
|
157
|
+
}
|
|
158
|
+
//#endregion
|
|
159
|
+
//#region src/cli/Reporter.d.ts
|
|
160
|
+
type LogLevel = LogLevel$1 | "error";
|
|
161
|
+
type StatusKind = "FAIL" | "BUSY" | "IDLE" | "PASS" | "SKIP";
|
|
162
|
+
interface Reporter {
|
|
163
|
+
reportStackTraces: boolean;
|
|
164
|
+
log(title: string, message: string, level?: LogLevel): void;
|
|
165
|
+
logError(title: string, ex: Error): void;
|
|
166
|
+
addPackage(pkg: Package): void;
|
|
167
|
+
setStatus(pkg: Package, status: StatusKind): void;
|
|
168
|
+
setMessage(pkg: Package, message: string): void;
|
|
169
|
+
packageBuildStarted(pkg: Package): void;
|
|
170
|
+
packageBuildSucceeded(pkg: Package): void;
|
|
171
|
+
packageBuildFailed(pkg: Package): void;
|
|
172
|
+
finish(outro?: string): void;
|
|
173
|
+
}
|
|
174
|
+
//#endregion
|
|
175
|
+
//#region src/cli/common.d.ts
|
|
176
|
+
declare function formatTime(timeMs: number): string;
|
|
177
|
+
declare function overrideConsole(reporter: Reporter): void;
|
|
178
|
+
declare function restoreConsole(): void;
|
|
179
|
+
//#endregion
|
|
180
|
+
//#region src/cli/StreamReporter.d.ts
|
|
181
|
+
interface PackageInfo {
|
|
182
|
+
readonly pkg: Package;
|
|
183
|
+
status: StatusKind;
|
|
184
|
+
buildStartTime: number;
|
|
185
|
+
buildEndTime: number;
|
|
186
|
+
message?: string;
|
|
187
|
+
}
|
|
188
|
+
declare class StreamReporter implements Reporter {
|
|
189
|
+
private readonly output;
|
|
190
|
+
reportStackTraces: boolean;
|
|
191
|
+
private readonly isFormatted;
|
|
192
|
+
private readonly packages;
|
|
193
|
+
private updateHandle;
|
|
194
|
+
private linesToClear;
|
|
195
|
+
private lastLogTitle;
|
|
196
|
+
private isFinished;
|
|
197
|
+
constructor(output: WriteStream);
|
|
198
|
+
log(title: string, message: string, level?: LogLevel): void;
|
|
199
|
+
logError(title: string, ex: Error): void;
|
|
200
|
+
addPackage(pkg: Package): void;
|
|
201
|
+
setStatus(pkg: Package, status: StatusKind): void;
|
|
202
|
+
setMessage(pkg: Package, message: string): void;
|
|
203
|
+
packageBuildStarted(pkg: Package): void;
|
|
204
|
+
packageBuildSucceeded(pkg: Package): void;
|
|
205
|
+
packageBuildFailed(pkg: Package): void;
|
|
206
|
+
finish(outro?: string): void;
|
|
207
|
+
private format;
|
|
208
|
+
private getInfoFor;
|
|
209
|
+
private scheduleUpdate;
|
|
210
|
+
private writeOutput;
|
|
211
|
+
private formatTree;
|
|
212
|
+
private formatTreeNode;
|
|
213
|
+
}
|
|
214
|
+
//#endregion
|
|
215
|
+
//#region src/cli/NoOpReporter.d.ts
|
|
216
|
+
declare const NoOpReporter: Reporter;
|
|
217
|
+
//#endregion
|
|
218
|
+
//#region src/cli/stringify.d.ts
|
|
219
|
+
declare function safeStringifyStruct(value: unknown, indent?: string, visited?: WeakSet<WeakKey>): any;
|
|
220
|
+
//#endregion
|
|
221
|
+
//#region src/factory/common.d.ts
|
|
222
|
+
type InputConfig = Omit<InputOptions, "cwd" | "input" | "onLog" | "plugins">;
|
|
223
|
+
type OutputConfig = Omit<OutputOptions, "plugins">;
|
|
224
|
+
interface BuildTarget {
|
|
225
|
+
readonly name: string;
|
|
226
|
+
readonly input: InputOptions;
|
|
227
|
+
readonly outputs: OutputOptions[];
|
|
228
|
+
}
|
|
229
|
+
interface BuildContext {
|
|
230
|
+
readonly reporter: Reporter;
|
|
231
|
+
readonly cwd: string;
|
|
232
|
+
readonly env: Env;
|
|
233
|
+
readonly moduleName: string;
|
|
234
|
+
readonly isWatching: boolean;
|
|
235
|
+
readonly isDebugging: boolean;
|
|
236
|
+
}
|
|
237
|
+
declare enum Env {
|
|
238
|
+
Development = "dev",
|
|
239
|
+
Staging = "stag",
|
|
240
|
+
Production = "prod"
|
|
241
|
+
}
|
|
242
|
+
interface UtilityConfigurator {
|
|
243
|
+
(context: BuildContext): boolean;
|
|
244
|
+
(current: boolean, context: BuildContext): boolean;
|
|
245
|
+
}
|
|
246
|
+
declare const inDevelopment: UtilityConfigurator;
|
|
247
|
+
declare const inStaging: UtilityConfigurator;
|
|
248
|
+
declare const inProduction: UtilityConfigurator;
|
|
249
|
+
declare const inWatchMode: UtilityConfigurator;
|
|
250
|
+
declare const inDebugMode: UtilityConfigurator;
|
|
251
|
+
declare function inEnv(env0: Env, ...more: Env[]): UtilityConfigurator;
|
|
252
|
+
//#endregion
|
|
253
|
+
//#region src/factory/Entity.d.ts
|
|
254
|
+
type Entity<TName extends string, TConfig extends object, TBase = {}> = TBase & {
|
|
255
|
+
readonly name: TName;
|
|
256
|
+
enable(configurator?: Configurator<boolean>): Entity<TName, TConfig, TBase>;
|
|
257
|
+
disable(configurator?: Configurator<boolean>): Entity<TName, TConfig, TBase>;
|
|
258
|
+
configure(configurator: TConfig | Configurator<TConfig>): Entity<TName, TConfig, TBase>;
|
|
259
|
+
};
|
|
260
|
+
interface ConfiguratorContext<TConfig> extends BuildContext {
|
|
261
|
+
readonly config: TConfig | null;
|
|
262
|
+
}
|
|
263
|
+
interface Configurator<TConfig> {
|
|
264
|
+
(currentConfig: TConfig | undefined, context: BuildContext): Promise<TConfig | undefined> | TConfig | undefined;
|
|
265
|
+
}
|
|
266
|
+
type AnyEntity = (Entity<any, any>);
|
|
267
|
+
type NameOf<TEntity extends AnyEntity> = (TEntity extends Entity<infer TName, any, {}> ? TName : string);
|
|
268
|
+
type ConfigOf<TEntity extends AnyEntity> = (TEntity extends Entity<any, infer TConfig, {}> ? TConfig : unknown);
|
|
269
|
+
declare function createEntity<TName extends string, TConfig extends object, TBase>(name: TName, base: TBase): Entity<TName, TConfig, TBase>;
|
|
270
|
+
//#endregion
|
|
271
|
+
//#region src/factory/EntityContainer.d.ts
|
|
272
|
+
interface EntityContainer<TEntity extends AnyEntity, TEntities extends EntityMap<TEntity> = EntityMap<TEntity>> {
|
|
273
|
+
readonly entityKind: string;
|
|
274
|
+
readonly entityMap: TEntities;
|
|
275
|
+
readonly entityOrder: readonly (keyof TEntities)[];
|
|
276
|
+
isFinal: boolean;
|
|
277
|
+
finalize(): EntityContainer<TEntity, TEntities>;
|
|
278
|
+
add<T extends TEntity>(entity: T): EntityContainer<TEntity, TEntities & { [K in NameOf<TEntity>]: T }>;
|
|
279
|
+
collect<T>(block: (entity: TEntity) => Promise<T | null | undefined>): Promise<T[]>;
|
|
280
|
+
}
|
|
281
|
+
type EntityMap<TEntity extends AnyEntity> = { readonly [TName in string]: TEntity };
|
|
282
|
+
declare function createEntityContainer<TEntity extends AnyEntity>(kind: string): EntityContainer<TEntity, {}>;
|
|
283
|
+
//#endregion
|
|
284
|
+
//#region src/factory/PluginDefinition.d.ts
|
|
285
|
+
type PluginDefinition<TName extends string, TConfig extends object> = Entity<TName, TConfig, {
|
|
286
|
+
suppress(code: string): PluginDefinition<TName, TConfig>;
|
|
287
|
+
}>;
|
|
288
|
+
interface PluginLoader<TConfig extends object> {
|
|
289
|
+
(context: BuildContext): Promise<(config?: TConfig) => Plugin>;
|
|
290
|
+
}
|
|
291
|
+
type AnyPluginDeclaration = (PluginDefinition<any, any>);
|
|
292
|
+
declare function definePlugin<TName extends string, TConfig extends object>(name: TName, loadPlugin: PluginLoader<TConfig>): PluginDefinition<TName, TConfig>;
|
|
293
|
+
//#endregion
|
|
294
|
+
//#region src/factory/OutputDefinition.d.ts
|
|
295
|
+
type OutputDefinition<TName extends string, TPlugins extends EntityMap<AnyPluginDeclaration>> = Entity<TName, OutputConfig, {
|
|
296
|
+
readonly plugins: TPlugins;
|
|
297
|
+
plugin<TPlugin extends AnyPluginDeclaration>(plugin: TPlugin): OutputDefinition<TName, TPlugins & { [K in NameOf<TPlugin>]: TPlugin }>;
|
|
298
|
+
}>;
|
|
299
|
+
type AnyOutputDeclaration = OutputDefinition<any, any>;
|
|
300
|
+
declare function defineOutput<TName extends string>(name: TName): OutputDefinition<TName, {}>;
|
|
301
|
+
//#endregion
|
|
302
|
+
//#region src/factory/PipelineDefinition.d.ts
|
|
303
|
+
type PipelineDefinition<TName extends string, TPlugins extends EntityMap<AnyPluginDeclaration>, TOutputs extends EntityMap<AnyOutputDeclaration>> = Entity<TName, InputConfig, {
|
|
304
|
+
readonly plugins: TPlugins;
|
|
305
|
+
readonly outputs: TOutputs;
|
|
306
|
+
plugin<TPlugin extends AnyPluginDeclaration>(plugin: TPlugin): PipelineDefinition<TName, TPlugins & { [K in NameOf<TPlugin>]: TPlugin }, TOutputs>;
|
|
307
|
+
output<TOutputName extends string, TOutput extends AnyOutputDeclaration>(name: TOutputName, block?: (output: OutputDefinition<TOutputName, {}>) => TOutput): PipelineDefinition<TName, TPlugins, TOutputs & { [K in NameOf<TOutput>]: TOutput }>;
|
|
308
|
+
suppress(code: string): PipelineDefinition<TName, TPlugins, TOutputs>;
|
|
309
|
+
}>;
|
|
310
|
+
type AnyPipelineDeclaration = PipelineDefinition<any, any, any>;
|
|
311
|
+
declare function definePipeline<TName extends string>(name: TName): PipelineDefinition<TName, {}, {}>;
|
|
312
|
+
//#endregion
|
|
313
|
+
//#region src/factory/TargetDefinition.d.ts
|
|
314
|
+
type TargetDefinition<TName extends string, TPipelines extends EntityMap<AnyPipelineDeclaration>> = Entity<TName, InputConfig, {
|
|
315
|
+
readonly pipelines: TPipelines;
|
|
316
|
+
pipeline<TPipelineName extends string, TPipeline extends AnyPipelineDeclaration>(name: TPipelineName, block: (pipeline: PipelineDefinition<TPipelineName, {}, {}>) => TPipeline): TargetDefinition<TName, TPipelines & { [K in NameOf<TPipeline>]: TPipeline }>;
|
|
317
|
+
build(block: (target: Target<TName, TPipelines>, context: BuildContext) => void): void;
|
|
318
|
+
}>;
|
|
319
|
+
type AnyTargetDeclaration = TargetDefinition<any, any>;
|
|
320
|
+
type Target<TName extends string, TPipelines extends EntityMap<AnyPipelineDeclaration>> = Omit<TargetDefinition<TName, TPipelines>, "pipeline" | "override" | "build"> & {
|
|
321
|
+
entry(unit: string, entryPath: string): Target<TName, TPipelines>;
|
|
322
|
+
};
|
|
323
|
+
type AnyTarget = Target<any, any>;
|
|
324
|
+
declare function defineTarget<TName extends string, TTarget extends AnyTargetDeclaration>(name: TName, block: (target: TargetDefinition<TName, {}>) => TTarget): TTarget;
|
|
325
|
+
//#endregion
|
|
326
|
+
//#region src/build/Deferred.d.ts
|
|
327
|
+
interface Deferred<T = void> {
|
|
328
|
+
readonly value: Promise<T>;
|
|
329
|
+
ensurePending(): void;
|
|
330
|
+
getValue(): T;
|
|
331
|
+
}
|
|
332
|
+
interface CompletableDeferred<T = void> extends Deferred<T> {
|
|
333
|
+
complete(value: T): void;
|
|
334
|
+
fail(reason: Error): void;
|
|
335
|
+
}
|
|
336
|
+
declare function deferred<T = void>(): CompletableDeferred<T>;
|
|
337
|
+
declare namespace deferred {
|
|
338
|
+
var resolved: <T>(value: T) => Deferred<T>;
|
|
339
|
+
var rejected: <T = unknown>(reason: Error) => Deferred<T>;
|
|
340
|
+
}
|
|
341
|
+
//#endregion
|
|
342
|
+
//#region src/build/Builder.d.ts
|
|
343
|
+
type BuildCall = Omit<BuildContext, "cwd" | "moduleName">;
|
|
344
|
+
interface BuildHandle {
|
|
345
|
+
build: () => Promise<void>;
|
|
346
|
+
}
|
|
347
|
+
interface WatchResult {
|
|
348
|
+
readonly currentBuild: Deferred;
|
|
349
|
+
readonly watcher: Activity;
|
|
350
|
+
}
|
|
351
|
+
declare class Builder {
|
|
352
|
+
readonly pkg: Package;
|
|
353
|
+
private readonly target;
|
|
354
|
+
private readonly reporter;
|
|
355
|
+
build(main: Activity): Promise<void>;
|
|
356
|
+
watch(main: Activity, onBuildPending: (handle: BuildHandle) => void): WatchResult;
|
|
357
|
+
private static readonly targets;
|
|
358
|
+
private static currentTasks;
|
|
359
|
+
static getTargets(pkg: Package, call: BuildCall): Promise<readonly BuildTarget[]>;
|
|
360
|
+
}
|
|
361
|
+
//#endregion
|
|
362
|
+
//#region src/build/Dispatcher.d.ts
|
|
363
|
+
declare class Dispatcher {
|
|
364
|
+
private readonly targets;
|
|
365
|
+
private readonly reporter;
|
|
366
|
+
private readonly main;
|
|
367
|
+
private readonly queue;
|
|
368
|
+
private isBuilding;
|
|
369
|
+
private constructor();
|
|
370
|
+
private build;
|
|
371
|
+
private watch;
|
|
372
|
+
private enqueue;
|
|
373
|
+
private readonly triggerNext;
|
|
374
|
+
static run(packages: readonly Package[], call: BuildCall, main?: Activity): Promise<Activity>;
|
|
375
|
+
}
|
|
376
|
+
//#endregion
|
|
377
|
+
//#region src/build/runner.d.ts
|
|
378
|
+
interface BuildOptions extends DiscoverWorkspaceOptions {
|
|
379
|
+
/** the CLI arguments without exec path or filename, defaults to: `process.argv.slice(2)` */
|
|
380
|
+
argv?: readonly string[];
|
|
381
|
+
/** the environment to build, overrides CLI args */
|
|
382
|
+
env?: Env;
|
|
383
|
+
/** whether to run in debug mode, overrides CLI args */
|
|
384
|
+
debug?: boolean;
|
|
385
|
+
/** whether to run in watch mode, overrides CLI args */
|
|
386
|
+
watch?: boolean;
|
|
387
|
+
/** the output stream to write CLI info to, null completely disables output, defaults to process.stdout */
|
|
388
|
+
stdout?: WriteStream | null;
|
|
389
|
+
}
|
|
390
|
+
declare function build(options?: BuildOptions): Promise<void>;
|
|
391
|
+
//#endregion
|
|
392
|
+
export { Activity, AnyEntity, AnyOutputDeclaration, AnyPipelineDeclaration, AnyPluginDeclaration, AnyTarget, AnyTargetDeclaration, ArgumentInfo, BooleanOptionSetup, BuildCall, BuildContext, BuildHandle, BuildOptions, BuildTarget, Builder, Command, CommandBuilder, CommandBuilderWithArgs, CompletableDeferred, ConfigOf, Configurator, ConfiguratorContext, Deferred, DependencyKind, DependencyMap, DiscoverPackageOptions, DiscoverWorkspaceOptions, DiscoverWorkspaceResult, Dispatcher, Entity, EntityContainer, EntityMap, Env, FileSystem, GlobOptions, InputConfig, LogLevel, MultiValueOptionSetup, NameOf, NoOpReporter, OptionInfo, OptionalArgumentSetup, OutputConfig, OutputDefinition, Package, PackageDeclaration, PackageInfo, ParsedCommand, PipelineDefinition, PluginDefinition, PluginLoader, Reporter, RequiredArgumentSetup, StatusKind, StreamReporter, Target, TargetDefinition, ValueOptionSetup, WatchResult, Workspace, activity, build, buildCommand, createEntity, createEntityContainer, defaultFileSystem, deferred, defineOutput, definePipeline, definePlugin, defineTarget, formatTime, inDebugMode, inDevelopment, inEnv, inProduction, inStaging, inWatchMode, overrideConsole, parseArgs, restoreConsole, safeStringifyStruct };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{pathToFileURL as e}from"node:url";import{rolldown as t,watch as n}from"rolldown";import{EOL as r}from"node:os";import*as i from"node:path";var a=class extends Error{};function o(e){let t=!0;return{get isActive(){return t},completed:new Promise(n=>{let r=()=>{t=!1,n()};e(r)?.then(r,r)}),ensureActive:s}}function s(){if(!this.isActive)throw new a(`the activity was stopped`)}function c(...e){return o(t=>{let n=()=>{e.forEach(e=>process.off(e,n)),t()};e.forEach(e=>process.on(e,n))})}o.untilSignal=c,o.completed={isActive:!1,completed:Promise.resolve(),ensureActive:s};function l(){let e,t,n={_pending:!0,value:new Promise((n,r)=>{e=n,t=r}),ensurePending:u,getValue:d,complete:t=>{n._pending=!1,n._value=t,e(t)},fail:e=>{n._pending=!1,n._reason=e,t(e)}};return n}l.resolved=e=>{let t=l();return t.complete(e),t},l.rejected=e=>{let t=l();return t.fail(e),t};function u(){if(!this._pending)throw Error(`the Deferred is not pending`)}function d(){if(this._pending)throw Error(`the Deferred is still pending`);if(this._reason)throw this._reason;return this._value}var f=class r{constructor(e,t,n){this.pkg=e,this.target=t,this.reporter=n}async build(e){let{pkg:n,reporter:r,target:i}=this,a;r.packageBuildStarted(n);try{process.chdir(n.directory),a=await t({...i.input,cwd:n.directory});for(let t of i.outputs)e.ensureActive(),await a.write(t);await a.close(),a=void 0,r.packageBuildSucceeded(n)}catch(e){throw r.packageBuildFailed(n),r.logError(n.declaration.name,e),await a?.close(),e}}watch(e,t){let{pkg:r,reporter:i,target:a}=this;process.chdir(r.directory);let s=typeof a.input.watch==`object`?a.input.watch:null,c=n({...a.input,cwd:r.directory,output:a.outputs,watch:{...s,clearScreen:!1}}),u=l();return c.on(`restart`,()=>{let e=l();return t({build:()=>(u??=l(),e.complete(),u.value)}),e.value}),c.on(`event`,e=>{switch(e.code){case`START`:i.packageBuildStarted(r),process.chdir(r.directory);return;case`BUNDLE_END`:return e.result.close();case`END`:i.packageBuildSucceeded(r),u?.complete(),u=null;return;case`ERROR`:i.packageBuildFailed(r),i.logError(r.declaration.name,e.error),u?.fail(e.error),u=null;return}}),{currentBuild:u,watcher:o(async()=>{await e.completed,await c.close()})}}static targets=new WeakMap;static currentTasks=null;static addBuildTask(e){if(!r.currentTasks)throw Error(`build configs must be loaded via the build API`);r.currentTasks.push(e)}static async getTargets(t,n){let i=r.targets.get(t);if(i)return i;let a=[];if(t.buildConfigPath)try{r.currentTasks=a;let n=e(t.buildConfigPath).href;process.chdir(t.directory),await import(n)}finally{r.currentTasks=null}let o={...n,cwd:t.directory,moduleName:t.declaration.name};return i=(await Promise.all(a.map(e=>e(o)))).flat(1),r.targets.set(t,i),i}},p=class e{queue=[];isBuilding=!1;constructor(e,t,n){this.targets=e,this.reporter=t,this.main=n}async build(){let{main:e}=this,t=0;try{for(;t<this.targets.length;)e.ensureActive(),await this.targets[t++].builder.build(e)}catch{for(;t<this.targets.length;)this.reporter.setStatus(this.targets[t++].builder.pkg,`SKIP`)}return o.completed}async watch(){let{main:e}=this,t=[];for(let n of this.targets){e.ensureActive();let r=n.builder.watch(e,e=>this.enqueue(n,e));t.push(r.watcher.completed),await r.currentBuild.value}return o(async()=>{await e.completed,this.reporter.log(`Watch Mode`,`stopping watchers...`),await Promise.allSettled(t)})}enqueue(e,t){let n=0;for(;n<this.queue.length;){let t=this.queue[n];if(t.target===e)return;if(t.target.priority<e.priority)break;n+=1}this.queue.splice(n,0,{target:e,handle:t}),this.triggerNext()}triggerNext=()=>{if(this.isBuilding||!this.main.isActive)return;let e=this.queue[0];e&&(this.isBuilding=!0,e.handle.build().catch(m).finally(()=>{this.queue.shift(),this.isBuilding=!1,process.nextTick(this.triggerNext)}))};static async run(t,n,r=o.untilSignal(`SIGTERM`,`SIGINT`)){let i=new WeakSet,a=new WeakSet,s=[],c=null,l=``,u=(e,t=0)=>{if(i.has(e))return!0;if(a.has(e))return c=e,l=e.declaration.name,!1;a.add(e);for(let n of e.downstreamDependencies)if(!u(n,t+1)){if(c===e)throw Error(`dependency cycle [-> ${l} ->]`);return l+=` -> ${e.declaration.name}`,!1}return a.delete(e),i.add(e),s.push({pkg:e,priority:t}),!0};t.forEach(u);let{reporter:d}=n;for(let e of s)d.addPackage(e.pkg);let p=[];for(let e of s){let t=await f.getTargets(e.pkg,n);for(let n of t)p.push({priority:e.priority,builder:new f(e.pkg,n,d)});t.length===0&&(d.setStatus(e.pkg,`SKIP`),d.setMessage(e.pkg,e.pkg.buildConfigPath?`no targets defined`:`no build config`))}p.sort((e,t)=>t.priority-e.priority);let m=new e(p,d,r);return n.isWatching?m.watch():m.build()}};function m(){}function h(){let e=[],t=[],n={},r={build:()=>({args:e,opts:t,optMap:n}),arg:(t,n)=>{if(n.required===!0&&e.length>0&&e[e.length-1].required!==!0)throw Error(`required args must precede any optional args`);return e.push({name:t,read:n.read,required:n.required??!0,default:n.default}),r},opt:(e,i)=>{if(i?.flag&&i.flag.length!==1)throw Error(`flag must be a single character but '${i.flag}' was given`);let a=i?.read,o=a?i.multiple??!1:!1,s={name:e,read:a,multiple:o,default:o?void 0:a?i.default:!1},c=[e];return i?.alias&&c.push(...i.alias),i?.flag&&c.push(i.flag),t.push(s),c.forEach(e=>{if(n[e]!==void 0)throw Error(`duplicate option name '${e}'`);n[e]=s}),r}};return r}const g=/^\s*?--([^\s]+)\s*$/,_=/^\s*?-([^\s-]+)\s*$/,ee=/^\s*?--\s*$/;function v(e,t=process.argv.slice(2)){let n={},r={},i,a=0,o=0,s=!1,c=(e,n)=>{if(e.read){let i=t[a+1];if(!i||g.test(i)||_.test(i))throw Error(`missing value for option '${n}'`);if(e.multiple)(r[e.name]=r[e.name]??[]).push(e.read(i));else if(r[e.name]===void 0)r[e.name]=e.read(i);else throw Error(`option '${n}' only accepts a single value`);a+=1}else r[e.name]=!0};for(;a<t.length;a+=1){if(ee.test(t[a])){s=!0;continue}if(!s&&(i=g.exec(t[a]))){let t=e.optMap[i[1]];if(!t)throw Error(`unrecognized option '--${i[1]}'`);c(t,`--${i[1]}`);continue}if(!s&&(i=_.exec(t[a]))){let t=i[1];if(t.length===1){let n=e.optMap[t];if(!n)throw Error(`unrecognized option '-${t}'`);c(n,`-${t}`)}else{let n=0;for(;n<i[1].length;n+=1){let i=e.optMap[t[n]];if(!i)throw Error(`unrecognized flag '-${t[n]}'`);if(i.read)throw Error(`cannot use option '-${t[n]}' in a flag group, it requires a value`);r[i.name]=!0}}continue}if(o>=e.args.length)throw Error(`too many arguments`);let l=e.args[o];n[l.name]=l.read(t[a]),o+=1}let l=e.args.reduce((e,t)=>e+(t.required?1:0),0);if(o<l)throw Error(`too few arguments`);return e.opts.forEach(e=>{r[e.name]===void 0&&(r[e.name]=e.multiple?[]:e.default)}),{args:n,opts:r}}function y(e,t=``,n=new WeakSet){switch(typeof e){case`number`:return e.toString();case`string`:return b(e);case`boolean`:return e?`true`:`false`;case`bigint`:return e.toString()+`n`;case`symbol`:return`<symbol>`;case`function`:return`<function>`;case`object`:{if(e===null)return`null`;if(n.has(e))return`<cycle>`;if(n.add(e),Array.isArray(e))return x(e,t,n);let r=Object.getPrototypeOf(e);return r===Object.prototype?S(e,t,n):r?.constructor?.name??`<unknown>`}}}function b(e){let{length:t}=e,n=``,r=0,i=0;for(;r<t;r+=1)e[r]===`"`&&(n+=e.slice(i,r)+`\\"`,i=r+1);return`"`+n+e.slice(i)+`"`}function x(e,t,n){let r=t+` `,{length:i}=e,a=``,o=0;for(;o<i;o+=1)a+=`\n${r}${y(e[o],r,n)},`;return a?`[${a}\n${t}]`:`[]`}function S(e,t,n){let r=t+` `,i=``,a;for(a in e)Object.hasOwn(e,a)&&(i+=`\n${r}${y(a,``,n)}: ${y(e[a],r,n)},`);return i?`{${i}\n${t}}`:`{}`}function C(e){return e>=1e3?`${(Math.round(e/100)/10).toFixed(1)}s`:`${e.toFixed(0)}ms`}const te=console.trace,ne=console.debug,re=console.log,ie=console.info,ae=console.warn,oe=console.error;function w(e){let t=t=>(...n)=>{let r=n.map(e=>typeof e==`string`?e:y(e)).join(` `);e.log(`Console`,r,t)};console.trace=t(`debug`),console.debug=t(`debug`),console.log=t(`info`),console.info=t(`info`),console.warn=t(`warn`),console.error=t(`error`)}function T(){console.trace=te,console.debug=ne,console.log=re,console.info=ie,console.warn=ae,console.error=oe}const E=`0;31m`,D=`0;33m`,O=`0;90m`,k={FAIL:E,BUSY:`0;36m`,IDLE:O,PASS:`0;32m`,SKIP:D},se={debug:O,info:`0;37m`,warn:D,error:E};var A=class{reportStackTraces=!1;isFormatted=!/^(true|1)$/i.test(process.env.CI??``);packages=new Map;updateHandle=null;linesToClear=0;lastLogTitle=``;isFinished=!1;constructor(e){this.output=e}log(e,t,n=`info`){let i=``;if(this.lastLogTitle!==e){let t=`╭`+`─`.repeat(e.length-1);i=`${r}${this.format(e,`1m`)}${r}${this.format(t,O)}${r}`,this.lastLogTitle=e}let a=this.format(`│`,O),o=t.split(/(?:\r\n|\n|\r)+/g).map(e=>this.format(e,se[n])).join(`${r}${a} `);i+=`${a} ${o}${r}`,this.writeOutput(i)}logError(e,t){t instanceof a||this.log(e,(this.reportStackTraces?t.stack:null)??t.toString(),`error`)}addPackage(e){let t=this.getInfoFor(e);t.status=`IDLE`,this.scheduleUpdate()}setStatus(e,t){let n=this.getInfoFor(e);n.status=t,this.scheduleUpdate()}setMessage(e,t){let n=this.getInfoFor(e);n.message=t,this.scheduleUpdate()}packageBuildStarted(e){let t=this.getInfoFor(e);t.status=`BUSY`,t.buildStartTime=Date.now(),this.scheduleUpdate()}packageBuildSucceeded(e){let t=this.getInfoFor(e);t.status=`PASS`,t.buildEndTime=Date.now(),this.scheduleUpdate()}packageBuildFailed(e){let t=this.getInfoFor(e);t.status=`FAIL`,t.buildEndTime=Date.now(),this.scheduleUpdate()}finish(e){this.writeOutput(``,!0,e?`${r}${e}${r}`:r),this.linesToClear=0,this.isFinished=!0}format(e,t){return this.isFormatted?/^\s*$/.test(e)?e:`\u001b[${t}${e}\u001b[0m`:e}getInfoFor(e){let t=this.packages.get(e);return t||this.packages.set(e,t={pkg:e,status:`IDLE`,buildStartTime:0,buildEndTime:0}),t}scheduleUpdate(){this.updateHandle??=setTimeout(()=>{this.updateHandle=null,this.writeOutput(``)},50)}writeOutput(e,t=this.isFormatted,n=``){let r=e;if(this.linesToClear>0&&(r=`\u001b[${this.linesToClear}A\r\u001b[0J${r}`,this.linesToClear=0),t&&!this.isFinished){let e=this.formatTree();r+=e.output,this.linesToClear=e.lineCount}this.output.write(r+n)}formatTree(){return this.packages.values().filter(({pkg:e})=>e.upstreamDependents.length===0||e.upstreamDependents.every(e=>!this.packages.has(e))).reduce((e,t)=>{let n=this.formatTreeNode(t.pkg);return e.lineCount+=n.lineCount,e.output+=n.output,e},{lineCount:1,output:r})}formatTreeNode(e,t=``,n=``,i=``){let a=this.packages.get(e),o=this.format(`IDLE`,k.IDLE),s=``;a&&(o=this.format(a.status,k[a.status]),a.buildStartTime>0&&a.buildEndTime>=a.buildStartTime&&(s+=` · ${C(a.buildEndTime-a.buildStartTime)}`),a.message&&(s+=` · ${a.message}`));let{length:c}=e.downstreamDependencies,l=0,u,d,f=1,p=`${o} ${this.format(t+n,O)}${this.format(e.declaration.name,`1m`)}${this.format(s,O)}${r}`;for(;l<c;l+=1)u=l+1===c,d=this.formatTreeNode(e.downstreamDependencies[l],t+i,u?`╰─ `:`├─ `,u?` `:`│ `),f+=d.lineCount,p+=d.output;return{lineCount:f,output:p}}};const j={reportStackTraces:!1,log:M,logError:M,addPackage:M,setStatus:M,setMessage:M,packageBuildStarted:M,packageBuildSucceeded:M,packageBuildFailed:M,finish:M};function M(){}let N=function(e){return e.Development=`dev`,e.Staging=`stag`,e.Production=`prod`,e}({});function P(e,...t){return(n,r)=>e(typeof n==`boolean`?r:n,...t)}const ce=P(e=>e.env===N.Development),le=P(e=>e.env===N.Staging),ue=P(e=>e.env===N.Production),de=P(e=>e.isWatching),fe=P(e=>e.isDebugging);function pe(...e){return P(t=>e.includes(t.env))}function F(e,t){return{name:e,isFinal:!1,getEnabled:I,getConfig:L,finalize:R,enable:z,disable:B,configure:me,...t}}function I(){return!0}function L(e){return e}function R(){return this.isFinal?this:{...this,isFinal:!0}}function z(e=I){let t=this.getEnabled,n=async(n,r)=>e(await t(n,r),r);return this.isFinal?(this.getEnabled=n,this):{...this,getEnabled:n}}function B(e=I){let t=this.getEnabled,n=async(n,r)=>!await e(!await t(n,r),r);return this.isFinal?(this.getEnabled=n,this):{...this,getEnabled:n}}function me(e){let t=this.getConfig,n=async(n,r)=>typeof e==`function`?e(await t(n,r),r):V(await t(n,r),e);return this.isFinal?(this.getConfig=n,this):{...this,getConfig:n}}function V(e,t){if(!H(e)||!H(t))return t;let n={...e},r;for(r in t)Object.hasOwn(t,r)&&(n[r]=V(e[r],t[r]));return n}function H(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function U(e){return{entityKind:e,entityMap:{},entityOrder:[],isFinal:!1,finalize:he,add:ge,collect:_e}}function he(){return{...this,isFinal:!0,entityOrder:[...this.entityOrder],entityMap:this.entityOrder.reduce((e,t)=>(e[t]=this.entityMap[t].finalize(),e),{})}}function ge(e){if(this.entityMap[e.name]!==void 0)throw Error(`${this.entityKind} '${e.name}' has already been added.`);return this.isFinal?(this.entityMap[e.name]=e,this.entityOrder.push(e.name),this):{...this,entityMap:{...this.entityMap,[e.name]:e},entityOrder:[...this.entityOrder,e.name]}}function _e(e){return Promise.all(this.entityOrder.map(t=>e(this.entityMap[t]))).then(e=>e.filter(e=>e!=null))}function W(e){let t=U(`Plugin`);return F(e,{plugins:t.entityMap,pluginContainer:t,finalize:ve,plugin:ye})}function ve(){let e=this.pluginContainer.finalize();return{...this,isFinal:!0,plugins:e.entityMap,pluginContainer:e}}function ye(e){if(this.isFinal)return this.pluginContainer.add(e),this;let t=this.pluginContainer.add(e);return{...this,plugins:t.entityMap,pluginContainer:t}}function G(e){let t=U(`Plugin`),n=U(`Output`);return F(e,{plugins:t.entityMap,outputs:n.entityMap,pluginContainer:t,outputContainer:n,suppressions:new Set,finalize:be,plugin:xe,output:Se,suppress:Ce})}function be(){let e=this.pluginContainer.finalize(),t=this.outputContainer.finalize();return{...this,isFinal:!0,plugins:e.entityMap,pluginContainer:e,outputs:t.entityMap,outputContainer:t}}function xe(e){if(this.isFinal)return this.pluginContainer.add(e),this;let t=this.pluginContainer.add(e);return{...this,plugins:t.entityMap,pluginContainer:t}}function Se(e,t){let n=t?t(W(e)):W(e);if(this.isFinal)return this.outputContainer.add(n),this;let r=this.outputContainer.add(n);return{...this,outputs:r.entityMap,outputContainer:r}}function Ce(e){return this.suppressions.add(e),this}function we(e,t){return F(e,{suppressions:new Set,loadPlugin:t,suppress:Te})}function Te(e){return this.suppressions.add(e),this}function Ee(e,t){let n=U(`Pipeline`);return t(F(e,{pipelines:n.entityMap,pipelineContainer:n,finalize:De,entry:Oe,pipeline:ke,build:Ae}))}function De(){let e=this.pipelineContainer.finalize();return{...this,isFinal:!0,entries:{},pipelines:e.entityMap,pipelineContainer:e}}function Oe(e,t){if(!this.isFinal)throw Error(`Cannot add entries to an unfinalized Target.`);return this.entries[e]=t,this}function ke(e,t){let n=t(G(e));if(this.isFinal)return this.pipelineContainer.add(n),this;let r=this.pipelineContainer.add(n);return{...this,pipelines:r.entityMap,pipelineContainer:r}}function Ae(e){let t=this.finalize();f.addBuildTask(async n=>{if(e(t,n),!je(t)||await K(t,n))return[];let r=await t.getConfig({},n);return t.pipelineContainer.collect(async e=>{if(await K(e,n))return null;let i=Array.from(e.suppressions).map(e=>({code:e})),a=await e.getConfig(r,n),o=await q(e.pluginContainer,n,i),s=await e.outputContainer.collect(async e=>{if(await K(e,n))return null;let t=await e.getConfig({},n),r=await q(e.pluginContainer,n,i);return{...t,plugins:r}});return s.length===0?null:{name:`${t.name} · ${e.name}`,outputs:s,input:{...a,input:t.entries,plugins:o,onLog(e,t){if(!(t.pluginCode!==void 0&&i.some(e=>e.code===t.pluginCode&&(!e.plugin||e.plugin===t.plugin)))&&(e!==`debug`||n.isDebugging)){let r=`${t.pluginCode?`[${t.plugin}:${t.pluginCode}] `:``}${t.message}`;n.reporter.log(n.moduleName,r,e)}}}}})})}function je(e){return!!e.entries&&Object.keys(e.entries).length>0}async function K(e,t){return!await e.getEnabled(!0,t)}function q(e,t,n){return e.collect(async e=>{if(await K(e,t))return null;let r=await e.getConfig(void 0,t),i=(await e.loadPlugin(t))(r);return e.suppressions.forEach(e=>n.push({code:e,plugin:i.name})),i})}async function J(){let e=await import(`node:fs/promises`);return{glob:e.glob,readFile:e.readFile}}var Y=class e{downstreamDependencies=[];upstreamDependents=[];constructor(e,t,n){this.directory=e,this.declaration=t,this.buildConfigPath=n}static cache=new Map;static async discover(t){let n=t?.fs??await J(),r=[],a=null;try{let o=t?.jail?i.resolve(t?.jail):``,s,c,l=t?.cwd?i.resolve(t.cwd):process.cwd(),u=0;for(;l.startsWith(o)&&++u<128;){let t=e.cache.get(l);if(t!==void 0)return t;try{r.push(l),s=i.join(l,`./package.json`),c=await n.readFile(s,`utf8`);break}catch(e){if(!Me(e))throw e}let a=i.join(l,`..`);if(a===l)break;l=a}if(!c)return null;let d;try{d=JSON.parse(c)}catch(e){throw Error(`could not parse 'package.json' file at: ${s}`,{cause:e})}if(!Ne(d))throw Error(`expected a JSON object in: ${s}`);if(!X(d.name))throw Error(`name must be a string in: ${s}`);if(d.workspaces!==void 0&&!Pe(d.workspaces,X))throw Error(`workspaces must be an array of strings in: ${s}`);let f=t?.buildConfigGlob??`build.config.{js,mjs}`,p=n.glob(f,{cwd:l}),m;try{for await(let e of p){if(m)throw Error(`multiple build config files found in: ${l}`);m=i.join(l,e)}}finally{await p.return?.()}return a=new e(l,d,m)}catch(e){throw e}finally{r.forEach(t=>{e.cache.set(t,a)})}}};function Me(e){return e?.code===`ENOENT`}function Ne(e){return typeof e==`object`&&!!e}function X(e){return typeof e==`string`}function Pe(e,t){return Array.isArray(e)&&(e.length===0||t(e[0]))}let Z=function(e){return e.Runtime=`dependencies`,e.Development=`devDependencies`,e.Peer=`peerDependencies`,e.Optional=`optionalDependencies`,e}({});const Fe=e=>e.startsWith(`workspace:`),Ie=[Z.Runtime,Z.Development,Z.Peer];var Q=class e{constructor(e=[],t){this.packages=e,this.workspaceRoot=t}static async discover(t){let n=t?.fs??await J(),r=null,a=t?.cwd?i.resolve(t.cwd):process.cwd(),o=0,s;for(;s=await Y.discover({...t,cwd:a,fs:n}),!(!s||(r??=s,s.declaration.workspaces));){let e=i.join(s?.directory??a,`..`);if(e===a||++o>=128)break;a=e}if(!s?.declaration.workspaces)return{currentPackage:r,workspace:null};let c=t?.exclude??[`build-logic`],l=[],u=new Set([s]);a=s.directory;for await(let e of n.glob(s.declaration.workspaces,{cwd:a}))l.push((async()=>{let n=await Y.discover({...t,cwd:i.join(a,e)});n&&!c.includes(n.declaration.name)&&u.add(n)})());await Promise.all(l);let d=t?.refFilter??Fe,f=t?.followDeps??Ie;return u.forEach(e=>{u.forEach(t=>{f.forEach(n=>{let r=e.declaration[n]?.[t.declaration.name];r&&d(r)&&(e.downstreamDependencies.push(t),t.upstreamDependents.push(e))})})}),{currentPackage:r,workspace:new e(Array.from(u),s)}}};const $={dev:N.Development,development:N.Development,stag:N.Staging,staging:N.Staging,prod:N.Production,production:N.Production},Le=h().opt(`env`,{alias:[`environment`],flag:`e`,read:e=>{let t=$[e.toLowerCase()];if(t===void 0)throw Error(`'${e}' is not a valid environment name`);return t}}).opt(`watch`,{flag:`w`}).opt(`debug`,{flag:`d`}).build();async function Re(e){let t=Date.now(),n=e?.stdout===null?j:new A(e?.stdout??process.stdout),r=!1,i=!1;try{let t=v(Le,e?.argv),a=e?.cwd??process.cwd();r=e?.watch??t.opts.watch,i=e?.debug??t.opts.debug,n.reportStackTraces=i,w(n);let o=e?.env??t.opts.env;if(o===void 0){let e;e??=process.env.NODE_ENV,e??=process.env.BUILD_ENV,e??=process.env.ENVIRONMENT,o=$[e?.toLowerCase()??``]??N.Production}let{currentPackage:s,workspace:c}=await Q.discover({...e,cwd:a}),l;if(c&&c.workspaceRoot===s&&!s.buildConfigPath)l=c.packages;else if(s){if(!s.buildConfigPath)throw Error(`package '${s.declaration.name}' has no build config`);l=[s]}else throw Error(`no package was found`);await(await p.run(l,{reporter:n,env:o,isWatching:r,isDebugging:i})).completed,process.exitCode=0}catch(e){n.logError(`Error`,e),process.exitCode=1}finally{let e=``;r||(e=`done in ${C(Date.now()-t)}`),n.finish(e),T()}}export{f as Builder,Z as DependencyKind,p as Dispatcher,N as Env,j as NoOpReporter,Y as Package,A as StreamReporter,Q as Workspace,o as activity,Re as build,h as buildCommand,F as createEntity,U as createEntityContainer,J as defaultFileSystem,l as deferred,W as defineOutput,G as definePipeline,we as definePlugin,Ee as defineTarget,C as formatTime,fe as inDebugMode,ce as inDevelopment,pe as inEnv,ue as inProduction,le as inStaging,de as inWatchMode,w as overrideConsole,v as parseArgs,T as restoreConsole,y as safeStringifyStruct};
|
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@calmdown/rolldown-workspace",
|
|
3
|
+
"version": "1.0.0-rc.1",
|
|
4
|
+
"license": "ISC",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"import": "./dist/index.js",
|
|
9
|
+
"types": "./dist/index.d.ts"
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"./dist/index.js",
|
|
14
|
+
"./dist/index.d.ts"
|
|
15
|
+
],
|
|
16
|
+
"peerDependencies": {
|
|
17
|
+
"rolldown": "1.0.0-rc.9"
|
|
18
|
+
},
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"@types/node": "25.5.0",
|
|
21
|
+
"rolldown": "1.0.0-rc.9",
|
|
22
|
+
"rolldown-plugin-dts": "0.22.5",
|
|
23
|
+
"typescript": "5.9.3"
|
|
24
|
+
},
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "rolldown --config rolldown.config.js",
|
|
27
|
+
"typecheck": "tsc --noEmit"
|
|
28
|
+
}
|
|
29
|
+
}
|
package/readme.md
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
# Rolldown Workspace
|
|
2
|
+
|
|
3
|
+
Utility library marrying Rolldown with Yarn Workspaces with declarative and
|
|
4
|
+
reusable config blocks inspired by Gradle.
|
|
5
|
+
|
|
6
|
+
## Getting Started
|
|
7
|
+
|
|
8
|
+
First, create a `build-logic` workspace in your monorepo. This alone creates a
|
|
9
|
+
powerful setup for sharing dependencies and build configs without the need to
|
|
10
|
+
re-define anything twice. The general structure looks similar to this:
|
|
11
|
+
|
|
12
|
+
```txt
|
|
13
|
+
my-monorepo
|
|
14
|
+
├─ build-logic
|
|
15
|
+
│ ├─ build.js the global build command
|
|
16
|
+
│ ├─ package.json defines Rolldown and plugin versions
|
|
17
|
+
│ ├─ plugins.js plugin imports and default configs
|
|
18
|
+
│ └─ targets.js common build targets used by individual packages
|
|
19
|
+
│
|
|
20
|
+
├─ packages
|
|
21
|
+
│ ├─ package-1
|
|
22
|
+
│ │ ├─ build.config.js defines which targets to build with optional overrides
|
|
23
|
+
│ │ ├─ package.json defines build-logic dev dependency
|
|
24
|
+
│ │ └─ ...
|
|
25
|
+
│ │
|
|
26
|
+
│ ├─ package-2
|
|
27
|
+
│ │ ├─ build.config.js defines which targets to build with optional overrides
|
|
28
|
+
│ │ ├─ package.json defines build-logic dev dependency
|
|
29
|
+
│ │ └─ ...
|
|
30
|
+
│ │
|
|
31
|
+
│ └─ ...
|
|
32
|
+
│
|
|
33
|
+
└─ package.json defines workspaces
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
The monorepo root `package.json` only needs to define workspaces and optionally
|
|
37
|
+
a dev dependency on `build-logic` if you'd like to have the build command
|
|
38
|
+
available throughout all workspaces.
|
|
39
|
+
|
|
40
|
+
```json
|
|
41
|
+
{
|
|
42
|
+
"name": "my-monorepo",
|
|
43
|
+
"private": true,
|
|
44
|
+
"workspaces": [
|
|
45
|
+
"build-logic",
|
|
46
|
+
"packages/*"
|
|
47
|
+
],
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"build-logic": "workspace:*"
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### The build-logic Package
|
|
55
|
+
|
|
56
|
+
The `build-logic` package will contain most of the meat. First, create the
|
|
57
|
+
`package.json` file. It should define your plugins and targets exports, the
|
|
58
|
+
global build command and dev dependencies on rolldown itself and all plugins
|
|
59
|
+
you're using. E.g.:
|
|
60
|
+
|
|
61
|
+
```json
|
|
62
|
+
{
|
|
63
|
+
"name": "build-logic",
|
|
64
|
+
"private": true,
|
|
65
|
+
"exports": {
|
|
66
|
+
"./plugins": {
|
|
67
|
+
"import": "./plugins.js"
|
|
68
|
+
},
|
|
69
|
+
"./targets": {
|
|
70
|
+
"import": "./targets.js"
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
"bin": {
|
|
74
|
+
"build": "./build.js"
|
|
75
|
+
},
|
|
76
|
+
"devDependencies": {
|
|
77
|
+
"@calmdown/rolldown-workspace": "1.0.0",
|
|
78
|
+
"rolldown": "1.0.0-rc.3",
|
|
79
|
+
"rolldown-plugin-dts": "0.22.1"
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Then, define the plugins you will be using in `plugins.js`. To avoid importing
|
|
85
|
+
plugins that are only used by some targets, dynamic imports are typically used.
|
|
86
|
+
E.g.:
|
|
87
|
+
|
|
88
|
+
```js
|
|
89
|
+
import { definePlugin } from "@calmdown/rolldown-workspace";
|
|
90
|
+
|
|
91
|
+
export const Declarations = definePlugin(
|
|
92
|
+
"Declarations",
|
|
93
|
+
async () => (await import("rolldown-plugin-dts")).dts,
|
|
94
|
+
);
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Then, define common build targets in `targets.mjs`. E.g.:
|
|
98
|
+
|
|
99
|
+
```js
|
|
100
|
+
import { defineTarget, Env, inEnv } from "@calmdown/rolldown-workspace";
|
|
101
|
+
|
|
102
|
+
import * as Plugin from "./plugins.mjs";
|
|
103
|
+
|
|
104
|
+
export const TypeScriptLibrary = defineTarget("TypeScriptLibrary", target => target
|
|
105
|
+
.configure({
|
|
106
|
+
external: [ "lodash" ],
|
|
107
|
+
tsconfig: "./tsconfig.json",
|
|
108
|
+
})
|
|
109
|
+
.pipeline("Code", pipe => pipe
|
|
110
|
+
.plugin(Plugin.Declarations
|
|
111
|
+
.enable(inEnv(Env.Production))
|
|
112
|
+
)
|
|
113
|
+
.output("Main", out => out
|
|
114
|
+
.configure((prev, context) => ({
|
|
115
|
+
...prev,
|
|
116
|
+
cleanDir: true,
|
|
117
|
+
minify: isEnv(context, Env.Production),
|
|
118
|
+
}))
|
|
119
|
+
)
|
|
120
|
+
)
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
// ...
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Finally add the build command script in `build.mjs`. The build function comes
|
|
127
|
+
with sensible defaults out of the box, however it is recommended to set at least
|
|
128
|
+
the `jail` directory to constrain all lookups to stay within the monorepo.
|
|
129
|
+
|
|
130
|
+
```js
|
|
131
|
+
import * as path from "node:path";
|
|
132
|
+
|
|
133
|
+
import { build } from "@calmdown/rolldown-workspace";
|
|
134
|
+
|
|
135
|
+
const jail = path.join(import.meta.dirname, "../..");
|
|
136
|
+
await build({ jail });
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Other Packages
|
|
140
|
+
|
|
141
|
+
With this setup, any package that needs a Rolldown build can now do so simply by
|
|
142
|
+
adding a dev dependency on `build-logic` and adding a `build.config.mjs` script:
|
|
143
|
+
|
|
144
|
+
```json
|
|
145
|
+
{
|
|
146
|
+
"name": "package-1",
|
|
147
|
+
"devDependencies": {
|
|
148
|
+
"build-logic": "workspace:*"
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
```js
|
|
154
|
+
import * as Target from "build-logic/targets";
|
|
155
|
+
|
|
156
|
+
Target.JavaScriptLibrary.build(target => {
|
|
157
|
+
target.entry("app", "./src/index.js");
|
|
158
|
+
|
|
159
|
+
// here you can override individual configurations, add or disable plugins, etc.
|
|
160
|
+
// all without affecting other packages even if they use the same target
|
|
161
|
+
target.pipelines.Code.plugins.Terser.disable();
|
|
162
|
+
});
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Now when you navigate to the `./packages/package-1` directory and run
|
|
166
|
+
`yarn build`, it will execute the configured Rolldown build. Additionally, if
|
|
167
|
+
your package defines dependencies on other workspace packages, they will be
|
|
168
|
+
built first as long as they define their own build configs.
|