@gjsify/cli 0.51.1 → 0.53.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 +539 -493
- package/lib/actions/build.d.ts +22 -0
- package/lib/actions/build.js +37 -9
- package/lib/bundler-pick.d.ts +37 -1
- package/lib/bundler-pick.js +108 -17
- package/lib/cli-app.js +7 -2
- package/lib/commands/affected-classify.d.ts +7 -1
- package/lib/commands/affected-classify.js +66 -9
- package/lib/commands/affected-script-refs.d.ts +20 -0
- package/lib/commands/affected-script-refs.js +218 -0
- package/lib/commands/affected.js +24 -2
- package/lib/commands/env.d.ts +31 -0
- package/lib/commands/env.js +114 -0
- package/lib/commands/exec.d.ts +10 -0
- package/lib/commands/exec.js +208 -0
- package/lib/commands/flatpak/diff.js +8 -2
- package/lib/commands/flatpak/init.js +4 -1
- package/lib/commands/flatpak/sources.js +4 -3
- package/lib/commands/flatpak/sync-flathub.d.ts +2 -0
- package/lib/commands/flatpak/sync-flathub.js +149 -7
- package/lib/commands/flatpak/utils.d.ts +10 -0
- package/lib/commands/flatpak/utils.js +10 -0
- package/lib/commands/foreach.js +5 -97
- package/lib/commands/format.js +26 -6
- package/lib/commands/index.d.ts +4 -0
- package/lib/commands/index.js +4 -0
- package/lib/commands/install.d.ts +2 -2
- package/lib/commands/install.js +81 -5
- package/lib/commands/link.d.ts +13 -0
- package/lib/commands/link.js +243 -0
- package/lib/commands/onboard.js +18 -2
- package/lib/commands/publish.d.ts +34 -0
- package/lib/commands/publish.js +153 -8
- package/lib/commands/self-update.js +2 -1
- package/lib/commands/ship.js +19 -1
- package/lib/commands/test.d.ts +18 -9
- package/lib/commands/test.js +56 -11
- package/lib/commands/tsc.js +4 -4
- package/lib/commands/upgrade.d.ts +15 -0
- package/lib/commands/upgrade.js +76 -2
- package/lib/commands/webext/index.d.ts +2 -0
- package/lib/commands/webext/index.js +15 -0
- package/lib/commands/webext/subcommands.d.ts +16 -0
- package/lib/commands/webext/subcommands.js +204 -0
- package/lib/types/config-data.d.ts +2 -2
- package/lib/utils/bin-shim.d.ts +8 -2
- package/lib/utils/bin-shim.js +6 -5
- package/lib/utils/bundle-inputs.d.ts +84 -0
- package/lib/utils/bundle-inputs.js +268 -0
- package/lib/utils/check-system-deps.d.ts +5 -19
- package/lib/utils/check-system-deps.js +31 -94
- package/lib/utils/dev-link.d.ts +225 -0
- package/lib/utils/dev-link.js +684 -0
- package/lib/utils/exec-bin.d.ts +137 -0
- package/lib/utils/exec-bin.js +321 -0
- package/lib/utils/gi-runtime-paths.js +3 -2
- package/lib/utils/gitignore.d.ts +15 -0
- package/lib/utils/gitignore.js +178 -0
- package/lib/utils/gjsify-shim.d.ts +47 -0
- package/lib/utils/gjsify-shim.js +97 -8
- package/lib/utils/hang-watchdog.d.ts +95 -0
- package/lib/utils/hang-watchdog.js +194 -0
- package/lib/utils/install-backend-native.d.ts +33 -1
- package/lib/utils/install-backend-native.js +184 -20
- package/lib/utils/install-extraneous.d.ts +90 -0
- package/lib/utils/install-extraneous.js +120 -0
- package/lib/utils/install-lock.js +4 -25
- package/lib/utils/install-tarball-cache.d.ts +37 -9
- package/lib/utils/install-tarball-cache.js +59 -14
- package/lib/utils/native-skip-scan.d.ts +20 -0
- package/lib/utils/native-skip-scan.js +343 -0
- package/lib/utils/node-script.js +1 -1
- package/lib/utils/normalize-bundler-options.js +11 -0
- package/lib/utils/oxc-resolve.js +42 -3
- package/lib/utils/process-table.d.ts +22 -0
- package/lib/utils/process-table.js +188 -0
- package/lib/utils/prune-prefix.js +1 -1
- package/lib/utils/publish-pins.d.ts +38 -0
- package/lib/utils/publish-pins.js +47 -0
- package/lib/utils/publish-readback.d.ts +103 -17
- package/lib/utils/publish-readback.js +326 -47
- package/lib/utils/run-gjs.d.ts +15 -1
- package/lib/utils/run-gjs.js +98 -13
- package/lib/utils/run-node.d.ts +2 -0
- package/lib/utils/run-node.js +2 -1
- package/lib/utils/runtimes.js +14 -13
- package/lib/utils/ship/gzip.js +1 -1
- package/lib/utils/ship/icns.d.ts +14 -0
- package/lib/utils/ship/icns.js +83 -0
- package/lib/utils/ship/ico.d.ts +25 -0
- package/lib/utils/ship/ico.js +120 -0
- package/lib/utils/ship/icons.d.ts +197 -0
- package/lib/utils/ship/icons.js +399 -0
- package/lib/utils/ship/launcher.js +16 -1
- package/lib/utils/ship/layout.d.ts +32 -0
- package/lib/utils/ship/layout.js +112 -38
- package/lib/utils/ship/msi.d.ts +1 -1
- package/lib/utils/ship/msi.js +30 -5
- package/lib/utils/ship/pe-launcher.d.ts +18 -0
- package/lib/utils/ship/pe-launcher.js +125 -4
- package/lib/utils/ship/plan.d.ts +1 -34
- package/lib/utils/ship/plan.js +7 -56
- package/lib/utils/ship/plist.d.ts +20 -10
- package/lib/utils/ship/plist.js +29 -12
- package/lib/utils/ship/settings.js +3 -2
- package/lib/utils/spawn.d.ts +13 -0
- package/lib/utils/spawn.js +10 -5
- package/lib/utils/watch-loop.d.ts +15 -1
- package/lib/utils/watch-loop.js +9 -5
- package/lib/utils/webext/build.d.ts +42 -0
- package/lib/utils/webext/build.js +120 -0
- package/lib/utils/webext/config.d.ts +72 -0
- package/lib/utils/webext/config.js +234 -0
- package/lib/utils/webext/icons.d.ts +24 -0
- package/lib/utils/webext/icons.js +83 -0
- package/lib/utils/webext/launch.d.ts +32 -0
- package/lib/utils/webext/launch.js +77 -0
- package/lib/utils/webext/manifest.d.ts +53 -0
- package/lib/utils/webext/manifest.js +219 -0
- package/lib/utils/webext/pages.d.ts +26 -0
- package/lib/utils/webext/pages.js +61 -0
- package/lib/utils/webext/targets.d.ts +13 -0
- package/lib/utils/webext/targets.js +36 -0
- package/lib/utils/win32-command.d.ts +17 -0
- package/lib/utils/win32-command.js +21 -6
- package/package.json +20 -20
package/lib/actions/build.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ConfigData } from '../types/index.js';
|
|
2
2
|
import type { App } from '@gjsify/rolldown-plugin-gjsify';
|
|
3
3
|
import type { RolldownOutput } from 'rolldown';
|
|
4
|
+
import { type RunBundleOptions } from '../bundler-pick.js';
|
|
4
5
|
export declare class BuildAction {
|
|
5
6
|
readonly configData: ConfigData;
|
|
6
7
|
constructor(configData?: ConfigData);
|
|
@@ -186,11 +187,31 @@ export declare class BuildAction {
|
|
|
186
187
|
*/
|
|
187
188
|
resolveFromToolchain?: boolean;
|
|
188
189
|
}): Promise<string>;
|
|
190
|
+
/**
|
|
191
|
+
* The uncached half of {@link bundleFileForGjsCached}: bundle `inputPath` to
|
|
192
|
+
* `outfile` as one self-contained `--app gjs` module. `gjsify exec` calls it
|
|
193
|
+
* directly because it keys its artifacts by CONTENT (package version, lockfile,
|
|
194
|
+
* CLI version — `utils/exec-bin.ts`) rather than by mtime.
|
|
195
|
+
*/
|
|
196
|
+
static bundleFileForGjs(inputPath: string, outfile: string, opts: {
|
|
197
|
+
verbose?: boolean;
|
|
198
|
+
define?: Record<string, string>;
|
|
199
|
+
preserveDefaultExport?: boolean;
|
|
200
|
+
globals?: string;
|
|
201
|
+
excludeGlobals?: string[];
|
|
202
|
+
/** The running CLI's file, or null — see `resolveFromToolchain` above; the CALLER decides. */
|
|
203
|
+
toolchainAnchor?: string | null;
|
|
204
|
+
/** `silent` drops warnings, never errors — errors reject the build either way. */
|
|
205
|
+
logLevel?: 'silent';
|
|
206
|
+
}): Promise<void>;
|
|
207
|
+
/** The running CLI's own file — the toolchain anchor `gjsify exec` hands {@link bundleFileForGjs}. */
|
|
208
|
+
static runningCliFile(): string | null;
|
|
189
209
|
/** Application mode */
|
|
190
210
|
buildApp(app?: App, opts?: {
|
|
191
211
|
watch?: boolean;
|
|
192
212
|
preserveDefaultExport?: boolean;
|
|
193
213
|
toolchainAnchor?: string;
|
|
214
|
+
onWatchFiles?: RunBundleOptions['onWatchFiles'];
|
|
194
215
|
}): Promise<RolldownOutput[]>;
|
|
195
216
|
/**
|
|
196
217
|
* Drive `rolldown.watch(...)`: rebuild on source change, apply the
|
|
@@ -203,5 +224,6 @@ export declare class BuildAction {
|
|
|
203
224
|
library?: boolean;
|
|
204
225
|
app?: App;
|
|
205
226
|
watch?: boolean;
|
|
227
|
+
onWatchFiles?: RunBundleOptions['onWatchFiles'];
|
|
206
228
|
}): Promise<RolldownOutput[]>;
|
|
207
229
|
}
|
package/lib/actions/build.js
CHANGED
|
@@ -555,6 +555,16 @@ export class BuildAction {
|
|
|
555
555
|
}
|
|
556
556
|
if (opts.verbose)
|
|
557
557
|
console.debug(`[gjsify] bundling ${inputPath} for GJS → ${outfile}`);
|
|
558
|
+
await BuildAction.bundleFileForGjs(inputPath, outfile, { ...opts, toolchainAnchor: anchorFile });
|
|
559
|
+
return outfile;
|
|
560
|
+
}
|
|
561
|
+
/**
|
|
562
|
+
* The uncached half of {@link bundleFileForGjsCached}: bundle `inputPath` to
|
|
563
|
+
* `outfile` as one self-contained `--app gjs` module. `gjsify exec` calls it
|
|
564
|
+
* directly because it keys its artifacts by CONTENT (package version, lockfile,
|
|
565
|
+
* CLI version — `utils/exec-bin.ts`) rather than by mtime.
|
|
566
|
+
*/
|
|
567
|
+
static async bundleFileForGjs(inputPath, outfile, opts) {
|
|
558
568
|
await mkdir(dirname(outfile), { recursive: true });
|
|
559
569
|
await new BuildAction({
|
|
560
570
|
verbose: opts.verbose,
|
|
@@ -564,15 +574,18 @@ export class BuildAction {
|
|
|
564
574
|
input: inputPath,
|
|
565
575
|
output: { file: outfile },
|
|
566
576
|
...(opts.define ? { transform: { define: opts.define } } : {}),
|
|
577
|
+
...(opts.logLevel ? { logLevel: opts.logLevel } : {}),
|
|
567
578
|
},
|
|
568
579
|
}).buildApp('gjs', {
|
|
569
580
|
preserveDefaultExport: opts.preserveDefaultExport ?? true,
|
|
570
|
-
//
|
|
571
|
-
//
|
|
572
|
-
|
|
573
|
-
...(anchorFile === null ? {} : { toolchainAnchor: anchorFile }),
|
|
581
|
+
// The CALLER decides whether this input is toolchain, because this helper
|
|
582
|
+
// alone cannot tell a config file from a consumer's `node ./src/main.mjs`.
|
|
583
|
+
...(opts.toolchainAnchor ? { toolchainAnchor: opts.toolchainAnchor } : {}),
|
|
574
584
|
});
|
|
575
|
-
|
|
585
|
+
}
|
|
586
|
+
/** The running CLI's own file — the toolchain anchor `gjsify exec` hands {@link bundleFileForGjs}. */
|
|
587
|
+
static runningCliFile() {
|
|
588
|
+
return runningCliFile();
|
|
576
589
|
}
|
|
577
590
|
/** Application mode */
|
|
578
591
|
async buildApp(app = 'gjs', opts = {}) {
|
|
@@ -712,7 +725,13 @@ export class BuildAction {
|
|
|
712
725
|
// unresolvable import would hard-crash the analysis pass.
|
|
713
726
|
// Mirrors the explicit-globals path (resolveGlobalsInject)
|
|
714
727
|
// and resolveUserPlugins above, which already anchor on cwd.
|
|
715
|
-
{
|
|
728
|
+
{
|
|
729
|
+
extraGlobalsList: extras,
|
|
730
|
+
excludeGlobals,
|
|
731
|
+
cwd: process.cwd(),
|
|
732
|
+
// The same fallback the resolver gets, or the gate drops what it would rescue.
|
|
733
|
+
...(opts.toolchainAnchor !== undefined ? { toolchainDir: dirname(opts.toolchainAnchor) } : {}),
|
|
734
|
+
}, bundleToChunks);
|
|
716
735
|
pluginOpts.autoGlobalsInject = injectPath;
|
|
717
736
|
}
|
|
718
737
|
else if (app === 'node' && autoMode) {
|
|
@@ -803,7 +822,7 @@ export class BuildAction {
|
|
|
803
822
|
await this.runWatchLoop(finalOpts, app, outfile, outdir, verbose);
|
|
804
823
|
return [];
|
|
805
824
|
}
|
|
806
|
-
const writeResult = await runBundle(finalOpts);
|
|
825
|
+
const writeResult = await runBundle(finalOpts, { onWatchFiles: opts.onWatchFiles });
|
|
807
826
|
// GJS truncates module source at a raw U+0000 (it is handed to SpiderMonkey as a
|
|
808
827
|
// NUL-terminated C string), so escape any the minifier emitted before anything else
|
|
809
828
|
// touches the file. See utils/gjs-source-escape.ts.
|
|
@@ -920,14 +939,23 @@ export class BuildAction {
|
|
|
920
939
|
}
|
|
921
940
|
await closed;
|
|
922
941
|
}
|
|
923
|
-
async start(buildType = {
|
|
942
|
+
async start(buildType = {
|
|
943
|
+
app: 'gjs',
|
|
944
|
+
}) {
|
|
924
945
|
if (buildType.library) {
|
|
946
|
+
// `onWatchFiles` has no consumer here and is deliberately NOT
|
|
947
|
+
// forwarded: a `--library` build emits a published package, and
|
|
948
|
+
// nothing asks whether it is stale (`gjsify test` is the only
|
|
949
|
+
// freshness check, and it never builds a library).
|
|
925
950
|
if (buildType.watch) {
|
|
926
951
|
throw new Error('gjsify build: --watch is not supported with --library (library mode would emit watcher rebuilds for every produced format; use --app gjs|node|browser instead).');
|
|
927
952
|
}
|
|
928
953
|
return await this.buildLibrary();
|
|
929
954
|
}
|
|
930
|
-
return await this.buildApp(buildType.app, {
|
|
955
|
+
return await this.buildApp(buildType.app, {
|
|
956
|
+
watch: buildType.watch,
|
|
957
|
+
onWatchFiles: buildType.onWatchFiles,
|
|
958
|
+
});
|
|
931
959
|
}
|
|
932
960
|
}
|
|
933
961
|
async function runOneLibraryBuild(args) {
|
package/lib/bundler-pick.d.ts
CHANGED
|
@@ -8,6 +8,20 @@ export interface NativePluginContext {
|
|
|
8
8
|
id: string;
|
|
9
9
|
external: boolean;
|
|
10
10
|
} | null>;
|
|
11
|
+
/**
|
|
12
|
+
* rolldown's `this.addWatchFile`, collected by the native facade into
|
|
13
|
+
* `BundleResult.watchedFiles` — the native half of what npm rolldown reports
|
|
14
|
+
* as `RolldownBuild.watchFiles`.
|
|
15
|
+
*
|
|
16
|
+
* OPTIONAL here on purpose. The engine is resolved through several anchors
|
|
17
|
+
* and a global-prefix copy can answer first (measured 2026-09-29 on a dev
|
|
18
|
+
* host whose project-local engine was the current one), so a plugin cannot
|
|
19
|
+
* assume the method exists: it is this bridge's documented stance that an
|
|
20
|
+
* unimplemented context method FAILS at hook-call time, and a build must
|
|
21
|
+
* not fail over bookkeeping. `gjsify-css-as-string` therefore
|
|
22
|
+
* feature-detects and warns once.
|
|
23
|
+
*/
|
|
24
|
+
addWatchFile(id: string): void;
|
|
11
25
|
warn(message: string): void;
|
|
12
26
|
error(message: string): never;
|
|
13
27
|
}
|
|
@@ -72,11 +86,33 @@ export declare function bundleToChunks(input: {
|
|
|
72
86
|
* and is responsible for invoking `watcher.close()` on shutdown.
|
|
73
87
|
*/
|
|
74
88
|
export declare function runWatch(finalOpts: BundlerOptions): Promise<RolldownWatcher>;
|
|
89
|
+
/** What one build reported about the files its output depends on. */
|
|
90
|
+
export interface BuildWatchList {
|
|
91
|
+
/**
|
|
92
|
+
* The engine's watch list: npm rolldown's `RolldownBuild.watchFiles` (its
|
|
93
|
+
* module set plus every `this.addWatchFile`), the native facade's
|
|
94
|
+
* `watchedFiles` (the declared half — the native engine reports no modules,
|
|
95
|
+
* hence the two halves rather than either). Read BEFORE `close()`, which is
|
|
96
|
+
* where the npm getter is still alive.
|
|
97
|
+
*/
|
|
98
|
+
files: readonly string[];
|
|
99
|
+
/**
|
|
100
|
+
* `false` when the engine CANNOT report one at all (a `@gjsify/rolldown-native`
|
|
101
|
+
* older than `addWatchFile`). A caller that judges a build's inputs on this
|
|
102
|
+
* list has to refuse to trust it — the file a plugin read itself is then
|
|
103
|
+
* invisible, and a stale bundle would read as current.
|
|
104
|
+
*/
|
|
105
|
+
reportedByEngine: boolean;
|
|
106
|
+
}
|
|
107
|
+
/** Where a build's own input list goes. Absent → the caller does not want it. */
|
|
108
|
+
export interface RunBundleOptions {
|
|
109
|
+
onWatchFiles?: (watch: BuildWatchList) => void;
|
|
110
|
+
}
|
|
75
111
|
/**
|
|
76
112
|
* Run a bundle with the picked engine. Drop-in replacement for the
|
|
77
113
|
* `rolldown(opts).write(opts.output)` flow used directly in build.ts.
|
|
78
114
|
*/
|
|
79
|
-
export declare function runBundle(finalOpts: BundlerOptions): Promise<RolldownOutput>;
|
|
115
|
+
export declare function runBundle(finalOpts: BundlerOptions, options?: RunBundleOptions): Promise<RolldownOutput>;
|
|
80
116
|
export declare function shouldUseNative(): Promise<boolean>;
|
|
81
117
|
/**
|
|
82
118
|
* Walk parent directories from `startDir` (and optionally a second anchor
|
package/lib/bundler-pick.js
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
// synchronous require of a builtin, so the load dies before any `.node` is opened.
|
|
11
11
|
// The distinction is not pedantry — it says an N-API host alone would not be
|
|
12
12
|
// enough; the wrapper has to be bypassed too, which is exactly what
|
|
13
|
-
// `napiNodeAddonPlugin` does for napi-rs packages. See `status/open-todos.md`
|
|
13
|
+
// `napiNodeAddonPlugin` does for napi-rs packages. See `status/open-todos/README.md`
|
|
14
14
|
// § "Can `@gjsify/napi` retire the hand-written `-native` bridges?".
|
|
15
15
|
//
|
|
16
16
|
// `GJSIFY_BUNDLER=native|npm` overrides that: `native` throws when the prebuild is
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
import { promises as fs, existsSync } from 'node:fs';
|
|
31
31
|
import * as path from 'node:path';
|
|
32
32
|
import { createRequire } from 'node:module';
|
|
33
|
-
import { pathToFileURL } from 'node:url';
|
|
33
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
34
34
|
import { resolveNpmPackage } from './utils/resolve-npm-package.js';
|
|
35
35
|
// Static, not dynamic: `diagnoseNativeEngine()` is synchronous and called inside a
|
|
36
36
|
// `throw` expression. Safe because check-system-deps imports only `node:` builtins,
|
|
@@ -80,7 +80,8 @@ async function loadNpmRolldown() {
|
|
|
80
80
|
function diagnoseNativeEngine() {
|
|
81
81
|
let pkgDir = null;
|
|
82
82
|
try {
|
|
83
|
-
|
|
83
|
+
// Not `new URL(...).pathname`: on win32 that is `/C:/...`, percent-encoded, no path.
|
|
84
|
+
const bundleDir = path.dirname(fileURLToPath(import.meta.url));
|
|
84
85
|
pkgDir = findRolldownNativeDir(process.cwd(), bundleDir);
|
|
85
86
|
}
|
|
86
87
|
catch {
|
|
@@ -131,23 +132,39 @@ function diagnoseNativeEngine() {
|
|
|
131
132
|
// reads the same tables `gjsify system-check` does, so the answer cannot drift
|
|
132
133
|
// from the declaration.
|
|
133
134
|
const missing = missingSystemDepsFor('@gjsify/rolldown-native');
|
|
134
|
-
|
|
135
|
-
|
|
135
|
+
const names = missing.map((d) => d.name).join(', ');
|
|
136
|
+
const cmd = missing.length > 0 ? buildInstallCommand(detectPackageManager(), missing) : null;
|
|
137
|
+
const installHint = missing.length === 0
|
|
138
|
+
? undefined
|
|
139
|
+
: cmd
|
|
140
|
+
? `Install it:\n ${cmd}`
|
|
141
|
+
: `Install ${names} with your system package manager (this host's manager was not recognised, so no command is suggested rather than a wrong one).`;
|
|
142
|
+
// (0) The measurement could not run at all. First, because everything below
|
|
143
|
+
// reasons from a measurement: with no reading in hand, (2) would assert the
|
|
144
|
+
// prebuild IS on girepository's search path — a positive claim this PR
|
|
145
|
+
// exists to make measurable, so its absence is stated rather than papered over.
|
|
146
|
+
if (_utilsCoreError !== null) {
|
|
147
|
+
parts.push(`\nNOT MEASURED — the native-library probe could not be loaded, so nothing below is a reading of this host:\n ${_utilsCoreError instanceof Error ? _utilsCoreError.message : String(_utilsCoreError)}`);
|
|
148
|
+
}
|
|
149
|
+
// (1) The loader's own answer, when `tryLoadNative()` measured one: the file
|
|
150
|
+
// that would not open and the dependency it named. It outranks (2), which only
|
|
151
|
+
// knows what pkg-config can see — the dependency may be one no table declares.
|
|
152
|
+
if (_nativeLibraryFailure && _utilsCore) {
|
|
153
|
+
parts.push(`\nMEASURED CAUSE — ${new _utilsCore.NativeLibraryLoadError(_nativeLibraryFailure, installHint).message}`);
|
|
154
|
+
}
|
|
155
|
+
else if (missing.length > 0) {
|
|
136
156
|
parts.push(`\nMEASURED CAUSE — a system library the engine's prebuild loads is MISSING: ${names}.\n` +
|
|
137
157
|
'The prebuild is present but its typelib cannot open its backing library, which GJS reports as ' +
|
|
138
158
|
'`Unsupported type void, deriving from fundamental void` — a message that names nothing. ' +
|
|
139
159
|
'This is a system package, not an npm one.');
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
parts.push(`Install it:\n ${cmd}`);
|
|
143
|
-
else
|
|
144
|
-
parts.push(`Install ${names} with your system package manager (this host's manager was not recognised, so no command is suggested rather than a wrong one).`);
|
|
160
|
+
if (installHint)
|
|
161
|
+
parts.push(installHint);
|
|
145
162
|
}
|
|
146
163
|
// (2) No prebuild for this architecture — last because it is least actionable.
|
|
147
164
|
// Read off the set `activateNativePrebuilds()` ACTUALLY put on the search paths:
|
|
148
165
|
// a memoized cached-array read that cannot throw, and it names the per-target
|
|
149
166
|
// sibling package really holding the artifact.
|
|
150
|
-
if (missing.length === 0) {
|
|
167
|
+
if (missing.length === 0 && !_nativeLibraryFailure) {
|
|
151
168
|
const engine = activateNativePrebuilds().find((p) => p.name.startsWith('@gjsify/rolldown-native'));
|
|
152
169
|
parts.push(engine
|
|
153
170
|
? `\nEvery declared system library resolves and ${engine.name}'s prebuild (${engine.prebuildsDir}) IS on ` +
|
|
@@ -255,24 +272,64 @@ export async function runWatch(finalOpts) {
|
|
|
255
272
|
const output = finalOpts.output ?? {};
|
|
256
273
|
return mod.watch({ ...finalOpts, output });
|
|
257
274
|
}
|
|
275
|
+
let _warnedNoWatchList = false;
|
|
276
|
+
function warnNoNativeWatchList() {
|
|
277
|
+
if (_warnedNoWatchList)
|
|
278
|
+
return;
|
|
279
|
+
_warnedNoWatchList = true;
|
|
280
|
+
console.warn('[gjsify] this `@gjsify/rolldown-native` build reports no watch list: it predates ' +
|
|
281
|
+
'`addWatchFile`, so a file a plugin read itself (a stylesheet\u2019s `@import` chain, an ' +
|
|
282
|
+
'inlined `readFileSync`) cannot be declared as a build input. `gjsify test` will rebuild ' +
|
|
283
|
+
'the affected bundles on every run rather than trust a set it cannot see. Upgrade the ' +
|
|
284
|
+
'engine (it ships in the same release train as the CLI).');
|
|
285
|
+
}
|
|
258
286
|
/**
|
|
259
287
|
* Run a bundle with the picked engine. Drop-in replacement for the
|
|
260
288
|
* `rolldown(opts).write(opts.output)` flow used directly in build.ts.
|
|
261
289
|
*/
|
|
262
|
-
export async function runBundle(finalOpts) {
|
|
290
|
+
export async function runBundle(finalOpts, options = {}) {
|
|
263
291
|
if (await shouldUseNative()) {
|
|
264
|
-
return await runNativeBundle(finalOpts);
|
|
292
|
+
return await runNativeBundle(finalOpts, options);
|
|
265
293
|
}
|
|
266
294
|
const rolldown = await loadNpmRolldown();
|
|
267
295
|
const build = await rolldown(finalOpts);
|
|
268
296
|
try {
|
|
269
|
-
|
|
297
|
+
const output = await build.write(finalOpts.output ?? {});
|
|
298
|
+
if (options.onWatchFiles) {
|
|
299
|
+
options.onWatchFiles({ files: await build.watchFiles, reportedByEngine: true });
|
|
300
|
+
}
|
|
301
|
+
return output;
|
|
270
302
|
}
|
|
271
303
|
finally {
|
|
272
304
|
await build.close();
|
|
273
305
|
}
|
|
274
306
|
}
|
|
275
307
|
let _nativeProbe = null;
|
|
308
|
+
/** Why the engine's library would not open, when `tryLoadNative()` measured it. */
|
|
309
|
+
let _nativeLibraryFailure = null;
|
|
310
|
+
let _utilsCore = null;
|
|
311
|
+
/**
|
|
312
|
+
* Why the probe itself could not run, when that is the reason. Kept apart from
|
|
313
|
+
* "there is no engine" on purpose: `tryLoadNative()`'s bare `catch` cannot tell
|
|
314
|
+
* the two apart, and `diagnoseNativeEngine()` then answers a question nobody
|
|
315
|
+
* asked — it reports which system libraries resolve, and says the prebuild IS on
|
|
316
|
+
* girepository's search path, which is a positive claim about a measurement that
|
|
317
|
+
* never happened. This PR exists to make such a claim measurable, so a missing
|
|
318
|
+
* measurement is reported as one.
|
|
319
|
+
*/
|
|
320
|
+
let _utilsCoreError = null;
|
|
321
|
+
async function utilsCore() {
|
|
322
|
+
if (_utilsCore === null) {
|
|
323
|
+
// `./native-library`, not `./core`: `core` re-exports `main-loop`, which
|
|
324
|
+
// holds a module-level singleton. The GJS bundle inlines utils already,
|
|
325
|
+
// so loading `core` off disk would give the process a SECOND copy of that
|
|
326
|
+
// singleton — inert today because only pure probe functions are read
|
|
327
|
+
// through this edge, and a trap the first time that stops being true.
|
|
328
|
+
const href = pathToFileURL(createRequire(import.meta.url).resolve('@gjsify/utils/native-library')).href;
|
|
329
|
+
_utilsCore = (await import(/* @vite-ignore */ href));
|
|
330
|
+
}
|
|
331
|
+
return _utilsCore;
|
|
332
|
+
}
|
|
276
333
|
export async function shouldUseNative() {
|
|
277
334
|
const env = globalThis.process?.env ?? {};
|
|
278
335
|
const choice = env.GJSIFY_BUNDLER;
|
|
@@ -282,7 +339,8 @@ export async function shouldUseNative() {
|
|
|
282
339
|
if (choice === 'native') {
|
|
283
340
|
const native = await tryLoadNative();
|
|
284
341
|
if (!native) {
|
|
285
|
-
throw new Error('GJSIFY_BUNDLER=native but @gjsify/rolldown-native is not loadable (no prebuild for this architecture, or not running under GJS).'
|
|
342
|
+
throw new Error('GJSIFY_BUNDLER=native but @gjsify/rolldown-native is not loadable (no prebuild for this architecture, or not running under GJS).' +
|
|
343
|
+
(isGjs() ? `\n${diagnoseNativeEngine()}` : ''));
|
|
286
344
|
}
|
|
287
345
|
return true;
|
|
288
346
|
}
|
|
@@ -375,7 +433,7 @@ async function tryLoadNative() {
|
|
|
375
433
|
// limitations and `findWorkspaceRoot`'s dependency on
|
|
376
434
|
// `discoverWorkspaces`, both of which can fail to map a
|
|
377
435
|
// sub-package dir up to the hoisted workspace root.
|
|
378
|
-
const bundleDir = path.dirname(
|
|
436
|
+
const bundleDir = path.dirname(fileURLToPath(import.meta.url));
|
|
379
437
|
const resolvedFromNpm = resolveNpmPackage(specifier, { bundleUrl: import.meta.url });
|
|
380
438
|
const resolvedFromFs = resolvedFromNpm
|
|
381
439
|
? null
|
|
@@ -399,6 +457,25 @@ async function tryLoadNative() {
|
|
|
399
457
|
const mod = (await import(/* @vite-ignore */ target));
|
|
400
458
|
if (!mod.hasNativeRolldown())
|
|
401
459
|
return null;
|
|
460
|
+
// The typelib resolved, which says nothing about its library: that
|
|
461
|
+
// opens at the first class access, and a missing system library
|
|
462
|
+
// (Homebrew json-glib on a Mac) would pass here and fail inside
|
|
463
|
+
// `new BundlerSession()` as the nameless "Unsupported type void" —
|
|
464
|
+
// past `diagnoseNativeEngine()`, which then never runs.
|
|
465
|
+
// Separated from the engine's own failure so that "the engine is
|
|
466
|
+
// absent" and "the measurement could not run" stay distinguishable
|
|
467
|
+
// at the one place that reports them.
|
|
468
|
+
let surface;
|
|
469
|
+
try {
|
|
470
|
+
surface = await utilsCore();
|
|
471
|
+
}
|
|
472
|
+
catch (err) {
|
|
473
|
+
_utilsCoreError = err;
|
|
474
|
+
return null;
|
|
475
|
+
}
|
|
476
|
+
_nativeLibraryFailure = surface.probeNativeLibrary('GjsifyRolldown');
|
|
477
|
+
if (_nativeLibraryFailure)
|
|
478
|
+
return null;
|
|
402
479
|
return mod;
|
|
403
480
|
}
|
|
404
481
|
catch {
|
|
@@ -407,7 +484,7 @@ async function tryLoadNative() {
|
|
|
407
484
|
})();
|
|
408
485
|
return _nativeProbe;
|
|
409
486
|
}
|
|
410
|
-
async function runNativeBundle(finalOpts) {
|
|
487
|
+
async function runNativeBundle(finalOpts, options = {}) {
|
|
411
488
|
const native = await tryLoadNative();
|
|
412
489
|
if (!native) {
|
|
413
490
|
throw new Error('@gjsify/rolldown-native not loadable');
|
|
@@ -440,6 +517,20 @@ async function runNativeBundle(finalOpts) {
|
|
|
440
517
|
}
|
|
441
518
|
const result = await native.bundleWithPlugins(bundlerOpts, nativePlugins);
|
|
442
519
|
reportNativeWarnings(result, finalOpts);
|
|
520
|
+
if (options.onWatchFiles) {
|
|
521
|
+
if (result.watchedFiles === undefined) {
|
|
522
|
+
// NOT a silent drop. A version-skewed engine has no `addWatchFile` on
|
|
523
|
+
// its plugin context, so nothing a plugin declares can reach the
|
|
524
|
+
// build's input set — and a caller judging freshness on that set
|
|
525
|
+
// would call a stale bundle current. Say so here, where the engine is
|
|
526
|
+
// in hand, and report `reportedByEngine: false` so the caller refuses.
|
|
527
|
+
warnNoNativeWatchList();
|
|
528
|
+
options.onWatchFiles({ files: [], reportedByEngine: false });
|
|
529
|
+
}
|
|
530
|
+
else {
|
|
531
|
+
options.onWatchFiles({ files: result.watchedFiles, reportedByEngine: true });
|
|
532
|
+
}
|
|
533
|
+
}
|
|
443
534
|
// The native facade returns the BundleOutput shape but doesn't
|
|
444
535
|
// write files — replicate `.write()` here so callers see the same
|
|
445
536
|
// on-disk layout whether they used npm rolldown or native.
|
package/lib/cli-app.js
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
// build`, and `gjsify run build:types → gjsify tsc → gjs tsc.gjs.mjs`), so on
|
|
11
11
|
// CI's few cores the multiplier oversubscribes and the build thrashes. Letting
|
|
12
12
|
// `gjsify run` dispatch the inner `gjsify <cmd>` in-process collapses two gjs
|
|
13
|
-
// into one. See status/open-todos.md.
|
|
13
|
+
// into one. See status/open-todos/README.md.
|
|
14
14
|
//
|
|
15
15
|
// This module MUST NOT execute anything at load time (no top-level
|
|
16
16
|
// `parseAsync`) — `run.ts` imports it, and a top-level run would re-dispatch
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
import yargs from 'yargs';
|
|
19
19
|
import { classifyCliFailure } from './cli-fail.js';
|
|
20
20
|
import { cliVersion } from './utils/publish-headers.js';
|
|
21
|
-
import { buildCommand as build, clearCommand as clear, copyCommand as copy, testCommand as test, runCommand as run, infoCommand as info, systemCheckCommand as systemCheck, checkCommand as check, showcaseCommand as showcase, createCommand as create, gresourceCommand as gresource, gettextCommand as gettext, gsettingsCommand as gsettings, flatpakCommand as flatpak, shipCommand as ship, dlxCommand as dlx, installCommand as install, foreachCommand as foreach, workspaceCommand as workspace, packCommand as pack, publishCommand as publish, whoamiCommand as whoami, loginCommand as login, logoutCommand as logout, trustCommand as trust, onboardCommand as onboard, selfUpdateCommand as selfUpdate, generateInstallerCommand as generateInstaller, pruneCommand as prune, uninstallCommand as uninstall, formatCommand as format, lintCommand as lint, fixCommand as fix, upgradeCommand as upgrade, barrelsCommand as barrels, tscCommand as tsc, affectedCommand as affected, storybookCommand as storybook, devCommand as dev, debugCommand as debug, browseCommand as browse, } from './commands/index.js';
|
|
21
|
+
import { buildCommand as build, clearCommand as clear, copyCommand as copy, envCommand as env, execCommand as exec, testCommand as test, runCommand as run, infoCommand as info, systemCheckCommand as systemCheck, checkCommand as check, showcaseCommand as showcase, createCommand as create, gresourceCommand as gresource, gettextCommand as gettext, gsettingsCommand as gsettings, flatpakCommand as flatpak, shipCommand as ship, dlxCommand as dlx, installCommand as install, linkCommand as link, unlinkCommand as unlink, foreachCommand as foreach, workspaceCommand as workspace, packCommand as pack, publishCommand as publish, whoamiCommand as whoami, loginCommand as login, logoutCommand as logout, trustCommand as trust, onboardCommand as onboard, selfUpdateCommand as selfUpdate, generateInstallerCommand as generateInstaller, pruneCommand as prune, uninstallCommand as uninstall, formatCommand as format, lintCommand as lint, fixCommand as fix, upgradeCommand as upgrade, barrelsCommand as barrels, tscCommand as tsc, affectedCommand as affected, storybookCommand as storybook, devCommand as dev, debugCommand as debug, browseCommand as browse, webextCommand as webext, } from './commands/index.js';
|
|
22
22
|
import { APP_NAME } from './constants.js';
|
|
23
23
|
import { isBun, isDeno, isNode, gjsSystemVersion } from '@gjsify/rolldown-plugin-gjsify/runtime';
|
|
24
24
|
import { ensureGjsifyShimOnPath } from './utils/gjsify-shim.js';
|
|
@@ -93,9 +93,13 @@ export async function runCli(argv) {
|
|
|
93
93
|
.wrap(cli.terminalWidth())
|
|
94
94
|
.command(create.command, create.description, create.builder, create.handler)
|
|
95
95
|
.command(install.command, install.description, install.builder, install.handler)
|
|
96
|
+
.command(link.command, link.description, link.builder, link.handler)
|
|
97
|
+
.command(unlink.command, unlink.description, unlink.builder, unlink.handler)
|
|
96
98
|
.command(build.command, build.description, build.builder, build.handler)
|
|
97
99
|
.command(clear.command, clear.description, clear.builder, clear.handler)
|
|
98
100
|
.command(copy.command, copy.description, copy.builder, copy.handler)
|
|
101
|
+
.command(env.command, env.description, env.builder, env.handler)
|
|
102
|
+
.command(exec.command, exec.description, exec.builder, exec.handler)
|
|
99
103
|
.command(test.command, test.description, test.builder, test.handler)
|
|
100
104
|
.command(run.command, run.description, run.builder, run.handler)
|
|
101
105
|
.command(dlx.command, dlx.description, dlx.builder, dlx.handler)
|
|
@@ -132,6 +136,7 @@ export async function runCli(argv) {
|
|
|
132
136
|
.command(dev.command, dev.description, dev.builder, dev.handler)
|
|
133
137
|
.command(debug.command, debug.description, debug.builder, debug.handler)
|
|
134
138
|
.command(browse.command, browse.description, browse.builder, browse.handler)
|
|
139
|
+
.command(webext.command, webext.description, webext.builder, webext.handler)
|
|
135
140
|
.demandCommand(1)
|
|
136
141
|
.epilogue(`Running on ${runtimeLabel()}`)
|
|
137
142
|
.help()
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type Workspace } from '@gjsify/workspace';
|
|
2
|
+
import type { ScriptReferrers } from './affected-script-refs.js';
|
|
2
3
|
export interface ClassifyResult {
|
|
3
4
|
/** Cannot decide precisely — caller should run full suite. */
|
|
4
5
|
global: boolean;
|
|
@@ -13,4 +14,9 @@ export interface ClassifyResult {
|
|
|
13
14
|
/** Diff was empty AND no triggers fired → CI can skip the whole job. */
|
|
14
15
|
skipAll: boolean;
|
|
15
16
|
}
|
|
16
|
-
|
|
17
|
+
/**
|
|
18
|
+
* @param readersOf who reads a root `scripts/*` file. Omitted, a changed root script stays
|
|
19
|
+
* `unmatched` and forces the full run — the behaviour before the lookup existed, and what
|
|
20
|
+
* the command falls back to when it cannot list the tree.
|
|
21
|
+
*/
|
|
22
|
+
export declare function classifyAndExpand(workspaces: readonly Workspace[], changedFiles: readonly string[], readersOf?: ScriptReferrers): ClassifyResult;
|
|
@@ -49,8 +49,10 @@ const GLOBAL_TRIGGERS = [
|
|
|
49
49
|
*/
|
|
50
50
|
const OTHER_WORKFLOW_INPUTS = [
|
|
51
51
|
// Each sibling workflow's own definition. `main.yml` is deliberately absent: it
|
|
52
|
-
// is a GLOBAL_TRIGGER instead.
|
|
53
|
-
|
|
52
|
+
// is a GLOBAL_TRIGGER instead. The three OS-suite workflows run unfiltered on every
|
|
53
|
+
// PR, so an edit to one is measured by that run; `webview2-probe.yml` is absent on
|
|
54
|
+
// purpose, being dispatch-only — nothing would measure an edit to it on the PR.
|
|
55
|
+
/^\.github\/workflows\/(deploy-docs|commitlint|release|release-cut|audit-runtimes|prebuilds|node-gi|napi|cli-cross-platform|build-ci-image|cancel-pr-runs|macos-suites|windows-suites|gtk-os-suites)\.yml$/,
|
|
54
56
|
// `prebuilds.yml`'s toolchain (#838): the QEMU-emulated build script and the
|
|
55
57
|
// classifier deciding which native packages a prebuild run rebuilds. It is in
|
|
56
58
|
// both of that workflow's `paths:` filters; `main.yml` builds no prebuild and
|
|
@@ -168,7 +170,51 @@ const SCRIPT_COUPLINGS = [
|
|
|
168
170
|
why: 'tests/e2e/react-native-devtools is the only external observer of AppRegistry.runApplication',
|
|
169
171
|
},
|
|
170
172
|
];
|
|
171
|
-
|
|
173
|
+
/** A root script whose readers can stand in for it (see `affected-script-refs.ts`). */
|
|
174
|
+
const ROOT_SCRIPT = /^scripts\/[^/]+$/;
|
|
175
|
+
function isResolvableScript(f) {
|
|
176
|
+
return (ROOT_SCRIPT.test(f) &&
|
|
177
|
+
!GLOBAL_TRIGGERS.some((re) => re.test(f)) &&
|
|
178
|
+
!SCRIPT_COUPLINGS.some((c) => c.match.test(f)));
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Replace each changed root script by the files that read it, recursively through scripts
|
|
182
|
+
* that read scripts. Readers go back through IGNORE here and through GLOBAL / workspace
|
|
183
|
+
* mapping in the caller, so a reader this classifier does not model still forces the full
|
|
184
|
+
* run, and a script a GLOBAL_TRIGGER reads (`audit-runtimes.mjs`) stays in and fires it.
|
|
185
|
+
*/
|
|
186
|
+
function resolveRootScripts(files, readersOf) {
|
|
187
|
+
const out = new Set();
|
|
188
|
+
const queue = [];
|
|
189
|
+
for (const f of files) {
|
|
190
|
+
if (isResolvableScript(f))
|
|
191
|
+
queue.push(f);
|
|
192
|
+
else
|
|
193
|
+
out.add(f);
|
|
194
|
+
}
|
|
195
|
+
const seen = new Set();
|
|
196
|
+
while (queue.length > 0) {
|
|
197
|
+
const s = queue.shift();
|
|
198
|
+
if (seen.has(s))
|
|
199
|
+
continue;
|
|
200
|
+
seen.add(s);
|
|
201
|
+
for (const r of readersOf(s)) {
|
|
202
|
+
if (IGNORE.some((re) => re.test(r)))
|
|
203
|
+
continue;
|
|
204
|
+
if (isResolvableScript(r))
|
|
205
|
+
queue.push(r);
|
|
206
|
+
else
|
|
207
|
+
out.add(r);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
return { files: [...out], scripts: seen.size };
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* @param readersOf who reads a root `scripts/*` file. Omitted, a changed root script stays
|
|
214
|
+
* `unmatched` and forces the full run — the behaviour before the lookup existed, and what
|
|
215
|
+
* the command falls back to when it cannot list the tree.
|
|
216
|
+
*/
|
|
217
|
+
export function classifyAndExpand(workspaces, changedFiles, readersOf) {
|
|
172
218
|
const files = changedFiles.map((f) => f.replace(/\\/g, '/')).filter((f) => f.length > 0);
|
|
173
219
|
if (files.length === 0) {
|
|
174
220
|
return {
|
|
@@ -182,16 +228,26 @@ export function classifyAndExpand(workspaces, changedFiles) {
|
|
|
182
228
|
}
|
|
183
229
|
// Ignored files go FIRST, before the global-trigger check: ignore wins over
|
|
184
230
|
// global, so `packages/infra/cli/README.md` must not force a full run.
|
|
185
|
-
|
|
231
|
+
let remaining = [];
|
|
186
232
|
for (const f of files) {
|
|
187
233
|
if (IGNORE.some((re) => re.test(f)))
|
|
188
234
|
continue;
|
|
189
235
|
remaining.push(f);
|
|
190
236
|
}
|
|
237
|
+
// Every verdict below says when it was reached through a script's readers, so a
|
|
238
|
+
// surprising selection can be traced back to the lookup rather than the diff.
|
|
239
|
+
let note = '';
|
|
240
|
+
if (readersOf) {
|
|
241
|
+
const resolved = resolveRootScripts(remaining, readersOf);
|
|
242
|
+
if (resolved.scripts > 0) {
|
|
243
|
+
remaining = resolved.files;
|
|
244
|
+
note = `; ${resolved.scripts} root script(s) resolved to their readers`;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
191
247
|
if (remaining.length === 0) {
|
|
192
248
|
return {
|
|
193
249
|
global: false,
|
|
194
|
-
reason: 'ignored-only',
|
|
250
|
+
reason: 'ignored-only' + note,
|
|
195
251
|
workspaces: [],
|
|
196
252
|
runE2E: false,
|
|
197
253
|
runIntegration: false,
|
|
@@ -204,7 +260,7 @@ export function classifyAndExpand(workspaces, changedFiles) {
|
|
|
204
260
|
if (re.test(f)) {
|
|
205
261
|
return {
|
|
206
262
|
global: true,
|
|
207
|
-
reason: `global-trigger ${re.source} matched ${f}`,
|
|
263
|
+
reason: `global-trigger ${re.source} matched ${f}${note}`,
|
|
208
264
|
workspaces: workspaces.map((w) => w.name),
|
|
209
265
|
runE2E: true,
|
|
210
266
|
runIntegration: true,
|
|
@@ -254,7 +310,7 @@ export function classifyAndExpand(workspaces, changedFiles) {
|
|
|
254
310
|
if (stillUnmatched.length > 0) {
|
|
255
311
|
return {
|
|
256
312
|
global: true,
|
|
257
|
-
reason: `unmatched files (${stillUnmatched.length}): ${stillUnmatched.slice(0, 3).join(', ')}${stillUnmatched.length > 3 ? '…' : ''}`,
|
|
313
|
+
reason: `unmatched files (${stillUnmatched.length}): ${stillUnmatched.slice(0, 3).join(', ')}${stillUnmatched.length > 3 ? '…' : ''}${note}`,
|
|
258
314
|
workspaces: workspaces.map((w) => w.name),
|
|
259
315
|
runE2E: true,
|
|
260
316
|
runIntegration: true,
|
|
@@ -274,7 +330,7 @@ export function classifyAndExpand(workspaces, changedFiles) {
|
|
|
274
330
|
const touchedIntegration = remaining.some((f) => f.startsWith('tests/integration/'));
|
|
275
331
|
return {
|
|
276
332
|
global: false,
|
|
277
|
-
reason: `test-only (${remaining.length} file(s) in ${only})`,
|
|
333
|
+
reason: `test-only (${remaining.length} file(s) in ${only})${note}`,
|
|
278
334
|
workspaces: [only],
|
|
279
335
|
// `|| couplingRunE2E`: this shortcut skips CLOSURE EXPANSION, and a
|
|
280
336
|
// declared tier is not part of the closure. Dropping it here made a
|
|
@@ -323,7 +379,8 @@ export function classifyAndExpand(workspaces, changedFiles) {
|
|
|
323
379
|
return {
|
|
324
380
|
global: false,
|
|
325
381
|
reason: `closure (${closure.size} ws from ${matched.size} seed(s))` +
|
|
326
|
-
(couplingSeeds.size > 0 ? `, ${couplingSeeds.size} via script-coupling` : '')
|
|
382
|
+
(couplingSeeds.size > 0 ? `, ${couplingSeeds.size} via script-coupling` : '') +
|
|
383
|
+
note,
|
|
327
384
|
workspaces: [...closure].sort(),
|
|
328
385
|
runE2E,
|
|
329
386
|
runIntegration,
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** Every file that names `scriptPath`, as repo-relative paths. */
|
|
2
|
+
export type ScriptReferrers = (scriptPath: string) => readonly string[];
|
|
3
|
+
/**
|
|
4
|
+
* The file-name pattern for a script: `adwaita-elements.mjs` is also read as
|
|
5
|
+
* `adwaita-elements.d.mts` (a TS import of the `.mjs` resolves to its declaration) and a
|
|
6
|
+
* `.d.mts` change is read through its `.mjs`. The leading boundary excludes `-` so
|
|
7
|
+
* `value-types.mjs` does not match `generate-value-types.mjs`.
|
|
8
|
+
*/
|
|
9
|
+
export declare function scriptNamePattern(scriptPath: string): RegExp;
|
|
10
|
+
/**
|
|
11
|
+
* Build the reader lookup over `texts` (repo-relative path → raw content). Pure: the command
|
|
12
|
+
* feeds it `git ls-files`, the spec feeds it a fixture map.
|
|
13
|
+
*/
|
|
14
|
+
export declare function buildScriptReferrers(texts: ReadonlyMap<string, string>): ScriptReferrers;
|
|
15
|
+
/**
|
|
16
|
+
* Every tracked text file under `rootDir`, for {@link buildScriptReferrers}. Throws when git
|
|
17
|
+
* cannot list the tree — the caller then classifies without the lookup, which is the old,
|
|
18
|
+
* conservative behaviour (a root script lands in `unmatched`).
|
|
19
|
+
*/
|
|
20
|
+
export declare function readTrackedTexts(rootDir: string): Map<string, string>;
|