@gjsify/cli 0.64.18 → 0.64.20
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/README.md +3 -1
- package/dist/cli.gjs.mjs +331 -334
- package/lib/commands/flatpak/check.d.ts +3 -0
- package/lib/commands/flatpak/check.js +14 -4
- package/lib/commands/site.js +10 -100
- package/lib/commands/webext/index.js +3 -2
- package/lib/commands/webext/subcommands.d.ts +13 -0
- package/lib/commands/webext/subcommands.js +65 -0
- package/lib/utils/site-dispatch.d.ts +33 -0
- package/lib/utils/site-dispatch.js +104 -0
- package/package.json +20 -20
|
@@ -8,8 +8,11 @@ interface FlatpakCheckOptions {
|
|
|
8
8
|
strict?: boolean;
|
|
9
9
|
json?: boolean;
|
|
10
10
|
qualityNetwork?: boolean;
|
|
11
|
+
appstreamNetwork?: boolean;
|
|
11
12
|
builderLint?: boolean;
|
|
12
13
|
verbose?: boolean;
|
|
13
14
|
}
|
|
15
|
+
/** argv for `appstreamcli`; offline unless the caller opts in to URL reachability checks. */
|
|
16
|
+
export declare function appstreamValidateArgs(metainfoAbs: string, network?: boolean): string[];
|
|
14
17
|
export declare const flatpakCheckCommand: Command<unknown, FlatpakCheckOptions>;
|
|
15
18
|
export {};
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
// `gjsify flatpak check` — run Flathub's pre-submission linters locally.
|
|
2
2
|
//
|
|
3
3
|
// Wraps two tools:
|
|
4
|
-
// - `appstreamcli validate --strict <metainfo>` — MetaInfo XML
|
|
5
|
-
// correctness check
|
|
4
|
+
// - `appstreamcli validate --strict --no-net <metainfo>` — MetaInfo XML
|
|
5
|
+
// correctness check; offline unless `--appstream-network` (a URL that
|
|
6
|
+
// is merely unreachable from the runner must not fail the gate)
|
|
6
7
|
// - `flatpak-builder-lint manifest <manifest.json>` — manifest
|
|
7
8
|
// correctness check (and optionally `repo` for built artefacts)
|
|
8
9
|
//
|
|
@@ -15,6 +16,10 @@ import { spawnToCompletion } from '../../utils/spawn.js';
|
|
|
15
16
|
import { readPackageJson, looksLikeAppId } from './utils.js';
|
|
16
17
|
import { Config } from '../../config.js';
|
|
17
18
|
import { formatFinding, lintMetainfo, readImageInfo, summarizeFindings, } from '../../utils/metainfo-quality.js';
|
|
19
|
+
/** argv for `appstreamcli`; offline unless the caller opts in to URL reachability checks. */
|
|
20
|
+
export function appstreamValidateArgs(metainfoAbs, network = false) {
|
|
21
|
+
return ['validate', '--strict', ...(network ? [] : ['--no-net']), metainfoAbs];
|
|
22
|
+
}
|
|
18
23
|
export const flatpakCheckCommand = {
|
|
19
24
|
command: 'check [manifest]',
|
|
20
25
|
description: 'Run Flathub pre-submission linters: appstreamcli validate + flatpak-builder-lint.',
|
|
@@ -36,7 +41,7 @@ export const flatpakCheckCommand = {
|
|
|
36
41
|
normalize: true,
|
|
37
42
|
})
|
|
38
43
|
.option('appstream', {
|
|
39
|
-
description: 'Run `appstreamcli validate --strict` (default: true).',
|
|
44
|
+
description: 'Run `appstreamcli validate --strict --no-net` (default: true).',
|
|
40
45
|
type: 'boolean',
|
|
41
46
|
default: true,
|
|
42
47
|
})
|
|
@@ -59,6 +64,11 @@ export const flatpakCheckCommand = {
|
|
|
59
64
|
description: 'Let the quality check fetch http(s) screenshot/icon URLs to measure their size.',
|
|
60
65
|
type: 'boolean',
|
|
61
66
|
default: false,
|
|
67
|
+
})
|
|
68
|
+
.option('appstream-network', {
|
|
69
|
+
description: 'Let `appstreamcli` fetch the MetaInfo URLs to check they are reachable.',
|
|
70
|
+
type: 'boolean',
|
|
71
|
+
default: false,
|
|
62
72
|
})
|
|
63
73
|
.option('builder-lint', {
|
|
64
74
|
description: 'Run `flatpak-builder-lint manifest` (default: true).',
|
|
@@ -86,7 +96,7 @@ export const flatpakCheckCommand = {
|
|
|
86
96
|
console.warn(`[gjsify flatpak check] skipping appstreamcli — ${metainfoAbs} not found`);
|
|
87
97
|
}
|
|
88
98
|
else {
|
|
89
|
-
const ok = await runLinter('appstreamcli',
|
|
99
|
+
const ok = await runLinter('appstreamcli', appstreamValidateArgs(metainfoAbs, args.appstreamNetwork === true), args.verbose ?? false);
|
|
90
100
|
if (!ok)
|
|
91
101
|
failures++;
|
|
92
102
|
}
|
package/lib/commands/site.js
CHANGED
|
@@ -21,55 +21,8 @@
|
|
|
21
21
|
// The resolved install directory is passed to the child as `--package-dir`. A
|
|
22
22
|
// bundle's `import.meta.url` is the OUTFILE, so the library cannot find its own
|
|
23
23
|
// `po/` and `lib/client/` on its own — only the caller still knows.
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
26
|
-
import { dirname, join, resolve } from 'node:path';
|
|
27
|
-
import { hostRuntime } from '@gjsify/rolldown-plugin-gjsify/runtime';
|
|
28
|
-
import { resolveNodeGi } from '../utils/run-node.js';
|
|
29
|
-
/** The `@gjsify/site` install reachable from `cwd`, walking the node_modules chain upwards. */
|
|
30
|
-
function resolveSitePackage(cwd) {
|
|
31
|
-
let dir = resolve(cwd);
|
|
32
|
-
for (;;) {
|
|
33
|
-
const candidate = join(dir, 'node_modules', '@gjsify', 'site');
|
|
34
|
-
if (existsSync(join(candidate, 'package.json')))
|
|
35
|
-
return candidate;
|
|
36
|
-
const parent = dirname(dir);
|
|
37
|
-
if (parent === dir)
|
|
38
|
-
return undefined;
|
|
39
|
-
dir = parent;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
function gjsOnPath() {
|
|
43
|
-
return spawnSync('gjs', ['--version'], { stdio: 'ignore' }).status === 0;
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* The runtime the page is built for. An explicit `--runtime` wins. Otherwise the host runtime —
|
|
47
|
-
* except that a non-gjs host without `@gjsify/node-gi` in the project cannot run the `--app node`
|
|
48
|
-
* bundle (GdkPixbuf is reached through it), so a consumer that only ran
|
|
49
|
-
* `npm i -D @gjsify/site` falls back to gjs when the system has one.
|
|
50
|
-
*/
|
|
51
|
-
function pickRuntime(requested, cwd) {
|
|
52
|
-
if (requested)
|
|
53
|
-
return requested;
|
|
54
|
-
const host = hostRuntime();
|
|
55
|
-
if (host === 'gjs' || resolveNodeGi(cwd))
|
|
56
|
-
return host;
|
|
57
|
-
return gjsOnPath() ? 'gjs' : host;
|
|
58
|
-
}
|
|
59
|
-
/**
|
|
60
|
-
* The generated entry. Arguments arrive as ARGV rather than baked in, so the cached bundle serves
|
|
61
|
-
* every invocation — flags change far more often than this does.
|
|
62
|
-
*
|
|
63
|
-
* The exit is spelled per runtime on purpose. Under GJS `process.exit` does not halt and loses its
|
|
64
|
-
* code (the `gjsify storybook` measurement), so the gjs entry uses `system.exit`; both read the
|
|
65
|
-
* user arguments from where their own runtime puts them.
|
|
66
|
-
*/
|
|
67
|
-
function generateEntry(app) {
|
|
68
|
-
const header = `// Auto-generated by \`gjsify site\` — do not edit by hand.\nimport { runSiteCli } from '@gjsify/site';\n`;
|
|
69
|
-
return app === 'gjs'
|
|
70
|
-
? `${header}import system from 'system';\n\nsystem.exit(await runSiteCli(system.programArgs));\n`
|
|
71
|
-
: `${header}\nprocess.exit(await runSiteCli(process.argv.slice(2)));\n`;
|
|
72
|
-
}
|
|
24
|
+
import { resolve } from 'node:path';
|
|
25
|
+
import { dispatchSite } from '../utils/site-dispatch.js';
|
|
73
26
|
export const siteCommand = {
|
|
74
27
|
command: 'site <operation>',
|
|
75
28
|
description: "Render this project's static landing page from its AppStream metainfo (downloads, screenshots, " +
|
|
@@ -123,45 +76,7 @@ export const siteCommand = {
|
|
|
123
76
|
.option('globals', { description: 'Value for `gjsify build --globals` (default: auto)', type: 'string' }),
|
|
124
77
|
handler: async (args) => {
|
|
125
78
|
const cwd = process.cwd();
|
|
126
|
-
const
|
|
127
|
-
if (!packageDir) {
|
|
128
|
-
console.error('gjsify site: @gjsify/site is not installed in this project.\n\n' +
|
|
129
|
-
' The generator ships as its own package so a project only pays for it when it\n' +
|
|
130
|
-
' publishes a page. Add it, then run this again:\n\n' +
|
|
131
|
-
' npm install --save-dev @gjsify/site');
|
|
132
|
-
return process.exit(1);
|
|
133
|
-
}
|
|
134
|
-
if (!existsSync(join(packageDir, 'lib', 'client', 'site.js'))) {
|
|
135
|
-
console.error(`gjsify site: ${packageDir} has no built client bundle (lib/client/site.js).\n` +
|
|
136
|
-
' In a source checkout, build the package first: `gjsify workspace site build`.');
|
|
137
|
-
return process.exit(1);
|
|
138
|
-
}
|
|
139
|
-
const runtime = pickRuntime(args.runtime, cwd);
|
|
140
|
-
const app = runtime === 'gjs' ? 'gjs' : 'node';
|
|
141
|
-
const cacheDir = join(cwd, 'node_modules', '.cache', 'gjsify-site');
|
|
142
|
-
mkdirSync(cacheDir, { recursive: true });
|
|
143
|
-
const entryPath = join(cacheDir, `entry.${app}.ts`);
|
|
144
|
-
const outPath = join(cacheDir, `site.${app}.mjs`);
|
|
145
|
-
writeFileSync(entryPath, generateEntry(app));
|
|
146
|
-
const globals = args.globals ?? 'auto';
|
|
147
|
-
if (app === 'gjs') {
|
|
148
|
-
// The consumer installed `@gjsify/site`, not the polyfills `--globals auto` injects
|
|
149
|
-
// (URL, DOMException, streams, …), so those resolve from beside the running CLI.
|
|
150
|
-
const { BuildAction } = await import('../actions/build.js');
|
|
151
|
-
await BuildAction.bundleFileForGjs(entryPath, outPath, {
|
|
152
|
-
globals,
|
|
153
|
-
preserveDefaultExport: false,
|
|
154
|
-
toolchainAnchor: BuildAction.runningCliFile(),
|
|
155
|
-
logLevel: 'silent',
|
|
156
|
-
});
|
|
157
|
-
}
|
|
158
|
-
else {
|
|
159
|
-
const { runCli } = await import('../cli-app.js');
|
|
160
|
-
await runCli(['build', entryPath, '--app', app, '--globals', globals, '--outfile', outPath]);
|
|
161
|
-
}
|
|
162
|
-
// RESOLVED values, not the raw argv: the child parses its own flags and
|
|
163
|
-
// cannot know where this CLI found the package.
|
|
164
|
-
const forwarded = [args.operation, '--package-dir', packageDir];
|
|
79
|
+
const forwarded = [args.operation];
|
|
165
80
|
if (args.root)
|
|
166
81
|
forwarded.push('--root', resolve(cwd, args.root));
|
|
167
82
|
if (args.out)
|
|
@@ -178,17 +93,12 @@ export const siteCommand = {
|
|
|
178
93
|
forwarded.push('--check');
|
|
179
94
|
if (args.package)
|
|
180
95
|
forwarded.push('--package');
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
await runNodeBundle(outPath, forwarded, { completion: 'exit', exitOnSuccess: true });
|
|
189
|
-
return;
|
|
190
|
-
}
|
|
191
|
-
const { runRuntimeBundle } = await import('../utils/run-node.js');
|
|
192
|
-
await runRuntimeBundle(runtime, outPath, forwarded, { completion: 'exit', exitOnSuccess: true });
|
|
96
|
+
await dispatchSite({
|
|
97
|
+
invokedAs: 'gjsify site',
|
|
98
|
+
argv: forwarded,
|
|
99
|
+
runtime: args.runtime,
|
|
100
|
+
globals: args.globals,
|
|
101
|
+
needsClient: args.operation === 'build',
|
|
102
|
+
});
|
|
193
103
|
},
|
|
194
104
|
};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// `gjsify webext` — yargs subcommand-group dispatcher (ADR 0077).
|
|
2
2
|
//
|
|
3
|
-
// Wires {build, zip, dev}; each is a self-contained `Command<>` in `subcommands.ts`,
|
|
3
|
+
// Wires {build, zip, dev, listing}; each is a self-contained `Command<>` in `subcommands.ts`,
|
|
4
4
|
// the same composition `flatpak/index.ts` uses.
|
|
5
|
-
import { webextBuildCommand, webextDevCommand, webextZipCommand } from './subcommands.js';
|
|
5
|
+
import { webextBuildCommand, webextDevCommand, webextListingCommand, webextZipCommand } from './subcommands.js';
|
|
6
6
|
export const webextCommand = {
|
|
7
7
|
command: 'webext <subcommand>',
|
|
8
8
|
description: 'Browser extensions: build, zip and develop one WebExtension for Chrome, Edge, Firefox, Opera and Safari.',
|
|
@@ -10,6 +10,7 @@ export const webextCommand = {
|
|
|
10
10
|
.command(webextBuildCommand.command, webextBuildCommand.description, webextBuildCommand.builder, webextBuildCommand.handler)
|
|
11
11
|
.command(webextZipCommand.command, webextZipCommand.description, webextZipCommand.builder, webextZipCommand.handler)
|
|
12
12
|
.command(webextDevCommand.command, webextDevCommand.description, webextDevCommand.builder, webextDevCommand.handler)
|
|
13
|
+
.command(webextListingCommand.command, webextListingCommand.description, webextListingCommand.builder, webextListingCommand.handler)
|
|
13
14
|
.demandCommand(1)
|
|
14
15
|
.strict(),
|
|
15
16
|
};
|
|
@@ -13,4 +13,17 @@ interface WebextArgs {
|
|
|
13
13
|
export declare const webextBuildCommand: Command<unknown, WebextArgs>;
|
|
14
14
|
export declare const webextZipCommand: Command<unknown, WebextArgs>;
|
|
15
15
|
export declare const webextDevCommand: Command<unknown, WebextArgs>;
|
|
16
|
+
interface ListingArgs {
|
|
17
|
+
store: string;
|
|
18
|
+
out?: string;
|
|
19
|
+
check: boolean;
|
|
20
|
+
metainfo?: string;
|
|
21
|
+
config?: string;
|
|
22
|
+
pot?: string;
|
|
23
|
+
root?: string;
|
|
24
|
+
offline: boolean;
|
|
25
|
+
runtime?: string;
|
|
26
|
+
globals?: string;
|
|
27
|
+
}
|
|
28
|
+
export declare const webextListingCommand: Command<unknown, ListingArgs>;
|
|
16
29
|
export {};
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
// runs, re-entered in-process like `gjsify dev` does.
|
|
6
6
|
import { existsSync, mkdirSync, readdirSync, readFileSync } from 'node:fs';
|
|
7
7
|
import { dirname, join, resolve, sep } from 'node:path';
|
|
8
|
+
import { dispatchSite } from '../../utils/site-dispatch.js';
|
|
8
9
|
import { buildWebext } from '../../utils/webext/build.js';
|
|
9
10
|
import { resolveWebextConfig, selectTargets } from '../../utils/webext/config.js';
|
|
10
11
|
import { defaultDevProfile, resolveWebExt, WEB_EXT_MISSING, webExtRunArgs, } from '../../utils/webext/launch.js';
|
|
@@ -202,3 +203,67 @@ export const webextDevCommand = {
|
|
|
202
203
|
});
|
|
203
204
|
},
|
|
204
205
|
};
|
|
206
|
+
export const webextListingCommand = {
|
|
207
|
+
command: 'listing',
|
|
208
|
+
description: 'Derive the store listings (Chrome Web Store, Edge Add-ons, Firefox AMO) from the AppStream metainfo, ' +
|
|
209
|
+
'the gettext catalogues and the screenshots: texts, permission justifications and exact-size images.',
|
|
210
|
+
builder: (yargs) => yargs
|
|
211
|
+
.option('store', {
|
|
212
|
+
description: 'Which store to write (default: all).',
|
|
213
|
+
type: 'string',
|
|
214
|
+
choices: ['cws', 'edge', 'amo', 'all'],
|
|
215
|
+
default: 'all',
|
|
216
|
+
})
|
|
217
|
+
.option('out', { description: 'Output directory, emptied first (default: dist/listing).', type: 'string' })
|
|
218
|
+
.option('check', {
|
|
219
|
+
description: 'Validate against the store limits; write nothing.',
|
|
220
|
+
type: 'boolean',
|
|
221
|
+
default: false,
|
|
222
|
+
})
|
|
223
|
+
.option('metainfo', {
|
|
224
|
+
description: 'AppStream metainfo (default: gjsify.webext.listing.metainfo, else gjsify.site.metainfo).',
|
|
225
|
+
type: 'string',
|
|
226
|
+
})
|
|
227
|
+
.option('config', {
|
|
228
|
+
description: 'JSON file that overrides the gjsify.webext.listing block of package.json.',
|
|
229
|
+
type: 'string',
|
|
230
|
+
})
|
|
231
|
+
.option('pot', { description: 'Also write the config strings as a gettext template.', type: 'string' })
|
|
232
|
+
.option('root', { description: 'Project root (default: the working directory).', type: 'string' })
|
|
233
|
+
.option('offline', {
|
|
234
|
+
description: 'Skip downloading screenshots hosted elsewhere.',
|
|
235
|
+
type: 'boolean',
|
|
236
|
+
default: false,
|
|
237
|
+
})
|
|
238
|
+
.option('runtime', {
|
|
239
|
+
description: 'Runtime to run on: gjs | node | bun | deno (default: the host runtime).',
|
|
240
|
+
type: 'string',
|
|
241
|
+
choices: ['gjs', 'node', 'bun', 'deno'],
|
|
242
|
+
})
|
|
243
|
+
.option('globals', { description: 'Value for `gjsify build --globals` (default: auto).', type: 'string' }),
|
|
244
|
+
handler: async (args) => {
|
|
245
|
+
const cwd = process.cwd();
|
|
246
|
+
const forwarded = ['listing', '--store', args.store];
|
|
247
|
+
if (args.root)
|
|
248
|
+
forwarded.push('--root', resolve(cwd, args.root));
|
|
249
|
+
if (args.out)
|
|
250
|
+
forwarded.push('--out', resolve(cwd, args.out));
|
|
251
|
+
if (args.check)
|
|
252
|
+
forwarded.push('--check');
|
|
253
|
+
if (args.metainfo)
|
|
254
|
+
forwarded.push('--metainfo', args.metainfo);
|
|
255
|
+
if (args.config)
|
|
256
|
+
forwarded.push('--config', resolve(cwd, args.config));
|
|
257
|
+
if (args.pot)
|
|
258
|
+
forwarded.push('--pot', resolve(cwd, args.pot));
|
|
259
|
+
if (args.offline)
|
|
260
|
+
forwarded.push('--offline');
|
|
261
|
+
await dispatchSite({
|
|
262
|
+
invokedAs: 'gjsify webext listing',
|
|
263
|
+
argv: forwarded,
|
|
264
|
+
runtime: args.runtime,
|
|
265
|
+
globals: args.globals,
|
|
266
|
+
needsClient: false,
|
|
267
|
+
});
|
|
268
|
+
},
|
|
269
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/** `gjs` builds `--app gjs`; `node`/`bun`/`deno` build the same `--app node` bundle. */
|
|
2
|
+
export type SiteRuntime = 'gjs' | 'node' | 'bun' | 'deno';
|
|
3
|
+
/** The `@gjsify/site` install reachable from `cwd`, walking the node_modules chain upwards. */
|
|
4
|
+
export declare function resolveSitePackage(cwd: string): string | undefined;
|
|
5
|
+
export declare function gjsOnPath(): boolean;
|
|
6
|
+
/**
|
|
7
|
+
* The runtime the page is built for. An explicit `--runtime` wins. Otherwise the host runtime —
|
|
8
|
+
* except that a non-gjs host without `@gjsify/node-gi` in the project cannot run the `--app node`
|
|
9
|
+
* bundle (GdkPixbuf is reached through it), so a consumer that only ran
|
|
10
|
+
* `npm i -D @gjsify/site` falls back to gjs when the system has one.
|
|
11
|
+
*/
|
|
12
|
+
export declare function pickRuntime(requested: string | undefined, cwd: string): SiteRuntime;
|
|
13
|
+
/**
|
|
14
|
+
* The generated entry. Arguments arrive as ARGV rather than baked in, so the cached bundle serves
|
|
15
|
+
* every invocation — flags change far more often than this does.
|
|
16
|
+
*
|
|
17
|
+
* The exit is spelled per runtime on purpose. Under GJS `process.exit` does not halt and loses its
|
|
18
|
+
* code (the `gjsify storybook` measurement), so the gjs entry uses `system.exit`; both read the
|
|
19
|
+
* user arguments from where their own runtime puts them.
|
|
20
|
+
*/
|
|
21
|
+
export declare function generateEntry(app: 'gjs' | 'node', command?: string): string;
|
|
22
|
+
export interface SiteDispatch {
|
|
23
|
+
/** What the generated entry's header names as its author. */
|
|
24
|
+
invokedAs: string;
|
|
25
|
+
/** Forwarded to `runSiteCli` after `--package-dir`. */
|
|
26
|
+
argv: string[];
|
|
27
|
+
runtime?: string;
|
|
28
|
+
globals?: string;
|
|
29
|
+
/** Whether `lib/client/site.js` must exist (only the page build ships it to the browser). */
|
|
30
|
+
needsClient: boolean;
|
|
31
|
+
}
|
|
32
|
+
/** Resolves `@gjsify/site`, bundles the entry for the chosen runtime, and runs it; exits the process. */
|
|
33
|
+
export declare function dispatchSite(options: SiteDispatch): Promise<void>;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
// Shared by `gjsify site` and `gjsify webext listing`: both run `runSiteCli` from the CONSUMER's
|
|
2
|
+
// `@gjsify/site`, bundled for the runtime the CLI itself is on (see `commands/site.ts` for why).
|
|
3
|
+
import { spawnSync } from 'node:child_process';
|
|
4
|
+
import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
5
|
+
import { dirname, join, resolve } from 'node:path';
|
|
6
|
+
import { hostRuntime } from '@gjsify/rolldown-plugin-gjsify/runtime';
|
|
7
|
+
import { resolveNodeGi } from './run-node.js';
|
|
8
|
+
/** The `@gjsify/site` install reachable from `cwd`, walking the node_modules chain upwards. */
|
|
9
|
+
export function resolveSitePackage(cwd) {
|
|
10
|
+
let dir = resolve(cwd);
|
|
11
|
+
for (;;) {
|
|
12
|
+
const candidate = join(dir, 'node_modules', '@gjsify', 'site');
|
|
13
|
+
if (existsSync(join(candidate, 'package.json')))
|
|
14
|
+
return candidate;
|
|
15
|
+
const parent = dirname(dir);
|
|
16
|
+
if (parent === dir)
|
|
17
|
+
return undefined;
|
|
18
|
+
dir = parent;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export function gjsOnPath() {
|
|
22
|
+
return spawnSync('gjs', ['--version'], { stdio: 'ignore' }).status === 0;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* The runtime the page is built for. An explicit `--runtime` wins. Otherwise the host runtime —
|
|
26
|
+
* except that a non-gjs host without `@gjsify/node-gi` in the project cannot run the `--app node`
|
|
27
|
+
* bundle (GdkPixbuf is reached through it), so a consumer that only ran
|
|
28
|
+
* `npm i -D @gjsify/site` falls back to gjs when the system has one.
|
|
29
|
+
*/
|
|
30
|
+
export function pickRuntime(requested, cwd) {
|
|
31
|
+
if (requested)
|
|
32
|
+
return requested;
|
|
33
|
+
const host = hostRuntime();
|
|
34
|
+
if (host === 'gjs' || resolveNodeGi(cwd))
|
|
35
|
+
return host;
|
|
36
|
+
return gjsOnPath() ? 'gjs' : host;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* The generated entry. Arguments arrive as ARGV rather than baked in, so the cached bundle serves
|
|
40
|
+
* every invocation — flags change far more often than this does.
|
|
41
|
+
*
|
|
42
|
+
* The exit is spelled per runtime on purpose. Under GJS `process.exit` does not halt and loses its
|
|
43
|
+
* code (the `gjsify storybook` measurement), so the gjs entry uses `system.exit`; both read the
|
|
44
|
+
* user arguments from where their own runtime puts them.
|
|
45
|
+
*/
|
|
46
|
+
export function generateEntry(app, command = 'gjsify site') {
|
|
47
|
+
const header = `// Auto-generated by \`${command}\` — do not edit by hand.\nimport { runSiteCli } from '@gjsify/site';\n`;
|
|
48
|
+
return app === 'gjs'
|
|
49
|
+
? `${header}import system from 'system';\n\nsystem.exit(await runSiteCli(system.programArgs));\n`
|
|
50
|
+
: `${header}\nprocess.exit(await runSiteCli(process.argv.slice(2)));\n`;
|
|
51
|
+
}
|
|
52
|
+
/** Resolves `@gjsify/site`, bundles the entry for the chosen runtime, and runs it; exits the process. */
|
|
53
|
+
export async function dispatchSite(options) {
|
|
54
|
+
const cwd = process.cwd();
|
|
55
|
+
const packageDir = resolveSitePackage(cwd);
|
|
56
|
+
if (!packageDir) {
|
|
57
|
+
console.error(`${options.invokedAs}: @gjsify/site is not installed in this project.\n\n` +
|
|
58
|
+
' The generator ships as its own package so a project only pays for it when it\n' +
|
|
59
|
+
' publishes a page or a store listing. Add it, then run this again:\n\n' +
|
|
60
|
+
' npm install --save-dev @gjsify/site');
|
|
61
|
+
return process.exit(1);
|
|
62
|
+
}
|
|
63
|
+
if (options.needsClient && !existsSync(join(packageDir, 'lib', 'client', 'site.js'))) {
|
|
64
|
+
console.error(`${options.invokedAs}: ${packageDir} has no built client bundle (lib/client/site.js).\n` +
|
|
65
|
+
' In a source checkout, build the package first: `gjsify workspace site build`.');
|
|
66
|
+
return process.exit(1);
|
|
67
|
+
}
|
|
68
|
+
const runtime = pickRuntime(options.runtime, cwd);
|
|
69
|
+
const app = runtime === 'gjs' ? 'gjs' : 'node';
|
|
70
|
+
const cacheDir = join(cwd, 'node_modules', '.cache', 'gjsify-site');
|
|
71
|
+
mkdirSync(cacheDir, { recursive: true });
|
|
72
|
+
const entryPath = join(cacheDir, `entry.${app}.ts`);
|
|
73
|
+
const outPath = join(cacheDir, `site.${app}.mjs`);
|
|
74
|
+
writeFileSync(entryPath, generateEntry(app, options.invokedAs));
|
|
75
|
+
const globals = options.globals ?? 'auto';
|
|
76
|
+
if (app === 'gjs') {
|
|
77
|
+
// The consumer installed `@gjsify/site`, not the polyfills `--globals auto` injects
|
|
78
|
+
// (URL, DOMException, streams, …), so those resolve from beside the running CLI.
|
|
79
|
+
const { BuildAction } = await import('../actions/build.js');
|
|
80
|
+
await BuildAction.bundleFileForGjs(entryPath, outPath, {
|
|
81
|
+
globals,
|
|
82
|
+
preserveDefaultExport: false,
|
|
83
|
+
toolchainAnchor: BuildAction.runningCliFile(),
|
|
84
|
+
logLevel: 'silent',
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
const { runCli } = await import('../cli-app.js');
|
|
89
|
+
await runCli(['build', entryPath, '--app', app, '--globals', globals, '--outfile', outPath]);
|
|
90
|
+
}
|
|
91
|
+
const forwarded = [...options.argv.slice(0, 1), '--package-dir', packageDir, ...options.argv.slice(1)];
|
|
92
|
+
if (runtime === 'gjs') {
|
|
93
|
+
const { runGjsBundle } = await import('./run-gjs.js');
|
|
94
|
+
await runGjsBundle(outPath, forwarded, { completion: 'exit', exitOnSuccess: true });
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
if (runtime === 'node') {
|
|
98
|
+
const { runNodeBundle } = await import('./run-node.js');
|
|
99
|
+
await runNodeBundle(outPath, forwarded, { completion: 'exit', exitOnSuccess: true });
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
const { runRuntimeBundle } = await import('./run-node.js');
|
|
103
|
+
await runRuntimeBundle(runtime, outPath, forwarded, { completion: 'exit', exitOnSuccess: true });
|
|
104
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gjsify/cli",
|
|
3
|
-
"version": "0.64.
|
|
3
|
+
"version": "0.64.20",
|
|
4
4
|
"description": "CLI for Gjsify",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -142,22 +142,22 @@
|
|
|
142
142
|
"cli"
|
|
143
143
|
],
|
|
144
144
|
"dependencies": {
|
|
145
|
-
"@gjsify/blueprint": "^0.64.
|
|
146
|
-
"@gjsify/buffer": "^0.64.
|
|
147
|
-
"@gjsify/create-app": "^0.64.
|
|
148
|
-
"@gjsify/node-globals": "^0.64.
|
|
149
|
-
"@gjsify/node-polyfills": "^0.64.
|
|
150
|
-
"@gjsify/npm-registry": "^0.64.
|
|
151
|
-
"@gjsify/resolve-npm": "^0.64.
|
|
152
|
-
"@gjsify/rolldown-plugin-gjsify": "^0.64.
|
|
153
|
-
"@gjsify/vite-plugin-blueprint": "^0.64.
|
|
154
|
-
"@gjsify/rolldown-plugin-pnp": "^0.64.
|
|
155
|
-
"@gjsify/semver": "^0.64.
|
|
156
|
-
"@gjsify/tar": "^0.64.
|
|
157
|
-
"@gjsify/tsc": "^0.64.
|
|
158
|
-
"@gjsify/utils": "^0.64.
|
|
159
|
-
"@gjsify/web-polyfills": "^0.64.
|
|
160
|
-
"@gjsify/workspace": "^0.64.
|
|
145
|
+
"@gjsify/blueprint": "^0.64.20",
|
|
146
|
+
"@gjsify/buffer": "^0.64.20",
|
|
147
|
+
"@gjsify/create-app": "^0.64.20",
|
|
148
|
+
"@gjsify/node-globals": "^0.64.20",
|
|
149
|
+
"@gjsify/node-polyfills": "^0.64.20",
|
|
150
|
+
"@gjsify/npm-registry": "^0.64.20",
|
|
151
|
+
"@gjsify/resolve-npm": "^0.64.20",
|
|
152
|
+
"@gjsify/rolldown-plugin-gjsify": "^0.64.20",
|
|
153
|
+
"@gjsify/vite-plugin-blueprint": "^0.64.20",
|
|
154
|
+
"@gjsify/rolldown-plugin-pnp": "^0.64.20",
|
|
155
|
+
"@gjsify/semver": "^0.64.20",
|
|
156
|
+
"@gjsify/tar": "^0.64.20",
|
|
157
|
+
"@gjsify/tsc": "^0.64.20",
|
|
158
|
+
"@gjsify/utils": "^0.64.20",
|
|
159
|
+
"@gjsify/web-polyfills": "^0.64.20",
|
|
160
|
+
"@gjsify/workspace": "^0.64.20",
|
|
161
161
|
"acorn": "^8.17.0",
|
|
162
162
|
"cosmiconfig": "^9.0.2",
|
|
163
163
|
"get-tsconfig": "^4.14.0",
|
|
@@ -166,13 +166,13 @@
|
|
|
166
166
|
"yargs": "^18.0.0"
|
|
167
167
|
},
|
|
168
168
|
"devDependencies": {
|
|
169
|
-
"@gjsify/unit": "^0.64.
|
|
169
|
+
"@gjsify/unit": "^0.64.20",
|
|
170
170
|
"@types/yargs": "^17.0.35",
|
|
171
171
|
"typescript": "^6.0.3"
|
|
172
172
|
},
|
|
173
173
|
"peerDependencies": {
|
|
174
|
-
"@gjsify/oxfmt-native": "^0.64.
|
|
175
|
-
"@gjsify/rolldown-native": "^0.64.
|
|
174
|
+
"@gjsify/oxfmt-native": "^0.64.20",
|
|
175
|
+
"@gjsify/rolldown-native": "^0.64.20"
|
|
176
176
|
},
|
|
177
177
|
"peerDependenciesMeta": {
|
|
178
178
|
"@gjsify/oxfmt-native": {
|