@gjsify/cli 0.3.21 → 0.4.3

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.
Files changed (69) hide show
  1. package/dist/cli.gjs.mjs +791 -0
  2. package/lib/actions/build.js +4 -17
  3. package/lib/bundler-pick.d.ts +79 -0
  4. package/lib/bundler-pick.js +436 -0
  5. package/lib/commands/foreach.d.ts +17 -0
  6. package/lib/commands/foreach.js +341 -0
  7. package/lib/commands/index.d.ts +2 -0
  8. package/lib/commands/index.js +2 -0
  9. package/lib/commands/install.d.ts +1 -0
  10. package/lib/commands/install.js +401 -27
  11. package/lib/commands/run.d.ts +1 -1
  12. package/lib/commands/run.js +113 -20
  13. package/lib/commands/workspace.d.ts +8 -0
  14. package/lib/commands/workspace.js +79 -0
  15. package/lib/config.js +12 -1
  16. package/lib/index.js +11 -3
  17. package/lib/types/config-data.d.ts +10 -1
  18. package/lib/utils/install-backend-native.d.ts +5 -1
  19. package/lib/utils/install-backend-native.js +329 -70
  20. package/lib/utils/install-backend.d.ts +11 -1
  21. package/lib/utils/install-backend.js +4 -2
  22. package/lib/utils/pkg-json-edit.d.ts +47 -0
  23. package/lib/utils/pkg-json-edit.js +108 -0
  24. package/lib/utils/workspace-root.d.ts +1 -0
  25. package/lib/utils/workspace-root.js +46 -0
  26. package/package.json +70 -44
  27. package/src/actions/build.ts +0 -431
  28. package/src/actions/index.ts +0 -1
  29. package/src/commands/build.ts +0 -146
  30. package/src/commands/check.ts +0 -87
  31. package/src/commands/create.ts +0 -63
  32. package/src/commands/dlx.ts +0 -195
  33. package/src/commands/flatpak/build.ts +0 -225
  34. package/src/commands/flatpak/ci.ts +0 -173
  35. package/src/commands/flatpak/deps.ts +0 -120
  36. package/src/commands/flatpak/index.ts +0 -53
  37. package/src/commands/flatpak/init.ts +0 -191
  38. package/src/commands/flatpak/utils.ts +0 -76
  39. package/src/commands/gettext.ts +0 -258
  40. package/src/commands/gresource.ts +0 -97
  41. package/src/commands/gsettings.ts +0 -87
  42. package/src/commands/index.ts +0 -12
  43. package/src/commands/info.ts +0 -70
  44. package/src/commands/install.ts +0 -195
  45. package/src/commands/run.ts +0 -33
  46. package/src/commands/showcase.ts +0 -149
  47. package/src/config.ts +0 -304
  48. package/src/constants.ts +0 -1
  49. package/src/index.ts +0 -37
  50. package/src/types/cli-build-options.ts +0 -100
  51. package/src/types/command.ts +0 -10
  52. package/src/types/config-data-library.ts +0 -5
  53. package/src/types/config-data-typescript.ts +0 -6
  54. package/src/types/config-data.ts +0 -225
  55. package/src/types/cosmiconfig-result.ts +0 -5
  56. package/src/types/index.ts +0 -6
  57. package/src/utils/check-system-deps.ts +0 -480
  58. package/src/utils/detect-native-packages.ts +0 -153
  59. package/src/utils/discover-showcases.ts +0 -75
  60. package/src/utils/dlx-cache.ts +0 -135
  61. package/src/utils/install-backend-native.ts +0 -363
  62. package/src/utils/install-backend.ts +0 -88
  63. package/src/utils/install-global.ts +0 -182
  64. package/src/utils/normalize-bundler-options.ts +0 -129
  65. package/src/utils/parse-spec.ts +0 -48
  66. package/src/utils/resolve-gjs-entry.ts +0 -96
  67. package/src/utils/resolve-plugin-by-name.ts +0 -106
  68. package/src/utils/run-gjs.ts +0 -90
  69. package/tsconfig.json +0 -16
@@ -1,4 +1,4 @@
1
- import { rolldown } from "rolldown";
1
+ import { runBundle, bundleToChunks } from "../bundler-pick.js";
2
2
  import { gjsifyPlugin, textLoaderPlugin, resolveShebangLine } from "@gjsify/rolldown-plugin-gjsify";
