@gjsify/cli 0.35.0 → 0.37.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 +136 -126
- package/lib/actions/build.d.ts +19 -0
- package/lib/actions/build.js +2 -2
- package/lib/bundler-pick.js +72 -98
- package/lib/cli-fail.d.ts +4 -7
- package/lib/cli-fail.js +29 -55
- package/lib/commands/affected.js +161 -286
- package/lib/commands/install.d.ts +63 -66
- package/lib/commands/install.js +372 -536
- package/lib/commands/run.d.ts +1 -0
- package/lib/commands/run.js +37 -0
- package/lib/templates/install.mjs.tmpl +38 -68
- package/lib/types/cli-build-options.d.ts +33 -67
- package/lib/types/command.d.ts +9 -12
- package/lib/types/config-data.d.ts +125 -221
- package/lib/utils/auth-npmrc.d.ts +5 -10
- package/lib/utils/auth-npmrc.js +11 -21
- package/lib/utils/check-system-deps.d.ts +16 -0
- package/lib/utils/check-system-deps.js +49 -0
- package/lib/utils/clear-targets.d.ts +8 -11
- package/lib/utils/clear-targets.js +22 -29
- package/lib/utils/copy-targets.d.ts +13 -19
- package/lib/utils/copy-targets.js +31 -44
- package/lib/utils/dep-aggregation.d.ts +7 -15
- package/lib/utils/dep-aggregation.js +9 -22
- package/lib/utils/detect-native-packages.d.ts +83 -116
- package/lib/utils/detect-native-packages.js +111 -149
- package/lib/utils/dir-link.d.ts +29 -48
- package/lib/utils/dir-link.js +33 -56
- package/lib/utils/discover-showcases.d.ts +6 -7
- package/lib/utils/discover-showcases.js +11 -15
- package/lib/utils/dlx-cache.d.ts +29 -38
- package/lib/utils/dlx-cache.js +53 -63
- package/lib/utils/force-exit.d.ts +0 -3
- package/lib/utils/force-exit.js +13 -24
- package/lib/utils/gi-search-path.d.ts +16 -24
- package/lib/utils/gi-search-path.js +54 -82
- package/lib/utils/gjs-bundle-guard.d.ts +5 -13
- package/lib/utils/gjs-bundle-guard.js +35 -57
- package/lib/utils/gjs-source-escape.d.ts +2 -2
- package/lib/utils/gjs-source-escape.js +21 -39
- package/lib/utils/gjsify-shim.d.ts +26 -8
- package/lib/utils/gjsify-shim.js +128 -80
- package/lib/utils/html-entry.d.ts +8 -12
- package/lib/utils/html-entry.js +19 -28
- package/lib/utils/install-backend-native.d.ts +123 -161
- package/lib/utils/install-backend-native.js +536 -737
- package/lib/utils/install-backend.d.ts +42 -57
- package/lib/utils/install-backend.js +16 -21
- package/lib/utils/install-cache-fs.d.ts +10 -15
- package/lib/utils/install-cache-fs.js +18 -26
- package/lib/utils/install-lock.d.ts +5 -6
- package/lib/utils/install-lock.js +46 -65
- package/lib/utils/install-packument-cache.d.ts +27 -33
- package/lib/utils/install-packument-cache.js +44 -57
- package/lib/utils/install-progress.d.ts +2 -9
- package/lib/utils/install-progress.js +14 -39
- package/lib/utils/install-tarball-cache.d.ts +14 -20
- package/lib/utils/install-tarball-cache.js +41 -59
- package/lib/utils/library-output.d.ts +9 -22
- package/lib/utils/library-output.js +19 -37
- package/lib/utils/load-npmrc.d.ts +5 -6
- package/lib/utils/load-npmrc.js +18 -27
- package/lib/utils/node-bundle-guard.d.ts +4 -8
- package/lib/utils/node-bundle-guard.js +21 -35
- package/lib/utils/node-script.d.ts +12 -0
- package/lib/utils/node-script.js +95 -0
- package/lib/utils/node-version.d.ts +5 -14
- package/lib/utils/node-version.js +15 -24
- package/lib/utils/normalize-bundler-options.d.ts +7 -11
- package/lib/utils/normalize-bundler-options.js +24 -42
- package/lib/utils/npm-oidc.d.ts +23 -37
- package/lib/utils/npm-oidc.js +28 -53
- package/lib/utils/npm-otp-cache.d.ts +4 -4
- package/lib/utils/npm-otp-cache.js +20 -25
- package/lib/utils/npm-otp.d.ts +20 -30
- package/lib/utils/npm-otp.js +32 -51
- package/lib/utils/onboard-probe.d.ts +7 -13
- package/lib/utils/onboard-probe.js +16 -27
- package/lib/utils/parse-spec.d.ts +3 -3
- package/lib/utils/parse-spec.js +4 -5
- package/lib/utils/pkg-json-edit.d.ts +7 -12
- package/lib/utils/pkg-json-edit.js +13 -26
- package/lib/utils/pkg-json.d.ts +11 -18
- package/lib/utils/pkg-json.js +19 -28
- package/lib/utils/prefixed-output.d.ts +3 -4
- package/lib/utils/prefixed-output.js +13 -19
- package/lib/utils/prompt.d.ts +3 -4
- package/lib/utils/prompt.js +14 -18
- package/lib/utils/publish-diagnose.d.ts +11 -16
- package/lib/utils/publish-diagnose.js +15 -28
- package/lib/utils/publish-headers.d.ts +7 -11
- package/lib/utils/publish-headers.js +36 -65
- package/lib/utils/publishable-packages.d.ts +4 -6
- package/lib/utils/publishable-packages.js +14 -18
- package/lib/utils/resolve-gjs-entry.d.ts +5 -8
- package/lib/utils/resolve-gjs-entry.js +10 -27
- package/lib/utils/resolve-npm-package.d.ts +6 -11
- package/lib/utils/resolve-npm-package.js +29 -63
- package/lib/utils/resolve-plugin-by-name.d.ts +11 -19
- package/lib/utils/resolve-plugin-by-name.js +9 -14
- package/lib/utils/run-gjs.d.ts +19 -17
- package/lib/utils/run-gjs.js +37 -51
- package/lib/utils/run-lifecycle-script.d.ts +5 -9
- package/lib/utils/run-lifecycle-script.js +23 -42
- package/lib/utils/run-node.d.ts +23 -33
- package/lib/utils/run-node.js +56 -60
- package/lib/utils/runtimes.d.ts +25 -35
- package/lib/utils/runtimes.js +34 -46
- package/lib/utils/spawn.d.ts +32 -48
- package/lib/utils/spawn.js +51 -84
- package/lib/utils/stdin.d.ts +2 -2
- package/lib/utils/stdin.js +10 -25
- package/lib/utils/suggest.d.ts +6 -7
- package/lib/utils/suggest.js +8 -10
- package/lib/utils/system-gi.d.ts +18 -27
- package/lib/utils/system-gi.js +60 -114
- package/lib/utils/trust-registry.d.ts +4 -8
- package/lib/utils/trust-registry.js +7 -15
- package/lib/utils/win32-command.d.ts +8 -14
- package/lib/utils/win32-command.js +29 -43
- package/lib/utils/workspace-root.js +7 -12
- package/package.json +18 -17
- package/showcases.json +6 -0
package/lib/utils/run-node.js
CHANGED
|
@@ -1,26 +1,20 @@
|
|
|
1
1
|
// Shared utility for running a `--app node` bundle on Node.js with the native
|
|
2
2
|
// typelib env wired the same way `runGjsBundle` does.
|
|
3
3
|
//
|
|
4
|
-
// A
|
|
5
|
-
//
|
|
6
|
-
// true at runtime:
|
|
4
|
+
// A `--app node` bundle of a `gi://` source runs the GObject stack through `@gjsify/node-gi`
|
|
5
|
+
// (the Axis-5 reverse bridge). Two things must hold at runtime:
|
|
7
6
|
//
|
|
8
|
-
// 1. `@gjsify/node-gi` must resolve FROM THE BUNDLE —
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
//
|
|
16
|
-
// ships its typelib in `prebuilds/` — so we reuse the SAME
|
|
17
|
-
// `computeNativeEnvForBundle()` walker `runGjsBundle` uses to prepend
|
|
18
|
-
// `GI_TYPELIB_PATH` / `LD_LIBRARY_PATH`. It is a no-op when no native
|
|
19
|
-
// gjsify packages are present (the storybook's common case).
|
|
7
|
+
// 1. `@gjsify/node-gi` must resolve FROM THE BUNDLE — the bundler keeps it EXTERNAL (native
|
|
8
|
+
// addon), so it has to physically exist in a node_modules the bundle's own directory can
|
|
9
|
+
// reach, with the CWD as a fallback. Checked up front so the failure is a clear hint
|
|
10
|
+
// rather than an `ERR_MODULE_NOT_FOUND` deep in the bundle (`resolveNodeGiForBundle`).
|
|
11
|
+
// 2. `gi://Gtk` / `gi://Adw` must resolve. System typelibs come from the default GI search
|
|
12
|
+
// path, but an `@gjsify/*` Vala bridge ships its typelib in `prebuilds/`, so the SAME
|
|
13
|
+
// `computeNativeEnvForBundle()` walker `runGjsBundle` uses prepends `GI_TYPELIB_PATH` /
|
|
14
|
+
// `LD_LIBRARY_PATH`. A no-op when no native gjsify packages are present.
|
|
20
15
|
//
|
|
21
|
-
// The node binary is `process.execPath` when the CLI
|
|
22
|
-
// the
|
|
23
|
-
// `gjs`, which cannot run a `--app node` bundle).
|
|
16
|
+
// The node binary is `process.execPath` when the CLI runs under Node, else PATH `node` — under
|
|
17
|
+
// the GJS bundle `process.execPath` is `gjs`, which cannot run a `--app node` bundle.
|
|
24
18
|
import { spawn } from 'node:child_process';
|
|
25
19
|
import { existsSync, readFileSync } from 'node:fs';
|
|
26
20
|
import { dirname, join, resolve } from 'node:path';
|
|
@@ -28,10 +22,8 @@ import { isNode } from '@gjsify/rolldown-plugin-gjsify/runtime';
|
|
|
28
22
|
import { computeNativeEnvForBundle } from './run-gjs.js';
|
|
29
23
|
import { RUNTIMES } from './runtimes.js';
|
|
30
24
|
/**
|
|
31
|
-
* Walk up from `startDir`
|
|
32
|
-
*
|
|
33
|
-
* A plain fs walk (works identically on Node and GJS) — Node's own resolver is
|
|
34
|
-
* not available under the GJS-bundled CLI.
|
|
25
|
+
* Walk up from `startDir` for `<node_modules>/@gjsify/node-gi`, returning its package directory
|
|
26
|
+
* or null. A plain fs walk because Node's own resolver is not available under the GJS-bundled CLI.
|
|
35
27
|
*/
|
|
36
28
|
export function resolveNodeGi(startDir) {
|
|
37
29
|
let dir = resolve(startDir);
|
|
@@ -46,19 +38,15 @@ export function resolveNodeGi(startDir) {
|
|
|
46
38
|
}
|
|
47
39
|
}
|
|
48
40
|
/**
|
|
49
|
-
* Resolve `@gjsify/node-gi` for a bundle
|
|
50
|
-
*
|
|
41
|
+
* Resolve `@gjsify/node-gi` for a bundle about to launch: the BUNDLE's own directory first, then
|
|
42
|
+
* `cwd`.
|
|
51
43
|
*
|
|
52
|
-
* The bundle's directory is the correct base
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
* sitting right beside the bundle and nothing at all under the user's cwd, so a
|
|
59
|
-
* cwd-only probe rejected a run that would have worked. The cwd probe is kept
|
|
60
|
-
* because a project-local `node_modules` legitimately satisfies a bundle built
|
|
61
|
-
* into a `dist/` outside it (a `--outfile /tmp/…` build from a project root).
|
|
44
|
+
* The bundle's directory is the correct base for the same reason {@link computeNativeEnvForBundle}
|
|
45
|
+
* walks both: node-gi is kept EXTERNAL, so what must be satisfiable is the RUNTIME's resolution
|
|
46
|
+
* of a bare specifier from inside the bundle, which Node performs relative to the importing file,
|
|
47
|
+
* never to cwd. A dlx-cache layout has node-gi beside the bundle and nothing under the user's
|
|
48
|
+
* cwd, so a cwd-only probe rejected a run that would have worked. The cwd probe stays because a
|
|
49
|
+
* project-local `node_modules` legitimately satisfies a bundle built into a `dist/` outside it.
|
|
62
50
|
*/
|
|
63
51
|
export function resolveNodeGiForBundle(bundlePath, cwd) {
|
|
64
52
|
const resolvedBundle = resolve(bundlePath);
|
|
@@ -69,10 +57,8 @@ export function nodeBinary() {
|
|
|
69
57
|
return isNode() && process.execPath ? process.execPath : 'node';
|
|
70
58
|
}
|
|
71
59
|
/**
|
|
72
|
-
* Run a `--app node` bundle on Node.js
|
|
73
|
-
*
|
|
74
|
-
* {@link runGjsBundle}). Verifies `@gjsify/node-gi` is resolvable first and
|
|
75
|
-
* throws a clear, actionable error otherwise.
|
|
60
|
+
* Run a `--app node` bundle on Node.js with the native typelib env set (same detection as
|
|
61
|
+
* {@link runGjsBundle}). Throws when `@gjsify/node-gi` is not resolvable.
|
|
76
62
|
*/
|
|
77
63
|
export async function runNodeBundle(bundlePath, extraArgs = [], options = {}) {
|
|
78
64
|
const cwd = process.cwd();
|
|
@@ -85,8 +71,7 @@ export async function runNodeBundle(bundlePath, extraArgs = [], options = {}) {
|
|
|
85
71
|
const env = { ...process.env, ...nativeEnv };
|
|
86
72
|
const nodeBin = nodeBinary();
|
|
87
73
|
const nodeArgs = [bundlePath, ...extraArgs];
|
|
88
|
-
// Echo
|
|
89
|
-
// stays uncontaminated) so users can reproduce the run without the wrapper.
|
|
74
|
+
// Echo on stderr, so a child speaking a protocol on stdout stays uncontaminated.
|
|
90
75
|
const cmd = [nodeBin, ...nodeArgs.map((a) => (a.includes(' ') ? `"${a}"` : a))].join(' ');
|
|
91
76
|
console.error(`$ ${envPrefix ? `${envPrefix} ` : ''}${cmd}`);
|
|
92
77
|
const child = spawn(nodeBin, nodeArgs, { env, stdio: 'inherit' });
|
|
@@ -106,11 +91,10 @@ export async function runNodeBundle(bundlePath, extraArgs = [], options = {}) {
|
|
|
106
91
|
process.exit(0);
|
|
107
92
|
}
|
|
108
93
|
/**
|
|
109
|
-
* Whether a `--app node` bundle actually consumes `@gjsify/node-gi`
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
* conditional on this, not unconditional like the storybook path.
|
|
94
|
+
* Whether a `--app node` bundle actually consumes `@gjsify/node-gi` — kept EXTERNAL, so a bundle
|
|
95
|
+
* using gi:// imports the shim by name. A plain Node app does NOT, and must run on node/bun/deno
|
|
96
|
+
* WITHOUT node-gi installed, which is why the check is conditional here and not unconditional
|
|
97
|
+
* like the storybook path.
|
|
114
98
|
*/
|
|
115
99
|
export function bundleRequiresNodeGi(bundlePath) {
|
|
116
100
|
try {
|
|
@@ -121,15 +105,12 @@ export function bundleRequiresNodeGi(bundlePath) {
|
|
|
121
105
|
}
|
|
122
106
|
}
|
|
123
107
|
/**
|
|
124
|
-
* Run a built bundle on a non-gjs runtime (node / bun / deno). All three consume
|
|
125
|
-
*
|
|
126
|
-
*
|
|
127
|
-
* node
|
|
128
|
-
* (so a bundle pulling an `@gjsify/*` Vala bridge resolves its prebuild), and
|
|
129
|
-
* `@gjsify/node-gi` is required ONLY when the bundle actually uses gi://.
|
|
108
|
+
* Run a built bundle on a non-gjs runtime (node / bun / deno). All three consume the SAME
|
|
109
|
+
* `--app node` bundle — Node-API is their common ABI — so this is the shared launcher for
|
|
110
|
+
* `gjsify run --runtime` and `gjsify showcase --runtime`. Native typelib env is wired as in
|
|
111
|
+
* {@link runGjsBundle}; `@gjsify/node-gi` is required ONLY when the bundle actually uses gi://.
|
|
130
112
|
*
|
|
131
|
-
* `gjs` is intentionally NOT handled here — the caller dispatches it to
|
|
132
|
-
* {@link runGjsBundle}.
|
|
113
|
+
* `gjs` is intentionally NOT handled here — the caller dispatches it to {@link runGjsBundle}.
|
|
133
114
|
*/
|
|
134
115
|
export async function runRuntimeBundle(runtime, bundlePath, extraArgs = [], options = {}) {
|
|
135
116
|
const cwd = process.cwd();
|
|
@@ -141,27 +122,42 @@ export async function runRuntimeBundle(runtime, bundlePath, extraArgs = [], opti
|
|
|
141
122
|
}
|
|
142
123
|
const { env: nativeEnv, envPrefix } = computeNativeEnvForBundle(resolvedBundle, cwd);
|
|
143
124
|
const env = { ...process.env, ...nativeEnv };
|
|
144
|
-
//
|
|
145
|
-
//
|
|
146
|
-
//
|
|
125
|
+
// The shared RUNTIMES launch spec supplies the argv (deno's `--node-modules-dir=manual`
|
|
126
|
+
// etc.); the `node` runtime substitutes the resolved binary, since under a GJS-hosted CLI
|
|
127
|
+
// `process.execPath` is gjs.
|
|
147
128
|
const [, launchArgs] = RUNTIMES[runtime].launch(resolvedBundle, extraArgs);
|
|
148
129
|
const cmd = runtime === 'node' ? nodeBinary() : RUNTIMES[runtime].probe;
|
|
149
130
|
// Echo on stderr so a child speaking a protocol on stdout stays clean.
|
|
150
131
|
const shown = [cmd, ...launchArgs.map((a) => (a.includes(' ') ? `"${a}"` : a))].join(' ');
|
|
151
|
-
|
|
132
|
+
if (!options.quiet)
|
|
133
|
+
console.error(`$ ${envPrefix ? `${envPrefix} ` : ''}${shown}`);
|
|
152
134
|
const child = spawn(cmd, launchArgs, { env, stdio: 'inherit' });
|
|
135
|
+
// Re-raise the CHILD's own code rather than a blanket 1 — a script run through
|
|
136
|
+
// `--node-script` reports its status through this path, and a caller reading `$?` needs
|
|
137
|
+
// the real one.
|
|
138
|
+
let failed = false;
|
|
139
|
+
let childCode = 1;
|
|
153
140
|
await new Promise((resolvePromise, reject) => {
|
|
154
141
|
child.on('close', (code) => {
|
|
155
|
-
if (code !== 0)
|
|
142
|
+
if (code !== 0) {
|
|
143
|
+
childCode = code ?? 1;
|
|
156
144
|
reject(new Error(`${runtime} exited with code ${code}`));
|
|
145
|
+
}
|
|
157
146
|
else
|
|
158
147
|
resolvePromise();
|
|
159
148
|
});
|
|
160
149
|
child.on('error', reject);
|
|
161
150
|
}).catch((err) => {
|
|
162
151
|
console.error(err.message);
|
|
163
|
-
|
|
152
|
+
failed = true;
|
|
164
153
|
});
|
|
154
|
+
// `return process.exit(…)`, and a flag rather than an exit inside the `catch`: under GJS
|
|
155
|
+
// `process.exit()` is deferred and RETURNS, so a bare call in the catch fell through to the
|
|
156
|
+
// `exitOnSuccess` line below and scheduled a second exit.
|
|
157
|
+
if (failed) {
|
|
158
|
+
process.exitCode = childCode;
|
|
159
|
+
return process.exit(childCode);
|
|
160
|
+
}
|
|
165
161
|
if (options.exitOnSuccess)
|
|
166
|
-
process.exit(0);
|
|
162
|
+
return process.exit(0);
|
|
167
163
|
}
|
package/lib/utils/runtimes.d.ts
CHANGED
|
@@ -16,10 +16,9 @@ export interface RuntimeSpec {
|
|
|
16
16
|
readonly launch: (entry: string, extraArgs?: readonly string[]) => [string, string[]];
|
|
17
17
|
}
|
|
18
18
|
/**
|
|
19
|
-
* The runtime map — the generalization of the node-gi harness's `RUNTIMES`.
|
|
20
19
|
* `deno` uses `--node-modules-dir=manual`: `auto` would re-resolve the example's
|
|
21
|
-
* heavy build-time dep tree (`@gjsify/cli` + platform binaries) and hang, when
|
|
22
|
-
*
|
|
20
|
+
* heavy build-time dep tree (`@gjsify/cli` + platform binaries) and hang, when the
|
|
21
|
+
* app only needs the already-linked runtime dep `@gjsify/node-gi`.
|
|
23
22
|
*/
|
|
24
23
|
export declare const RUNTIMES: Record<ExampleRuntime, RuntimeSpec>;
|
|
25
24
|
/** Type guard: is `value` one of the four known runtimes? */
|
|
@@ -34,22 +33,18 @@ export declare function buildAppForRuntime(runtime: ExampleRuntime): 'gjs' | 'no
|
|
|
34
33
|
* `--app gjs` bundle" and "needs a gjs interpreter" are the same fact, and a
|
|
35
34
|
* hand-written second list drifts the first time a runtime is added.
|
|
36
35
|
*
|
|
37
|
-
* The caller must resolve the runtime BEFORE gating on it.
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
* "Missing system dependencies: ✗ GJS" before reaching the
|
|
41
|
-
* branch that never touches gjs
|
|
42
|
-
* without gjs (Windows, plain Node/bun/deno) — including the default path,
|
|
43
|
-
* since `defaultExampleRuntime()` falls back to the host runtime for exactly
|
|
44
|
-
* those hosts.
|
|
36
|
+
* The caller must resolve the runtime BEFORE gating on it. Calling
|
|
37
|
+
* `runMinimalChecks()` (which marks `gjs` `required`) above the line that resolves
|
|
38
|
+
* `args.runtime` made every showcase unreachable on a host without gjs — `--runtime
|
|
39
|
+
* node` aborted with "Missing system dependencies: ✗ GJS" before reaching the
|
|
40
|
+
* branch that never touches gjs, the default path included.
|
|
45
41
|
*/
|
|
46
42
|
export declare function requiresGjsSystemDeps(runtime: ExampleRuntime): boolean;
|
|
47
43
|
/** Whether `<probe> --version` succeeds (i.e. the runtime binary is on PATH). */
|
|
48
44
|
export declare function isRuntimeOnPath(probe: string): boolean;
|
|
49
45
|
/**
|
|
50
|
-
* Whether a specific runtime is runnable here. The HOST runtime
|
|
51
|
-
*
|
|
52
|
-
* running on it, so no PATH probe is needed. Every other runtime is probed via
|
|
46
|
+
* Whether a specific runtime is runnable here. The HOST runtime needs no PATH probe
|
|
47
|
+
* — the CLI is executing on it; every other runtime is probed via
|
|
53
48
|
* `<binary> --version`.
|
|
54
49
|
*/
|
|
55
50
|
export declare function isRuntimeAvailable(runtime: ExampleRuntime): boolean;
|
|
@@ -59,20 +54,17 @@ export declare function availableRuntimes(): ExampleRuntime[];
|
|
|
59
54
|
* The default `--runtime` for running a prebuilt EXAMPLE/SHOWCASE: `gjs`
|
|
60
55
|
* whenever gjs is runnable here, else the host runtime.
|
|
61
56
|
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
* the primary documented entry point failed on a missing file.
|
|
57
|
+
* Deliberately NOT a plain `hostRuntime()`. A showcase's canonical artifact is its
|
|
58
|
+
* `--app gjs` bundle (`gjsify.main`) — what every showcase ships and what `gjsify
|
|
59
|
+
* dlx` installs. Following the host instead makes `npx @gjsify/cli showcase <name>`
|
|
60
|
+
* (host = node) ask for the `--app node` bundle, which most showcases do not ship
|
|
61
|
+
* and which also needs `@gjsify/node-gi` in the consumer's project, so the
|
|
62
|
+
* first-run experience of the primary documented entry point failed on a missing
|
|
63
|
+
* file.
|
|
70
64
|
*
|
|
71
|
-
* Same rule `gjsify run`
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
* of by sniffing the file. `--runtime` still overrides explicitly, and a host
|
|
75
|
-
* WITHOUT gjs (a plain Node/bun/deno box) keeps following the host so the
|
|
65
|
+
* Same rule `gjsify run` applies in its bare-file path (`isLikelyGjsBundle`), with
|
|
66
|
+
* "is it a gjs artifact" answered by the command rather than by sniffing the file.
|
|
67
|
+
* `--runtime` still overrides, and a host WITHOUT gjs keeps following the host so
|
|
76
68
|
* node-capable showcases stay runnable there.
|
|
77
69
|
*/
|
|
78
70
|
export declare function defaultExampleRuntime(): ExampleRuntime;
|
|
@@ -82,10 +74,9 @@ interface ExampleGjsifyField {
|
|
|
82
74
|
};
|
|
83
75
|
}
|
|
84
76
|
/**
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
* error against an older CLI).
|
|
77
|
+
* A package's declared example runtimes, or `null` when it declares none (the
|
|
78
|
+
* permissive case). Unknown entries are dropped so a future runtime name does not
|
|
79
|
+
* hard-error against an older CLI.
|
|
89
80
|
*/
|
|
90
81
|
export declare function readDeclaredRuntimes(pkg: {
|
|
91
82
|
gjsify?: ExampleGjsifyField;
|
|
@@ -96,10 +87,9 @@ export interface RuntimeSupportResult {
|
|
|
96
87
|
message?: string;
|
|
97
88
|
}
|
|
98
89
|
/**
|
|
99
|
-
* Validate a requested runtime against a package's declaration
|
|
100
|
-
* declaration is permissive
|
|
101
|
-
*
|
|
102
|
-
* callers can print it and exit cleanly.
|
|
90
|
+
* Validate a requested runtime against a package's declaration; a `null`
|
|
91
|
+
* declaration is permissive. Returns a message rather than throwing, so callers
|
|
92
|
+
* print it and exit cleanly.
|
|
103
93
|
*/
|
|
104
94
|
export declare function checkRuntimeSupported(runtime: ExampleRuntime, declared: ExampleRuntime[] | null, name: string): RuntimeSupportResult;
|
|
105
95
|
export {};
|
package/lib/utils/runtimes.js
CHANGED
|
@@ -1,27 +1,24 @@
|
|
|
1
1
|
// Shared runtime-selector tooling for running gjsify examples/showcases across
|
|
2
2
|
// the FOUR runtimes gjsify targets: gjs, node, bun, deno.
|
|
3
3
|
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
// in ONE place instead of a per-example copy.
|
|
4
|
+
// Both the CLI (`gjsify run` / `gjsify showcase --runtime`) and the examples (the
|
|
5
|
+
// node-gi `harness.mjs`) consume this, so the RUNTIMES map, the
|
|
6
|
+
// runtime→build-target mapping and `availableRuntimes()` live in ONE place instead
|
|
7
|
+
// of a per-example copy.
|
|
9
8
|
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
// deep-import precedent used by the dlx e2e suites.
|
|
9
|
+
// Intentionally PURE (only `node:child_process` and the side-effect-free
|
|
10
|
+
// `@gjsify/rolldown-plugin-gjsify/runtime` host detector, no `gi://` or native
|
|
11
|
+
// imports) so an external example can deep-import it from the installed CLI
|
|
12
|
+
// (`@gjsify/cli/lib/utils/runtimes.js`) without pulling in the whole bundler — the
|
|
13
|
+
// same deep-import precedent as `@gjsify/cli/lib/utils/run-gjs.js`.
|
|
16
14
|
import { execFileSync } from 'node:child_process';
|
|
17
15
|
import { hostRuntime } from '@gjsify/rolldown-plugin-gjsify/runtime';
|
|
18
16
|
/** All runtimes, in canonical order (gjs first — it is the reference). */
|
|
19
17
|
export const EXAMPLE_RUNTIMES = ['gjs', 'node', 'bun', 'deno'];
|
|
20
18
|
/**
|
|
21
|
-
* The runtime map — the generalization of the node-gi harness's `RUNTIMES`.
|
|
22
19
|
* `deno` uses `--node-modules-dir=manual`: `auto` would re-resolve the example's
|
|
23
|
-
* heavy build-time dep tree (`@gjsify/cli` + platform binaries) and hang, when
|
|
24
|
-
*
|
|
20
|
+
* heavy build-time dep tree (`@gjsify/cli` + platform binaries) and hang, when the
|
|
21
|
+
* app only needs the already-linked runtime dep `@gjsify/node-gi`.
|
|
25
22
|
*/
|
|
26
23
|
export const RUNTIMES = {
|
|
27
24
|
gjs: { probe: 'gjs', buildApp: 'gjs', launch: (e, a = []) => ['gjs', ['-m', e, ...a]] },
|
|
@@ -49,14 +46,11 @@ export function buildAppForRuntime(runtime) {
|
|
|
49
46
|
* `--app gjs` bundle" and "needs a gjs interpreter" are the same fact, and a
|
|
50
47
|
* hand-written second list drifts the first time a runtime is added.
|
|
51
48
|
*
|
|
52
|
-
* The caller must resolve the runtime BEFORE gating on it.
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
* "Missing system dependencies: ✗ GJS" before reaching the
|
|
56
|
-
* branch that never touches gjs
|
|
57
|
-
* without gjs (Windows, plain Node/bun/deno) — including the default path,
|
|
58
|
-
* since `defaultExampleRuntime()` falls back to the host runtime for exactly
|
|
59
|
-
* those hosts.
|
|
49
|
+
* The caller must resolve the runtime BEFORE gating on it. Calling
|
|
50
|
+
* `runMinimalChecks()` (which marks `gjs` `required`) above the line that resolves
|
|
51
|
+
* `args.runtime` made every showcase unreachable on a host without gjs — `--runtime
|
|
52
|
+
* node` aborted with "Missing system dependencies: ✗ GJS" before reaching the
|
|
53
|
+
* branch that never touches gjs, the default path included.
|
|
60
54
|
*/
|
|
61
55
|
export function requiresGjsSystemDeps(runtime) {
|
|
62
56
|
return buildAppForRuntime(runtime) === 'gjs';
|
|
@@ -72,9 +66,8 @@ export function isRuntimeOnPath(probe) {
|
|
|
72
66
|
}
|
|
73
67
|
}
|
|
74
68
|
/**
|
|
75
|
-
* Whether a specific runtime is runnable here. The HOST runtime
|
|
76
|
-
*
|
|
77
|
-
* running on it, so no PATH probe is needed. Every other runtime is probed via
|
|
69
|
+
* Whether a specific runtime is runnable here. The HOST runtime needs no PATH probe
|
|
70
|
+
* — the CLI is executing on it; every other runtime is probed via
|
|
78
71
|
* `<binary> --version`.
|
|
79
72
|
*/
|
|
80
73
|
export function isRuntimeAvailable(runtime) {
|
|
@@ -88,30 +81,26 @@ export function availableRuntimes() {
|
|
|
88
81
|
* The default `--runtime` for running a prebuilt EXAMPLE/SHOWCASE: `gjs`
|
|
89
82
|
* whenever gjs is runnable here, else the host runtime.
|
|
90
83
|
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
* the primary documented entry point failed on a missing file.
|
|
84
|
+
* Deliberately NOT a plain `hostRuntime()`. A showcase's canonical artifact is its
|
|
85
|
+
* `--app gjs` bundle (`gjsify.main`) — what every showcase ships and what `gjsify
|
|
86
|
+
* dlx` installs. Following the host instead makes `npx @gjsify/cli showcase <name>`
|
|
87
|
+
* (host = node) ask for the `--app node` bundle, which most showcases do not ship
|
|
88
|
+
* and which also needs `@gjsify/node-gi` in the consumer's project, so the
|
|
89
|
+
* first-run experience of the primary documented entry point failed on a missing
|
|
90
|
+
* file.
|
|
99
91
|
*
|
|
100
|
-
* Same rule `gjsify run`
|
|
101
|
-
*
|
|
102
|
-
*
|
|
103
|
-
* of by sniffing the file. `--runtime` still overrides explicitly, and a host
|
|
104
|
-
* WITHOUT gjs (a plain Node/bun/deno box) keeps following the host so the
|
|
92
|
+
* Same rule `gjsify run` applies in its bare-file path (`isLikelyGjsBundle`), with
|
|
93
|
+
* "is it a gjs artifact" answered by the command rather than by sniffing the file.
|
|
94
|
+
* `--runtime` still overrides, and a host WITHOUT gjs keeps following the host so
|
|
105
95
|
* node-capable showcases stay runnable there.
|
|
106
96
|
*/
|
|
107
97
|
export function defaultExampleRuntime() {
|
|
108
98
|
return isRuntimeAvailable('gjs') ? 'gjs' : hostRuntime();
|
|
109
99
|
}
|
|
110
100
|
/**
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
* error against an older CLI).
|
|
101
|
+
* A package's declared example runtimes, or `null` when it declares none (the
|
|
102
|
+
* permissive case). Unknown entries are dropped so a future runtime name does not
|
|
103
|
+
* hard-error against an older CLI.
|
|
115
104
|
*/
|
|
116
105
|
export function readDeclaredRuntimes(pkg) {
|
|
117
106
|
const list = pkg?.gjsify?.example?.runtimes;
|
|
@@ -120,10 +109,9 @@ export function readDeclaredRuntimes(pkg) {
|
|
|
120
109
|
return list.filter((v) => typeof v === 'string' && isExampleRuntime(v));
|
|
121
110
|
}
|
|
122
111
|
/**
|
|
123
|
-
* Validate a requested runtime against a package's declaration
|
|
124
|
-
* declaration is permissive
|
|
125
|
-
*
|
|
126
|
-
* callers can print it and exit cleanly.
|
|
112
|
+
* Validate a requested runtime against a package's declaration; a `null`
|
|
113
|
+
* declaration is permissive. Returns a message rather than throwing, so callers
|
|
114
|
+
* print it and exit cleanly.
|
|
127
115
|
*/
|
|
128
116
|
export function checkRuntimeSupported(runtime, declared, name) {
|
|
129
117
|
if (declared === null)
|
package/lib/utils/spawn.d.ts
CHANGED
|
@@ -2,12 +2,10 @@ import type { ChildProcess } from 'node:child_process';
|
|
|
2
2
|
/**
|
|
3
3
|
* What the calling command does once this spawn settles.
|
|
4
4
|
*
|
|
5
|
-
* - `'exit'` — the command terminates the process itself
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* GJS that MUST NOT leave a main loop armed, so the child is run on the
|
|
10
|
-
* blocking `spawnSync` path instead.
|
|
5
|
+
* - `'exit'` — the command terminates the process itself, which quits the armed GJS
|
|
6
|
+
* main loop, so the streaming async `spawn` is safe on both hosts.
|
|
7
|
+
* - `'return'` — the command returns and lets the CLI unwind. Under GJS that must
|
|
8
|
+
* not leave a main loop armed, so the child runs on the blocking `spawnSync` path.
|
|
11
9
|
*
|
|
12
10
|
* See the module header for the full rationale.
|
|
13
11
|
*/
|
|
@@ -17,59 +15,48 @@ export interface SpawnToCompletionOptions {
|
|
|
17
15
|
completion: SpawnCompletionContract;
|
|
18
16
|
/** Working directory for the child. Defaults to the parent's. */
|
|
19
17
|
cwd?: string;
|
|
20
|
-
/**
|
|
21
|
-
* Environment for the child. Omit to inherit the parent's environment
|
|
22
|
-
* verbatim (what `spawn` does with no `env`).
|
|
23
|
-
*/
|
|
18
|
+
/** Environment for the child. Omit to inherit the parent's verbatim. */
|
|
24
19
|
env?: NodeJS.ProcessEnv;
|
|
25
20
|
/**
|
|
26
|
-
* Seed `FORCE_COLOR=1`
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* stdout is a pipe. Mirrors yarn / npm. Default `false`.
|
|
21
|
+
* Seed `FORCE_COLOR=1` unless `FORCE_COLOR`/`NO_COLOR` is already set, so tools
|
|
22
|
+
* keying on `process.stdout.isTTY` still emit ANSI into a pipe. Mirrors
|
|
23
|
+
* yarn/npm. Default `false`.
|
|
30
24
|
*/
|
|
31
25
|
color?: boolean;
|
|
32
26
|
/**
|
|
33
|
-
* `'inherit'` (default) forwards the parent's stdio
|
|
34
|
-
*
|
|
35
|
-
*
|
|
27
|
+
* `'inherit'` (default) forwards the parent's stdio; `'pipe'` gives the caller
|
|
28
|
+
* `child.stdout`/`child.stderr` via {@link onSpawn}, so it needs
|
|
29
|
+
* `completion: 'exit'`.
|
|
36
30
|
*
|
|
37
|
-
* `'inherit-stderr'` inherits
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
* caller that pipes it into `JSON.parse`.
|
|
31
|
+
* `'inherit-stderr'` inherits but routes the child's **stdout to the parent's
|
|
32
|
+
* stderr**, for a parent whose own stdout is machine-readable: `gjsify pack
|
|
33
|
+
* --json` emits JSON there, and interleaved lifecycle-script log lines make it
|
|
34
|
+
* unparseable for anything piping into `JSON.parse`.
|
|
42
35
|
*/
|
|
43
36
|
stdio?: 'inherit' | 'pipe' | 'inherit-stderr';
|
|
44
37
|
/**
|
|
45
|
-
* Run `cmd` through the platform shell
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
* Skips the win32 command rewrite by design, per this file's own rule:
|
|
50
|
-
* Node routes a `shell: true` spawn through `%COMSPEC%`, which finds
|
|
51
|
-
* `.cmd` shims on its own, so rewriting the string would corrupt it.
|
|
38
|
+
* Run `cmd` through the platform shell so `&&`, `|` and env-var references work.
|
|
39
|
+
* `cmd` is then a whole command LINE and `args` must be empty — npm/yarn script
|
|
40
|
+
* semantics. Skips the win32 rewrite by design: Node routes it through
|
|
41
|
+
* `%COMSPEC%`, which finds `.cmd` shims itself, so rewriting would corrupt it.
|
|
52
42
|
*/
|
|
53
43
|
shell?: boolean;
|
|
54
44
|
/**
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
* ONLY fires on the streaming path: the blocking `spawnSync` path has no
|
|
60
|
-
* `ChildProcess` handle at all. A site that needs the handle must
|
|
61
|
-
* therefore declare `completion: 'exit'`.
|
|
45
|
+
* Called synchronously with the live `ChildProcess` after a successful async
|
|
46
|
+
* spawn — the seam for kill-tracking registries and piped output forwarders.
|
|
47
|
+
* ONLY fires on the streaming path (the blocking path has no handle), so a site
|
|
48
|
+
* needing the handle must declare `completion: 'exit'`.
|
|
62
49
|
*/
|
|
63
50
|
onSpawn?: (child: ChildProcess) => void;
|
|
64
51
|
/**
|
|
65
|
-
* Map an `ENOENT` spawn failure
|
|
66
|
-
*
|
|
52
|
+
* Map an `ENOENT` spawn failure to a domain error carrying an install hint.
|
|
53
|
+
* Other spawn errors are rejected as-is.
|
|
67
54
|
*/
|
|
68
55
|
notFound?: (err: NodeJS.ErrnoException) => Error;
|
|
69
56
|
/**
|
|
70
|
-
* Capture ceiling for the blocking path
|
|
71
|
-
*
|
|
72
|
-
*
|
|
57
|
+
* Capture ceiling for the blocking path, default 64 MiB: a full-workspace lint
|
|
58
|
+
* with many findings runs well past Node's 1 MB default, and an overflow would
|
|
59
|
+
* silently truncate diagnostics.
|
|
73
60
|
*/
|
|
74
61
|
maxBuffer?: number;
|
|
75
62
|
}
|
|
@@ -82,13 +69,10 @@ export interface SpawnCompletion {
|
|
|
82
69
|
/**
|
|
83
70
|
* Run `cmd args…` to completion and resolve with its exit code and signal.
|
|
84
71
|
*
|
|
85
|
-
* Resolves for ANY child exit — a non-zero code is data, not an error, so each
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
* Picks the streaming async path or the blocking captured path per the GJS
|
|
91
|
-
* teardown contract documented at the top of this file.
|
|
72
|
+
* Resolves for ANY child exit — a non-zero code is data, not an error, so each call
|
|
73
|
+
* site keeps its own failure message. Rejects only when the child could not be
|
|
74
|
+
* started (ENOENT mapped through {@link SpawnToCompletionOptions.notFound}). Picks
|
|
75
|
+
* the streaming or blocking path per the teardown contract in the module header.
|
|
92
76
|
*/
|
|
93
77
|
export declare function spawnToCompletion(cmd: string, args: readonly string[], opts: SpawnToCompletionOptions): Promise<SpawnCompletion>;
|
|
94
78
|
/**
|