@gjsify/cli 0.48.0 → 0.50.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 +165 -157
- package/lib/actions/barrels-generate.d.ts +22 -0
- package/lib/actions/barrels-generate.js +36 -1
- package/lib/actions/build.js +10 -6
- package/lib/commands/barrels.js +19 -2
- package/lib/commands/build.js +4 -0
- package/lib/commands/foreach.js +11 -19
- package/lib/commands/install.js +21 -1
- package/lib/commands/test.d.ts +16 -0
- package/lib/commands/test.js +30 -29
- package/lib/commands/upgrade.js +78 -30
- package/lib/commands/workspace.js +47 -44
- package/lib/config.js +13 -0
- package/lib/index.js +10 -0
- package/lib/types/cli-build-options.d.ts +6 -0
- package/lib/types/config-data.d.ts +14 -0
- package/lib/utils/build-cache.d.ts +15 -4
- package/lib/utils/build-cache.js +62 -67
- package/lib/utils/cli-exit.d.ts +23 -0
- package/lib/utils/cli-exit.js +78 -0
- package/lib/utils/detect-native-packages.d.ts +31 -0
- package/lib/utils/detect-native-packages.js +37 -1
- package/lib/utils/package-inputs.d.ts +81 -0
- package/lib/utils/package-inputs.js +233 -0
- package/lib/utils/ship/changelog.d.ts +15 -14
- package/lib/utils/ship/changelog.js +14 -13
- package/lib/utils/ship/formats.js +23 -2
- package/lib/utils/ship/gzip.d.ts +31 -2
- package/lib/utils/ship/gzip.js +55 -3
- package/lib/utils/ship/plan.d.ts +32 -4
- package/lib/utils/ship/plan.js +61 -10
- package/lib/utils/simple-command.d.ts +17 -2
- package/lib/utils/simple-command.js +9 -4
- package/package.json +19 -19
package/lib/utils/ship/plan.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// as `utils/copy-targets.ts`, and for the same reason: a stager that discovers
|
|
4
4
|
// its own inputs can only be tested by building a real project.
|
|
5
5
|
import { renderDebianChangelog } from './changelog.js';
|
|
6
|
-
import { gzipDeterministic } from './gzip.js';
|
|
6
|
+
import { gzipDeterministic, POLICY_MAX_COMPRESSION } from './gzip.js';
|
|
7
7
|
import { renderMimePackage } from './mime.js';
|
|
8
8
|
import { SHARE } from './share-dirs.js';
|
|
9
9
|
import { basename, extname, posix } from 'node:path';
|
|
@@ -174,12 +174,19 @@ export async function planOverlay(settings, format, inputs) {
|
|
|
174
174
|
// gzip performed on the packing host would put a second compressor's output in
|
|
175
175
|
// an artifact whose every other byte came from the first. `gzipDeterministic`
|
|
176
176
|
// zeroes the header stamp for the usual reason (utils/ship/gzip.ts).
|
|
177
|
+
//
|
|
178
|
+
// It is also the one gzip member in the artifact whose bytes cannot vary with
|
|
179
|
+
// the packing host, for the same reason: the two hosts' zlibs disagree (that
|
|
180
|
+
// file's header measurement), and this member is compressed once, here.
|
|
177
181
|
if (format.changelogDest !== undefined) {
|
|
178
182
|
const changelog = renderDebianChangelog(settings, inputs.changelogText, inputs.mtime);
|
|
179
183
|
files.push({
|
|
180
184
|
path: format.changelogDest(settings.binaryName),
|
|
181
185
|
mode: 0o644,
|
|
182
|
-
source: {
|
|
186
|
+
source: {
|
|
187
|
+
kind: 'bytes',
|
|
188
|
+
data: await gzipDeterministic(new TextEncoder().encode(changelog), POLICY_MAX_COMPRESSION),
|
|
189
|
+
},
|
|
183
190
|
});
|
|
184
191
|
}
|
|
185
192
|
return files;
|
|
@@ -233,19 +240,27 @@ function renderDebianCopyright(settings, licenseText) {
|
|
|
233
240
|
* Icons land in the hicolor theme, named after the app id — that name is what
|
|
234
241
|
* the desktop entry's `Icon=` and the MetaInfo `<id>` both point at, so a file
|
|
235
242
|
* keeping its source basename installs an icon nothing ever looks up.
|
|
243
|
+
*
|
|
244
|
+
* A SYMBOLIC icon keeps the `-symbolic` half of that name, and for the same
|
|
245
|
+
* reason rather than as an exception: the name GTK resolves a symbolic icon by
|
|
246
|
+
* is `<app id>-symbolic`, so renaming the file to the bare id installs an icon
|
|
247
|
+
* nothing ever looks up — one sentence, applied to both lookups.
|
|
236
248
|
*/
|
|
237
249
|
function planIcons(settings) {
|
|
238
250
|
const out = [];
|
|
239
251
|
const seen = new Map();
|
|
240
252
|
for (const icon of settings.iconFiles) {
|
|
241
253
|
const ext = extname(icon);
|
|
242
|
-
const dir =
|
|
243
|
-
const
|
|
254
|
+
const dir = iconThemeDir(icon);
|
|
255
|
+
const name = isSymbolicIcon(icon) ? `${settings.appId}-symbolic` : settings.appId;
|
|
256
|
+
const path = `${SHARE.icons}/${dir}/apps/${name}${ext}`;
|
|
244
257
|
const previous = seen.get(path);
|
|
245
258
|
if (previous !== undefined) {
|
|
246
259
|
throw new Error(`gjsify ship: ${icon} and ${previous} both install as ${path}. ` +
|
|
247
|
-
'
|
|
248
|
-
'
|
|
260
|
+
'An icon is keyed on its context and its size: `symbolic` is read from a `symbolic/` ' +
|
|
261
|
+
'path component or a `-symbolic` filename, the size from the path (`.../128x128/...`) ' +
|
|
262
|
+
'or the filename (`icon-128.png`). Give them distinguishable sizes, or point ' +
|
|
263
|
+
'`gjsify.ship.icon` at a single file.');
|
|
249
264
|
}
|
|
250
265
|
seen.set(path, icon);
|
|
251
266
|
out.push({ path, mode: 0o644, source: { kind: 'file', path: icon } });
|
|
@@ -253,11 +268,47 @@ function planIcons(settings) {
|
|
|
253
268
|
return out;
|
|
254
269
|
}
|
|
255
270
|
/**
|
|
256
|
-
*
|
|
257
|
-
*
|
|
258
|
-
*
|
|
271
|
+
* Whether an icon belongs in the theme's SYMBOLIC context rather than at a size.
|
|
272
|
+
*
|
|
273
|
+
* `symbolic` is a directory of its own in a hicolor theme and NOT a size value.
|
|
274
|
+
* Measured in `refs/adwaita-icon-theme/index.theme`, which lists `symbolic/apps`
|
|
275
|
+
* in `Directories=` beside `scalable/apps` and `16x16/apps` and gives it its own
|
|
276
|
+
* section — `Context=Applications`, `Size=16`, `MinSize=8`, `MaxSize=512`,
|
|
277
|
+
* `Type=Scalable` — against the scalable row's `Size=128`. The freedesktop icon
|
|
278
|
+
* theme specification has no notion of `symbolic` at all: a theme expresses it by
|
|
279
|
+
* giving the directory a section, which is exactly why reading the EXTENSION
|
|
280
|
+
* cannot see it, and why this question has to be asked before the size one.
|
|
281
|
+
*
|
|
282
|
+
* TWO SIGNALS, the same pair `iconThemeDir` already reads for a size: the
|
|
283
|
+
* directory an author put the file in, and the name they gave it. GTK resolves a
|
|
284
|
+
* symbolic icon by the `-symbolic` name suffix, so an author who wrote the name
|
|
285
|
+
* has said as much as one who wrote the path.
|
|
286
|
+
*
|
|
287
|
+
* SVG ONLY, because the symbolic directory is declared `Type=Scalable`: the
|
|
288
|
+
* raster form GTK's own `gtk-encode-symbolic-svg` produces
|
|
289
|
+
* (`<name>-symbolic.symbolic.png`) is installed at a SIZE instead. So a PNG keeps
|
|
290
|
+
* answering the size question, and one that cannot answer it stays refused rather
|
|
291
|
+
* than quietly becoming a scalable icon that does not scale.
|
|
292
|
+
*/
|
|
293
|
+
export function isSymbolicIcon(iconPath) {
|
|
294
|
+
if (extname(iconPath).toLowerCase() !== '.svg')
|
|
295
|
+
return false;
|
|
296
|
+
if (/(?:^|[\\/])symbolic[\\/]/.test(iconPath))
|
|
297
|
+
return true;
|
|
298
|
+
return basename(iconPath, extname(iconPath)).endsWith('-symbolic');
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* The hicolor subdirectory for an icon: the `symbolic` CONTEXT, else `scalable`
|
|
302
|
+
* for an SVG, else the pixel size read from a `<n>x<n>` path component or a
|
|
303
|
+
* trailing number in the filename.
|
|
304
|
+
*
|
|
305
|
+
* Named for the theme DIRECTORY rather than a size from the moment the first of
|
|
306
|
+
* those answers stopped being one: `iconSizeDir` returning `symbolic` would be a
|
|
307
|
+
* name every caller has to read past.
|
|
259
308
|
*/
|
|
260
|
-
export function
|
|
309
|
+
export function iconThemeDir(iconPath) {
|
|
310
|
+
if (isSymbolicIcon(iconPath))
|
|
311
|
+
return 'symbolic';
|
|
261
312
|
if (extname(iconPath).toLowerCase() === '.svg')
|
|
262
313
|
return 'scalable';
|
|
263
314
|
const square = /(?:^|[\\/])(\d{1,4})x\1(?:[\\/]|$)/.exec(iconPath);
|
|
@@ -1,3 +1,18 @@
|
|
|
1
|
+
export interface TokenizeOptions {
|
|
2
|
+
/**
|
|
3
|
+
* Accept an unquoted `*`/`?` as an ordinary token character.
|
|
4
|
+
*
|
|
5
|
+
* Off by default, and the default is about EXECUTION: a caller that RUNS
|
|
6
|
+
* the tokens must not pass `*.tsbuildinfo` through unexpanded, because the
|
|
7
|
+
* shell it replaces would have expanded it first. A caller that only READS
|
|
8
|
+
* the targets — `utils/package-inputs.ts`, asking which paths a package
|
|
9
|
+
* declares it produces — wants the pattern itself, and `gjsify clear`
|
|
10
|
+
* expands the same two characters in its own last segment anyway
|
|
11
|
+
* (`utils/clear-targets.ts`). Nothing else moves: every operator,
|
|
12
|
+
* substitution, brace and tilde still returns `null`.
|
|
13
|
+
*/
|
|
14
|
+
allowGlobs?: boolean;
|
|
15
|
+
}
|
|
1
16
|
/**
|
|
2
17
|
* Tokenize `cmd`, or return `null` if the string contains anything the shell
|
|
3
18
|
* would treat specially — operators (`&& | ; < > &`), substitutions (`$(...)` /
|
|
@@ -7,10 +22,10 @@
|
|
|
7
22
|
* single literal token, exactly as the shell would hand it to `gjsify` (which
|
|
8
23
|
* does its own glob expansion).
|
|
9
24
|
*/
|
|
10
|
-
export declare function tokenizeSimpleCommand(cmd: string): string[] | null;
|
|
25
|
+
export declare function tokenizeSimpleCommand(cmd: string, options?: TokenizeOptions): string[] | null;
|
|
11
26
|
/**
|
|
12
27
|
* The argv of a script that is a single `gjsify <subcommand> …` command — i.e.
|
|
13
28
|
* the tokens after `gjsify` — or `null` when it is anything else. `null` is the
|
|
14
29
|
* signal to hand the literal to a shell.
|
|
15
30
|
*/
|
|
16
|
-
export declare function gjsifyCommandArgv(literal: string): string[] | null;
|
|
31
|
+
export declare function gjsifyCommandArgv(literal: string, options?: TokenizeOptions): string[] | null;
|
|
@@ -6,6 +6,10 @@
|
|
|
6
6
|
// deliberately conservative in ONE direction — a `null` costs the caller its
|
|
7
7
|
// fast path, a wrong token list would run a different command than the script
|
|
8
8
|
// says.
|
|
9
|
+
/** Characters that make a string something only a shell may execute. */
|
|
10
|
+
const SHELL_SPECIAL = '|&;<>`$()\\\n\r*?{}[]~#!';
|
|
11
|
+
/** The same set minus `*` and `?` — see {@link TokenizeOptions.allowGlobs}. */
|
|
12
|
+
const SHELL_SPECIAL_ALLOWING_GLOBS = SHELL_SPECIAL.replace('*', '').replace('?', '');
|
|
9
13
|
/**
|
|
10
14
|
* Tokenize `cmd`, or return `null` if the string contains anything the shell
|
|
11
15
|
* would treat specially — operators (`&& | ; < > &`), substitutions (`$(...)` /
|
|
@@ -15,7 +19,8 @@
|
|
|
15
19
|
* single literal token, exactly as the shell would hand it to `gjsify` (which
|
|
16
20
|
* does its own glob expansion).
|
|
17
21
|
*/
|
|
18
|
-
export function tokenizeSimpleCommand(cmd) {
|
|
22
|
+
export function tokenizeSimpleCommand(cmd, options = {}) {
|
|
23
|
+
const special = options.allowGlobs === true ? SHELL_SPECIAL_ALLOWING_GLOBS : SHELL_SPECIAL;
|
|
19
24
|
const tokens = [];
|
|
20
25
|
let cur = '';
|
|
21
26
|
let has = false;
|
|
@@ -53,7 +58,7 @@ export function tokenizeSimpleCommand(cmd) {
|
|
|
53
58
|
}
|
|
54
59
|
continue;
|
|
55
60
|
}
|
|
56
|
-
if (
|
|
61
|
+
if (special.includes(c))
|
|
57
62
|
return null;
|
|
58
63
|
cur += c;
|
|
59
64
|
has = true;
|
|
@@ -69,8 +74,8 @@ export function tokenizeSimpleCommand(cmd) {
|
|
|
69
74
|
* the tokens after `gjsify` — or `null` when it is anything else. `null` is the
|
|
70
75
|
* signal to hand the literal to a shell.
|
|
71
76
|
*/
|
|
72
|
-
export function gjsifyCommandArgv(literal) {
|
|
73
|
-
const tokens = tokenizeSimpleCommand(literal);
|
|
77
|
+
export function gjsifyCommandArgv(literal, options = {}) {
|
|
78
|
+
const tokens = tokenizeSimpleCommand(literal, options);
|
|
74
79
|
if (!tokens || tokens.length < 2 || tokens[0] !== 'gjsify')
|
|
75
80
|
return null;
|
|
76
81
|
return tokens.slice(1);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gjsify/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.50.0",
|
|
4
4
|
"description": "CLI for Gjsify",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -142,21 +142,21 @@
|
|
|
142
142
|
"cli"
|
|
143
143
|
],
|
|
144
144
|
"dependencies": {
|
|
145
|
-
"@gjsify/buffer": "^0.
|
|
146
|
-
"@gjsify/create-app": "^0.
|
|
147
|
-
"@gjsify/node-globals": "^0.
|
|
148
|
-
"@gjsify/node-polyfills": "^0.
|
|
149
|
-
"@gjsify/npm-registry": "^0.
|
|
150
|
-
"@gjsify/resolve-npm": "^0.
|
|
151
|
-
"@gjsify/rolldown-plugin-gjsify": "^0.
|
|
152
|
-
"@gjsify/vite-plugin-blueprint": "^0.
|
|
153
|
-
"@gjsify/rolldown-plugin-pnp": "^0.
|
|
154
|
-
"@gjsify/semver": "^0.
|
|
155
|
-
"@gjsify/tar": "^0.
|
|
156
|
-
"@gjsify/tsc": "^0.
|
|
157
|
-
"@gjsify/utils": "^0.
|
|
158
|
-
"@gjsify/web-polyfills": "^0.
|
|
159
|
-
"@gjsify/workspace": "^0.
|
|
145
|
+
"@gjsify/buffer": "^0.50.0",
|
|
146
|
+
"@gjsify/create-app": "^0.50.0",
|
|
147
|
+
"@gjsify/node-globals": "^0.50.0",
|
|
148
|
+
"@gjsify/node-polyfills": "^0.50.0",
|
|
149
|
+
"@gjsify/npm-registry": "^0.50.0",
|
|
150
|
+
"@gjsify/resolve-npm": "^0.50.0",
|
|
151
|
+
"@gjsify/rolldown-plugin-gjsify": "^0.50.0",
|
|
152
|
+
"@gjsify/vite-plugin-blueprint": "^0.50.0",
|
|
153
|
+
"@gjsify/rolldown-plugin-pnp": "^0.50.0",
|
|
154
|
+
"@gjsify/semver": "^0.50.0",
|
|
155
|
+
"@gjsify/tar": "^0.50.0",
|
|
156
|
+
"@gjsify/tsc": "^0.50.0",
|
|
157
|
+
"@gjsify/utils": "^0.50.0",
|
|
158
|
+
"@gjsify/web-polyfills": "^0.50.0",
|
|
159
|
+
"@gjsify/workspace": "^0.50.0",
|
|
160
160
|
"acorn": "^8.17.0",
|
|
161
161
|
"cosmiconfig": "^9.0.2",
|
|
162
162
|
"get-tsconfig": "^4.14.0",
|
|
@@ -165,13 +165,13 @@
|
|
|
165
165
|
"yargs": "^18.0.0"
|
|
166
166
|
},
|
|
167
167
|
"devDependencies": {
|
|
168
|
-
"@gjsify/unit": "^0.
|
|
168
|
+
"@gjsify/unit": "^0.50.0",
|
|
169
169
|
"@types/yargs": "^17.0.35",
|
|
170
170
|
"typescript": "^6.0.3"
|
|
171
171
|
},
|
|
172
172
|
"peerDependencies": {
|
|
173
|
-
"@gjsify/oxfmt-native": "^0.
|
|
174
|
-
"@gjsify/rolldown-native": "^0.
|
|
173
|
+
"@gjsify/oxfmt-native": "^0.50.0",
|
|
174
|
+
"@gjsify/rolldown-native": "^0.50.0"
|
|
175
175
|
},
|
|
176
176
|
"peerDependenciesMeta": {
|
|
177
177
|
"@gjsify/oxfmt-native": {
|