3
3
  import { resolveUserPlugins } from "../utils/resolve-plugin-by-name.js";
4
4
  import { resolveGlobalsList, writeRegisterInjectFile, detectAutoGlobals, } from "@gjsify/rolldown-plugin-gjsify/globals";
@@ -256,7 +256,7 @@ export class BuildAction {
256
256
  external: userBundler.external,
257
257
  transform: userBundler.transform,
258
258
  format,
259
- }, pluginOpts, gjsifyPluginFactory, verbose, { extraGlobalsList: extras, excludeGlobals });
259
+ }, pluginOpts, gjsifyPluginFactory, verbose, { extraGlobalsList: extras, excludeGlobals }, bundleToChunks);
260
260
  pluginOpts.autoGlobalsInject = injectPath;
261
261
  }
262
262
  else if (extras) {
@@ -281,14 +281,7 @@ export class BuildAction {
281
281
  // Rolldown doesn't understand) would crash the build.
282
282
  plugins: [...pnpPlugins, ...userPlugins, ...cfg.plugins],
283
283
  };
284
- const build = await rolldown(finalOpts);
285
- let writeResult;
286
- try {
287
- writeResult = await build.write(finalOpts.output ?? {});
288
- }
289
- finally {
290
- await build.close();
291
- }
284
+ const writeResult = await runBundle(finalOpts);
292
285
  if (app === "gjs" && this.configData.shebang) {
293
286
  await this.applyShebang(outfile, verbose);
294
287
  }
@@ -312,11 +305,5 @@ async function runOneLibraryBuild(args) {
312
305
  ...merged,
313
306
  plugins: [...args.pnpPlugins, ...cfg.plugins],
314
307
  };
315
- const build = await rolldown(finalOpts);
316
- try {
317
- return await build.write(finalOpts.output ?? {});
318
- }
319
- finally {
320
- await build.close();
321
- }
308
+ return await runBundle(finalOpts);
322
309
  }
