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