@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.
- package/dist/cli.gjs.mjs +798 -0
- package/lib/actions/build.js +4 -17
- package/lib/bundler-pick.d.ts +79 -0
- package/lib/bundler-pick.js +428 -0
- package/lib/commands/foreach.d.ts +16 -0
- package/lib/commands/foreach.js +268 -0
- package/lib/commands/index.d.ts +2 -0
- package/lib/commands/index.js +2 -0
- package/lib/commands/install.d.ts +1 -0
- package/lib/commands/install.js +222 -26
- package/lib/commands/run.d.ts +1 -1
- package/lib/commands/run.js +133 -20
- package/lib/commands/workspace.d.ts +8 -0
- package/lib/commands/workspace.js +69 -0
- package/lib/config.js +12 -1
- package/lib/index.js +11 -3
- package/lib/types/config-data.d.ts +10 -1
- package/lib/utils/install-backend-native.d.ts +5 -1
- package/lib/utils/install-backend-native.js +88 -11
- package/lib/utils/install-backend.d.ts +11 -1
- package/lib/utils/install-backend.js +4 -2
- package/lib/utils/pkg-json-edit.d.ts +47 -0
- package/lib/utils/pkg-json-edit.js +108 -0
- package/package.json +36 -12
- package/src/actions/build.ts +0 -431
- package/src/actions/index.ts +0 -1
- package/src/commands/build.ts +0 -146
- package/src/commands/check.ts +0 -87
- package/src/commands/create.ts +0 -63
- package/src/commands/dlx.ts +0 -195
- package/src/commands/flatpak/build.ts +0 -225
- package/src/commands/flatpak/ci.ts +0 -173
- package/src/commands/flatpak/deps.ts +0 -120
- package/src/commands/flatpak/index.ts +0 -53
- package/src/commands/flatpak/init.ts +0 -191
- package/src/commands/flatpak/utils.ts +0 -76
- package/src/commands/gettext.ts +0 -258
- package/src/commands/gresource.ts +0 -97
- package/src/commands/gsettings.ts +0 -87
- package/src/commands/index.ts +0 -12
- package/src/commands/info.ts +0 -70
- package/src/commands/install.ts +0 -195
- package/src/commands/run.ts +0 -33
- package/src/commands/showcase.ts +0 -149
- package/src/config.ts +0 -304
- package/src/constants.ts +0 -1
- package/src/index.ts +0 -37
- package/src/types/cli-build-options.ts +0 -100
- package/src/types/command.ts +0 -10
- package/src/types/config-data-library.ts +0 -5
- package/src/types/config-data-typescript.ts +0 -6
- package/src/types/config-data.ts +0 -225
- package/src/types/cosmiconfig-result.ts +0 -5
- package/src/types/index.ts +0 -6
- package/src/utils/check-system-deps.ts +0 -480
- package/src/utils/detect-native-packages.ts +0 -153
- package/src/utils/discover-showcases.ts +0 -75
- package/src/utils/dlx-cache.ts +0 -135
- package/src/utils/install-backend-native.ts +0 -363
- package/src/utils/install-backend.ts +0 -88
- package/src/utils/install-global.ts +0 -182
- package/src/utils/normalize-bundler-options.ts +0 -129
- package/src/utils/parse-spec.ts +0 -48
- package/src/utils/resolve-gjs-entry.ts +0 -96
- package/src/utils/resolve-plugin-by-name.ts +0 -106
- package/src/utils/run-gjs.ts +0 -90
- package/tsconfig.json +0 -16
package/lib/actions/build.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
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
|
|
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
|
-
|
|
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 {};
|