@@ -0,0 +1,79 @@
1
+ import type { RolldownOutput } from 'rolldown';
2
+ import type { BundlerOptions } from './types/index.js';
3
+ export interface NativePluginContext {
4
+ resolve(specifier: string, importer?: string, opts?: {
5
+ skipSelf?: boolean;
6
+ isEntry?: boolean;
7
+ }): Promise<{
8
+ id: string;
9
+ external: boolean;
10
+ } | null>;
11
+ warn(message: string): void;
12
+ error(message: string): never;
13
+ }
14
+ export interface NativePlugin {
15
+ name: string;
16
+ idFilter?: {
17
+ load?: string;
18
+ transform?: string;
19
+ resolveId?: string;
20
+ };
21
+ load?: (this: NativePluginContext, id: string) => unknown;
22
+ transform?: (this: NativePluginContext, code: string, id: string, moduleType: string) => unknown;
23
+ resolveId?: (this: NativePluginContext, specifier: string, importer: string | undefined, opts: {
24
+ isEntry: boolean;
25
+ }) => unknown;
26
+ renderChunk?: (this: NativePluginContext, code: string, chunk: {
27
+ fileName: string;
28
+ name: string;
29
+ isEntry: boolean;
30
+ }) => unknown;
31
+ banner?: (this: NativePluginContext, chunk: {
32
+ fileName: string;
33
+ name: string;
34
+ isEntry: boolean;
35
+ }) => unknown;
36
+ footer?: (this: NativePluginContext, chunk: {
37
+ fileName: string;
38
+ name: string;
39
+ isEntry: boolean;
40
+ }) => unknown;
41
+ intro?: (this: NativePluginContext, chunk: {
42
+ fileName: string;
43
+ name: string;
44
+ isEntry: boolean;
45
+ }) => unknown;
46
+ outro?: (this: NativePluginContext, chunk: {
47
+ fileName: string;
48
+ name: string;
49
+ isEntry: boolean;
50
+ }) => unknown;
51
+ buildStart?: (this: NativePluginContext) => unknown;
52
+ buildEnd?: (this: NativePluginContext) => unknown;
53
+ generateBundle?: (this: NativePluginContext) => unknown;
54
+ writeBundle?: (this: NativePluginContext) => unknown;
55
+ closeBundle?: (this: NativePluginContext) => unknown;
56
+ }
57
+ /**
58
+ * In-memory bundle used by `--globals auto` for AST-driven detection.
59
+ * Mirrors the shape of `AnalysisBundler` in
60
+ * `@gjsify/rolldown-plugin-gjsify/utils/auto-globals`. Routes through the
61
+ * same engine as the final build (npm rolldown on Node, native on GJS) so
62
+ * the GJS-bundled CLI doesn't try to load the unloadable npm crate.
63
+ */
64
+ export declare function bundleToChunks(input: {
65
+ rolldownInput: import('rolldown').InputOptions;
66
+ format: 'esm' | 'cjs' | 'iife';
67
+ }): Promise<string[]>;
68
+ /**
69
+ * Run a bundle with the picked engine. Drop-in replacement for the
70
+ * `rolldown(opts).write(opts.output)` flow used directly in build.ts.
71
+ */
72
+ export declare function runBundle(finalOpts: BundlerOptions): Promise<RolldownOutput>;
73
+ export declare function shouldUseNative(): Promise<boolean>;
74
+ export type PluginRecord = {
75
+ name?: string;
76
+ [k: string]: unknown;
77
+ };
78
+ export declare function isPluginObject(p: unknown): p is PluginRecord;
79
+ export declare function toNativePlugin(p: PluginRecord): NativePlugin;
@@ -0,0 +1,436 @@
1
+ // Phase D-2.B.5b — runtime bundler pick.
2
+ //
3
+ // Default behavior: call npm `rolldown(opts).write(opts.output)` exactly
4
+ // as before. Setting `GJSIFY_BUNDLER=native` opts into the
5
+ // `@gjsify/rolldown-native` Vala/Rust prebuild via `bundleWithPlugins()`.
6
+ //
7
+ // The native path is only attempted under GJS — under Node it falls
8
+ // back to npm rolldown silently. Under GJS, if the prebuild isn't
9
+ // loadable for the running architecture, we throw so the caller
10
+ // notices the configuration mismatch instead of silently using a
11
+ // different code path.
12
+ //
13
+ // Plugin shape conversion: rolldown plugins may declare hooks either
14
+ // as bare functions (`load(id)`) or as `{filter, handler}` objects.
15
+ // Both shapes are translated to `NativePlugin` form. `filter.id`
16
+ // regex/string sources become `idFilter.<hook>` regex strings on the
17
+ // Rust side. `this.resolve()` / `this.warn()` / `this.error()` calls
18
+ // inside hook handlers route through the B.3 nested protocol.
19
+ //
20
+ // Plugins that depend on rolldown context methods we don't implement
21
+ // (`this.parse`, `this.emitFile`, `this.getModuleInfo`, …) will fail
22
+ // at hook-call time. The current gjsify plugin set doesn't use any
23
+ // of those, so we don't gate on it; future incompatibilities surface
24
+ // as build errors rather than silent wrong behavior.
25
+ import { promises as fs } from 'node:fs';
26
+ import * as path from 'node:path';
27
+ import { createRequire } from 'node:module';
28
+ import { pathToFileURL } from 'node:url';
29
+ // npm `rolldown` is a Rust crate with platform-specific prebuilds; loading
30
+ // it eagerly at module init pulls musl-detection code that does
31
+ // `require('node:fs')` synchronously — fine on Node, but fatal under GJS
32
+ // where the createRequire polyfill rejects synchronous builtin loads.
33
+ // Dynamic import keeps it off the GJS code path entirely; the native
34
+ // branch (`@gjsify/rolldown-native`) handles bundling there.
35
+ async function loadNpmRolldown() {
36
+ // Indirect specifier so Rolldown's static-analysis doesn't try to
37
+ // bundle the npm crate into a GJS target build.
38
+ const specifier = 'rolldown';
39
+ const mod = (await import(/* @vite-ignore */ specifier));
40
+ return mod.rolldown;
41
+ }
42
+ /**
43
+ * In-memory bundle used by `--globals auto` for AST-driven detection.
44
+ * Mirrors the shape of `AnalysisBundler` in
45
+ * `@gjsify/rolldown-plugin-gjsify/utils/auto-globals`. Routes through the
46
+ * same engine as the final build (npm rolldown on Node, native on GJS) so
47
+ * the GJS-bundled CLI doesn't try to load the unloadable npm crate.
48
+ */
49
+ export async function bundleToChunks(input) {
50
+ if (await shouldUseNative()) {
51
+ const native = await tryLoadNative();
52
+ if (!native)
53
+ throw new Error('@gjsify/rolldown-native not loadable');
54
+ const rawPlugins = (input.rolldownInput.plugins ?? []);
55
+ const nativePlugins = [];
56
+ for (const p of rawPlugins) {
57
+ if (isPluginObject(p))
58
+ nativePlugins.push(toNativePlugin(p));
59
+ }
60
+ const opts = liftTransformExtras(stripUnserializable({
61
+ ...input.rolldownInput,
62
+ input: normalizeInputForNative(input.rolldownInput.input),
63
+ format: input.format,
64
+ }));
65
+ delete opts.plugins;
66
+ const result = await native.bundleWithPlugins(opts, nativePlugins);
67
+ const codes = [];
68
+ for (const item of result.output) {
69
+ if (item.type === 'chunk')
70
+ codes.push(item.code);
71
+ }
72
+ return codes;
73
+ }
74
+ const rolldown = await loadNpmRolldown();
75
+ const build = await rolldown(input.rolldownInput);
76
+ try {
77
+ const result = await build.generate({ format: input.format, minify: false, sourcemap: false });
78
+ const codes = [];
79
+ for (const entry of result.output) {
80
+ if (entry.type === 'chunk')
81
+ codes.push(entry.code);
82
+ }
83
+ return codes;
84
+ }
85
+ finally {
86
+ await build.close();
87
+ }
88
+ }
89
+ /**
90
+ * Run a bundle with the picked engine. Drop-in replacement for the
91
+ * `rolldown(opts).write(opts.output)` flow used directly in build.ts.
92
+ */
93
+ export async function runBundle(finalOpts) {
94
+ if (await shouldUseNative()) {
95
+ return await runNativeBundle(finalOpts);
96
+ }
97
+ const rolldown = await loadNpmRolldown();
98
+ const build = await rolldown(finalOpts);
99
+ try {
100
+ return await build.write(finalOpts.output ?? {});
101
+ }
102
+ finally {
103
+ await build.close();
104
+ }
105
+ }
106
+ let _nativeProbe = null;
107
+ export async function shouldUseNative() {
108
+ const env = globalThis.process?.env ?? {};
109
+ const choice = env.GJSIFY_BUNDLER;
110
+ // Explicit env-var override always wins.
111
+ if (choice === 'npm')
112
+ return false;
113
+ if (choice === 'native') {
114
+ const native = await tryLoadNative();
115
+ if (!native) {
116
+ throw new Error('GJSIFY_BUNDLER=native but @gjsify/rolldown-native is not loadable (no prebuild for this architecture, or not running under GJS).');
117
+ }
118
+ return true;
119
+ }
120
+ // Phase D-3.1 — runtime-aware default.
121
+ // Node: use npm rolldown (no FFI loading cost at install time).
122
+ // GJS: try @gjsify/rolldown-native — it's the only engine
123
+ // that can actually run here (npm rolldown is a Rust
124
+ // crate). Fall back to npm only on Node.
125
+ const isGjs = typeof globalThis.imports?.gi !== 'undefined';
126
+ if (!isGjs)
127
+ return false;
128
+ const native = await tryLoadNative();
129
+ return native !== null;
130
+ }
131
+ async function tryLoadNative() {
132
+ if (_nativeProbe)
133
+ return _nativeProbe;
134
+ _nativeProbe = (async () => {
135
+ const isGjs = typeof globalThis.imports?.gi !== 'undefined';
136
+ if (!isGjs)
137
+ return null;
138
+ try {
139
+ // Under GJS the ESM loader has no node_modules resolver — a bare
140
+ // `import('@gjsify/rolldown-native')` would throw `Module not
141
+ // found`. Resolve via createRequire (PnP+node_modules-aware) to
142
+ // a real path, then dynamic-import the resulting file:// URL.
143
+ // Under Node a bare specifier import works directly, so we keep
144
+ // the simpler form there.
145
+ //
146
+ // `createRequire` + `pathToFileURL` are statically imported at
147
+ // the top of this file so the GJS bundle inlines them via
148
+ // `@gjsify/module` / `@gjsify/url`. A *dynamic* `import('node:…')`
149
+ // would instead hit the GJS native ESM loader which doesn't
150
+ // know the `node:` URI scheme and throws — silently swallowed
151
+ // by the surrounding catch, leaving the caller to fall back
152
+ // to npm rolldown (which then throws ImportError for `rolldown`).
153
+ const specifier = '@gjsify/rolldown-native';
154
+ let target = specifier;
155
+ if (isGjs) {
156
+ const require = createRequire(import.meta.url);
157
+ const resolved = require.resolve(specifier);
158
+ target = pathToFileURL(resolved).href;
159
+ }
160
+ const mod = (await import(/* @vite-ignore */ target));
161
+ if (!mod.hasNativeRolldown())
162
+ return null;
163
+ return mod;
164
+ }
165
+ catch {
166
+ return null;
167
+ }
168
+ })();
169
+ return _nativeProbe;
170
+ }
171
+ async function runNativeBundle(finalOpts) {
172
+ const native = await tryLoadNative();
173
+ if (!native) {
174
+ throw new Error('@gjsify/rolldown-native not loadable');
175
+ }
176
+ const rawPlugins = (finalOpts.plugins ?? []);
177
+ const nativePlugins = [];
178
+ for (const p of rawPlugins) {
179
+ if (isPluginObject(p))
180
+ nativePlugins.push(toNativePlugin(p));
181
+ }
182
+ // Strip plugins from opts — bundleWithPlugins gets them as a
183
+ // separate argument and the Rust side wires them into rolldown's
184
+ // own plugin chain. Normalize `input` to the Rust deserializer's
185
+ // expected `InputItem[]` shape, and flatten `output: { … }` (npm
186
+ // rolldown's JS-side shape) into the top-level keys the Rust
187
+ // BundlerOptions deserializer expects.
188
+ const { output: outputOpts, plugins: _droppedPlugins, ...rest } = finalOpts;
189
+ void _droppedPlugins;
190
+ const bundlerOpts = liftTransformExtras(stripUnserializable({
191
+ ...rest,
192
+ ...(outputOpts ?? {}),
193
+ input: normalizeInputForNative(finalOpts.input),
194
+ }));
195
+ if (globalThis.process?.env?.GJSIFY_DEBUG_NATIVE_OPTS) {
196
+ // Debug switch to inspect the shape we ship to the native facade —
197
+ // mismatches surface as Rust serde parse errors that point at column
198
+ // numbers in this JSON.
199
+ console.error('[gjsify-bundler-pick] native opts JSON:', JSON.stringify(bundlerOpts));
200
+ }
201
+ const result = await native.bundleWithPlugins(bundlerOpts, nativePlugins);
202
+ // The native facade returns the BundleOutput shape but doesn't
203
+ // write files — replicate `.write()` here so callers see the same
204
+ // on-disk layout whether they used npm rolldown or native.
205
+ const outputCfg = (finalOpts.output ?? {});
206
+ const outDir = outputCfg.dir ?? (outputCfg.file ? path.dirname(outputCfg.file) : process.cwd());
207
+ if (outDir)
208
+ await fs.mkdir(outDir, { recursive: true });
209
+ for (const item of result.output) {
210
+ if (item.type === 'chunk') {
211
+ const target = outputCfg.file && result.output.length === 1
212
+ ? outputCfg.file
213
+ : path.join(outDir, item.fileName);
214
+ await fs.writeFile(target, item.code, 'utf8');
215
+ }
216
+ }
217
+ // Synthesize the RolldownOutput shape downstream code touches.
218
+ return synthRolldownOutput(result);
219
+ }
220
+ /**
221
+ * Drop fields the JSON encoder can't ship to the Rust deserializer.
222
+ * `external` may be a function predicate (npm rolldown supports this);
223
+ * functions vanish under `JSON.stringify` and surface as parse errors on
224
+ * the Rust side. Strip top-level function values so the option object
225
+ * is JSON-clean. (The actual external behavior under native rolldown
226
+ * comes from arrays/regex strings, set elsewhere by the orchestrator.)
227
+ *
228
+ * Also drops `sourcemap: false` — the JS API accepts a boolean while
229
+ * the Rust deserializer expects an enum (`'File' | 'Inline' | 'Hidden'`).
230
+ * Omitting the field has the same effect as `false`.
231
+ */
232
+ function stripUnserializable(opts) {
233
+ const out = {};
234
+ for (const [k, v] of Object.entries(opts)) {
235
+ if (typeof v === 'function')
236
+ continue;
237
+ if (k === 'sourcemap' && typeof v === 'boolean')
238
+ continue;
239
+ out[k] = v;
240
+ }
241
+ return out;
242
+ }
243
+ /**
244
+ * The Rust deserializer in the native facade treats `define` and `inject`
245
+ * as top-level fields on `BundlerOptions`, while npm rolldown's JS API
246
+ * groups them under `transform.{define,inject}`. Lift them out so the
247
+ * orchestrator's shape (built around the JS API) is accepted by the Rust
248
+ * side too. Other transform sub-options (`target`, `dropLabels`, …) stay
249
+ * where they are because they are real TransformOptions fields.
250
+ */
251
+ function liftTransformExtras(opts) {
252
+ const transform = opts['transform'];
253
+ if (!transform)
254
+ return opts;
255
+ const lift = {};
256
+ const remaining = { ...transform };
257
+ for (const key of ['define', 'inject']) {
258
+ if (key in remaining) {
259
+ lift[key] = remaining[key];
260
+ delete remaining[key];
261
+ }
262
+ }
263
+ // `inject` shape diverges between engines: npm rolldown accepts a map
264
+ // `{ alias: 'module' | [module, named] }`; the native Rust deserializer
265
+ // expects an array of named-import descriptors. Convert if needed.
266
+ if (lift['inject'] !== undefined && !Array.isArray(lift['inject'])) {
267
+ lift['inject'] = mapToInjectArray(lift['inject']);
268
+ }
269
+ return {
270
+ ...opts,
271
+ transform: Object.keys(remaining).length === 0 ? undefined : remaining,
272
+ ...lift,
273
+ };
274
+ }
275
+ function mapToInjectArray(map) {
276
+ const out = [];
277
+ for (const [alias, value] of Object.entries(map)) {
278
+ if (typeof value === 'string') {
279
+ // Default-import binding: `import alias from 'module'`
280
+ out.push({ type: 'default', from: value, alias });
281
+ }
282
+ else {
283
+ // Named-import binding: `import { imported as alias } from 'from'`
284
+ const [from, imported] = value;
285
+ out.push({ type: 'named', from, imported, alias });
286
+ }
287
+ }
288
+ return out;
289
+ }
290
+ /**
291
+ * The native rolldown facade's Rust deserializer requires
292
+ * `input: BundleInputItem[]` (i.e. `[{ import, name? }]`). Normalize the
293
+ * other shapes npm rolldown accepts (string, string[], record) into that
294
+ * shape so callers can pass either engine the same options object.
295
+ */
296
+ function normalizeInputForNative(input) {
297
+ if (input === undefined)
298
+ return [];
299
+ if (typeof input === 'string')
300
+ return [{ import: input }];
301
+ if (Array.isArray(input)) {
302
+ return input.map((v) => typeof v === 'string' ? { import: v } : v);
303
+ }
304
+ return Object.entries(input).map(([name, file]) => ({ name, import: file }));
305
+ }
306
+ export function isPluginObject(p) {
307
+ return p !== null && typeof p === 'object' && !Array.isArray(p);
308
+ }
309
+ function pickHook(raw) {
310
+ if (typeof raw === 'function')
311
+ return { fn: raw };
312
+ if (raw !== null && typeof raw === 'object' && 'handler' in raw) {
313
+ const obj = raw;
314
+ const idFilter = filterToRegexSource(obj.filter?.id);
315
+ const out = { fn: obj.handler };
316
+ if (idFilter !== undefined)
317
+ out.idFilter = idFilter;
318
+ return out;
319
+ }
320
+ return undefined;
321
+ }
322
+ function filterToRegexSource(f) {
323
+ if (f === undefined)
324
+ return undefined;
325
+ if (Array.isArray(f)) {
326
+ const sources = f.map(oneToSource).filter((x) => x !== undefined);
327
+ return sources.length === 0 ? undefined : sources.length === 1 ? sources[0] : `(?:${sources.join('|')})`;
328
+ }
329
+ return oneToSource(f);
330
+ }
331
+ function oneToSource(f) {
332
+ if (f instanceof RegExp)
333
+ return f.source;
334
+ if (typeof f === 'string') {
335
+ // Treat plain strings as substring match. Escape regex metas
336
+ // so glob-like inputs don't accidentally turn into wild
337
+ // regexes.
338
+ return f.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
339
+ }
340
+ return undefined;
341
+ }
342
+ export function toNativePlugin(p) {
343
+ const name = typeof p.name === 'string' ? p.name : 'unnamed-plugin';
344
+ const out = { name };
345
+ const idFilter = {};
346
+ const load = pickHook(p.load);
347
+ if (load) {
348
+ out.load = load.fn;
349
+ if (load.idFilter)
350
+ idFilter.load = load.idFilter;
351
+ }
352
+ const transform = pickHook(p.transform);
353
+ if (transform) {
354
+ out.transform = transform.fn;
355
+ if (transform.idFilter)
356
+ idFilter.transform = transform.idFilter;
357
+ }
358
+ const resolveId = pickHook(p.resolveId);
359
+ if (resolveId) {
360
+ out.resolveId = resolveId.fn;
361
+ if (resolveId.idFilter)
362
+ idFilter.resolveId = resolveId.idFilter;
363
+ }
364
+ const renderChunk = pickHook(p.renderChunk);
365
+ if (renderChunk)
366
+ out.renderChunk = renderChunk.fn;
367
+ const banner = pickHook(p.banner);
368
+ if (banner)
369
+ out.banner = banner.fn;
370
+ const footer = pickHook(p.footer);
371
+ if (footer)
372
+ out.footer = footer.fn;
373
+ const intro = pickHook(p.intro);
374
+ if (intro)
375
+ out.intro = intro.fn;
376
+ const outro = pickHook(p.outro);
377
+ if (outro)
378
+ out.outro = outro.fn;
379
+ const buildStart = pickHook(p.buildStart);
380
+ if (buildStart)
381
+ out.buildStart = buildStart.fn;
382
+ const buildEnd = pickHook(p.buildEnd);
383
+ if (buildEnd)
384
+ out.buildEnd = buildEnd.fn;
385
+ const generateBundle = pickHook(p.generateBundle);
386
+ if (generateBundle)
387
+ out.generateBundle = generateBundle.fn;
388
+ const writeBundle = pickHook(p.writeBundle);
389
+ if (writeBundle)
390
+ out.writeBundle = writeBundle.fn;
391
+ const closeBundle = pickHook(p.closeBundle);
392
+ if (closeBundle)
393
+ out.closeBundle = closeBundle.fn;
394
+ if (Object.keys(idFilter).length > 0)
395
+ out.idFilter = idFilter;
396
+ return out;
397
+ }
398
+ function synthRolldownOutput(result) {
399
+ // RolldownOutput's exact shape in the npm types is rich; we fill
400
+ // in what downstream code in `build.ts` actually touches (none of
401
+ // it inspects the output beyond logging the file count today).
402
+ // Cast through unknown to satisfy the structural type without
403
+ // pulling in every internal field.
404
+ return {
405
+ output: result.output.map((item) => {
406
+ if (item.type === 'chunk') {
407
+ return {
408
+ type: 'chunk',
409
+ fileName: item.fileName,
410
+ code: item.code,
411
+ name: item.name,
412
+ isEntry: item.isEntry,
413
+ isDynamicEntry: item.isDynamicEntry,
414
+ map: item.map ?? null,
415
+ sourcemapFileName: item.sourcemapFilename ?? null,
416
+ imports: item.imports,
417
+ dynamicImports: item.dynamicImports,
418
+ facadeModuleId: null,
419
+ moduleIds: [],
420
+ modules: {},
421
+ exports: [],
422
+ referencedFiles: [],
423
+ importedBindings: {},
424
+ };
425
+ }
426
+ return {
427
+ type: 'asset',
428
+ fileName: item.fileName,
429
+ names: item.names,
430
+ originalFileNames: item.originalFileNames,
431
+ source: item.sourceText ?? '',
432
+ needsCodeReference: false,
433
+ };
434
+ }),
435
+ };
436
+ }
@@ -0,0 +1,17 @@
1
+ import type { Command } from '../types/index.js';
2
+ interface ForeachOptions {
3
+ script?: string;
4
+ args?: string[];
5
+ all?: boolean;
6
+ parallel?: boolean;
7
+ topological?: boolean;
8
+ 'topological-dev'?: boolean;
9
+ include?: string[];
10
+ exclude?: string[];
11
+ private?: boolean;
12
+ verbose?: boolean;
13
+ jobs?: number;
14
+ exec?: boolean;
15
+ }
16
+ export declare const foreachCommand: Command<any, ForeachOptions>;
17
+ export {};