@ts-for-gir/cli 4.0.0-rc.8 → 4.0.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/README.md +43 -3
- package/bin/ts-for-gir +458 -130
- package/bin/ts-for-gir-gjs +1213 -0
- package/package.json +194 -83
- package/src/commands/create.ts +84 -12
- package/src/commands/index.ts +1 -0
- package/src/commands/self-update.ts +142 -0
- package/src/config/config-loader.ts +6 -2
- package/src/config/defaults.ts +14 -0
- package/src/config/options.ts +2 -2
- package/src/start.ts +20 -6
- package/src/types/command-args.ts +8 -1
- package/dist-templates/types-locally/.ts-for-girrc.js +0 -6
- package/dist-templates/types-locally/README.md +0 -15
- package/dist-templates/types-locally/esbuild.ts +0 -10
- package/dist-templates/types-locally/main.ts +0 -21
- package/dist-templates/types-locally/package.json +0 -18
- package/dist-templates/types-locally/tsconfig.json +0 -17
- package/dist-templates/types-npm/README.md +0 -14
- package/dist-templates/types-npm/esbuild.ts +0 -10
- package/dist-templates/types-npm/main.ts +0 -19
- package/dist-templates/types-npm/package.json +0 -23
- package/dist-templates/types-npm/tsconfig.json +0 -15
- package/dist-templates/types-workspace/.ts-for-girrc.js +0 -12
- package/dist-templates/types-workspace/README.md +0 -26
- package/dist-templates/types-workspace/package.json +0 -22
- package/dist-templates/types-workspace/packages/app/esbuild.ts +0 -10
- package/dist-templates/types-workspace/packages/app/main.ts +0 -19
- package/dist-templates/types-workspace/packages/app/package.json +0 -23
- package/dist-templates/types-workspace/packages/app/tsconfig.json +0 -15
- package/dist-templates/types-workspace/tsconfig.json +0 -11
package/package.json
CHANGED
|
@@ -1,84 +1,195 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
}
|
|
2
|
+
"name": "@ts-for-gir/cli",
|
|
3
|
+
"version": "4.0.0",
|
|
4
|
+
"description": "TypeScript type definition generator for GObject introspection GIR files",
|
|
5
|
+
"main": "src/index.ts",
|
|
6
|
+
"module": "src/index.ts",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"bin": {
|
|
9
|
+
"cli": "bin/ts-for-gir",
|
|
10
|
+
"ts-for-gir": "bin/ts-for-gir",
|
|
11
|
+
"ts-for-gir-dev": "bin/ts-for-gir-dev",
|
|
12
|
+
"ts-for-gir-gjs": "bin/ts-for-gir-gjs"
|
|
13
|
+
},
|
|
14
|
+
"gjsify": {
|
|
15
|
+
"bin": {
|
|
16
|
+
"ts-for-gir": "bin/ts-for-gir-gjs"
|
|
17
|
+
},
|
|
18
|
+
"shebang": true,
|
|
19
|
+
"bundler": {
|
|
20
|
+
"input": "src/start.ts",
|
|
21
|
+
"output": {
|
|
22
|
+
"file": "bin/ts-for-gir-gjs"
|
|
23
|
+
},
|
|
24
|
+
"transform": {
|
|
25
|
+
"define": {
|
|
26
|
+
"__GJS_BUNDLE__": "true"
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"defineFromPackageJson": {
|
|
31
|
+
"__TS_FOR_GIR_VERSION__": {
|
|
32
|
+
"field": "version"
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"excludeGlobals": [
|
|
36
|
+
"XMLHttpRequest",
|
|
37
|
+
"XMLHttpRequestUpload"
|
|
38
|
+
],
|
|
39
|
+
"flatpak": {
|
|
40
|
+
"appId": "io.github.gjsify.ts_for_gir",
|
|
41
|
+
"kind": "cli",
|
|
42
|
+
"name": "ts-for-gir",
|
|
43
|
+
"runtime": "gnome",
|
|
44
|
+
"runtimeVersion": "50",
|
|
45
|
+
"command": "ts-for-gir",
|
|
46
|
+
"finishArgs": [
|
|
47
|
+
"--share=network",
|
|
48
|
+
"--filesystem=host"
|
|
49
|
+
],
|
|
50
|
+
"developer": {
|
|
51
|
+
"id": "io.github.gjsify",
|
|
52
|
+
"name": "gjsify contributors",
|
|
53
|
+
"email": "pascal@artandcode.studio"
|
|
54
|
+
},
|
|
55
|
+
"summary": "TypeScript type definitions for GObject Introspection (GJS)",
|
|
56
|
+
"description": [
|
|
57
|
+
{
|
|
58
|
+
"p": "ts-for-gir reads GObject Introspection (GIR) XML files and emits strongly-typed TypeScript definitions for use in GJS (GNOME JavaScript) projects. Type-check your GTK / Adwaita / GLib / Gio / GStreamer / WebKit / etc. code, get full IDE completion, and catch missing properties / wrong-arity signal handlers at build time instead of runtime."
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"p": "This Flatpak ships ts-for-gir as a self-contained CLI runnable on any modern Linux distro — no Node.js installation required. It reads from the system's installed GIR catalog (read-only mounts of /usr/share/gir-1.0 and /usr/share/gobject-introspection-1.0) and writes generated types under your project directory."
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"ul": [
|
|
65
|
+
{
|
|
66
|
+
"item": "`ts-for-gir generate Gtk-4.0` — generate types for one or more GI namespaces"
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"item": "`ts-for-gir generate --reporter` — write a JSON report alongside types for downstream analysis"
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"item": "`ts-for-gir analyze report.json` — inspect type-resolution issues by severity / category / namespace"
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"item": "`ts-for-gir create my-app` — scaffold a new GJS app from a template"
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"item": "`ts-for-gir list` — list all GIR namespaces available on this system"
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"item": "`ts-for-gir self-update` — refresh the global install in place"
|
|
82
|
+
}
|
|
83
|
+
]
|
|
84
|
+
}
|
|
85
|
+
],
|
|
86
|
+
"license": {
|
|
87
|
+
"metadata": "CC0-1.0",
|
|
88
|
+
"project": "Apache-2.0"
|
|
89
|
+
},
|
|
90
|
+
"categories": [
|
|
91
|
+
"Development"
|
|
92
|
+
],
|
|
93
|
+
"homepageUrl": "https://gjsify.github.io/gjsify/projects/ts-for-gir/",
|
|
94
|
+
"vcsBrowserUrl": "https://github.com/gjsify/ts-for-gir",
|
|
95
|
+
"issueTrackerUrl": "https://github.com/gjsify/ts-for-gir/issues",
|
|
96
|
+
"modules": [
|
|
97
|
+
{
|
|
98
|
+
"name": "ts-for-gir-cli",
|
|
99
|
+
"buildsystem": "simple",
|
|
100
|
+
"build-commands": [
|
|
101
|
+
"install -Dm755 package/bin/ts-for-gir-gjs /app/share/ts-for-gir/ts-for-gir.gjs.mjs",
|
|
102
|
+
"install -Dm755 launcher.sh /app/bin/ts-for-gir"
|
|
103
|
+
],
|
|
104
|
+
"sources": [
|
|
105
|
+
{
|
|
106
|
+
"type": "archive",
|
|
107
|
+
"url": "https://registry.npmjs.org/@ts-for-gir/cli/-/cli-4.0.0-rc.17.tgz",
|
|
108
|
+
"sha256": "6ca2c7c73bbc37259ebec621f1b24f8e9ca896426783114e80faa59cb4983afe",
|
|
109
|
+
"strip-components": 0,
|
|
110
|
+
"dest-filename": "tarball.tgz"
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
"type": "file",
|
|
114
|
+
"path": "launcher.sh"
|
|
115
|
+
}
|
|
116
|
+
]
|
|
117
|
+
}
|
|
118
|
+
]
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
"engines": {
|
|
122
|
+
"node": ">=18"
|
|
123
|
+
},
|
|
124
|
+
"scripts": {
|
|
125
|
+
"start": "node bin/ts-for-gir-dev",
|
|
126
|
+
"start:prod": "node bin/ts-for-gir",
|
|
127
|
+
"build": "node --experimental-specifier-resolution=node --experimental-strip-types --experimental-transform-types --no-warnings esbuild.ts && chmod +x bin/ts-for-gir-dev && chmod +x bin/ts-for-gir",
|
|
128
|
+
"build:gjs": "gjsify build",
|
|
129
|
+
"build:templates": "node scripts/process-templates.mjs",
|
|
130
|
+
"prepack": "node scripts/process-templates.mjs",
|
|
131
|
+
"check:types": "tsc --noEmit",
|
|
132
|
+
"check": "gjsify run check:types"
|
|
133
|
+
},
|
|
134
|
+
"repository": {
|
|
135
|
+
"type": "git",
|
|
136
|
+
"url": "git+https://github.com/gjsify/ts-for-gir.git"
|
|
137
|
+
},
|
|
138
|
+
"author": "Pascal Garber <pascal@mailfreun.de>",
|
|
139
|
+
"files": [
|
|
140
|
+
"src",
|
|
141
|
+
"bin",
|
|
142
|
+
"dist-templates"
|
|
143
|
+
],
|
|
144
|
+
"license": "Apache-2.0",
|
|
145
|
+
"bugs": {
|
|
146
|
+
"url": "https://github.com/gjsify/ts-for-gir/issues"
|
|
147
|
+
},
|
|
148
|
+
"homepage": "https://github.com/gjsify/ts-for-gir#readme",
|
|
149
|
+
"keywords": [
|
|
150
|
+
"gjs",
|
|
151
|
+
"typescript",
|
|
152
|
+
"generate",
|
|
153
|
+
"gir",
|
|
154
|
+
"gobject-introspection",
|
|
155
|
+
"gnome",
|
|
156
|
+
"gtk",
|
|
157
|
+
"glib",
|
|
158
|
+
"gobject",
|
|
159
|
+
"dts",
|
|
160
|
+
"type definitions",
|
|
161
|
+
"cli"
|
|
162
|
+
],
|
|
163
|
+
"exports": {
|
|
164
|
+
".": "./src/index.ts"
|
|
165
|
+
},
|
|
166
|
+
"devDependencies": {
|
|
167
|
+
"@gi.ts/parser": "^4.0.0",
|
|
168
|
+
"@gjsify/cli": "^0.4.19",
|
|
169
|
+
"@ts-for-gir/generator-base": "^4.0.0",
|
|
170
|
+
"@ts-for-gir/generator-html-doc": "^4.0.0",
|
|
171
|
+
"@ts-for-gir/generator-json": "^4.0.0",
|
|
172
|
+
"@ts-for-gir/generator-typescript": "^4.0.0",
|
|
173
|
+
"@ts-for-gir/lib": "^4.0.0",
|
|
174
|
+
"@ts-for-gir/reporter": "^4.0.0",
|
|
175
|
+
"@ts-for-gir/tsconfig": "^4.0.0",
|
|
176
|
+
"@types/ejs": "^3.1.5",
|
|
177
|
+
"@types/inquirer": "^9.0.9",
|
|
178
|
+
"@types/node": "^25.6.2",
|
|
179
|
+
"@types/yargs": "^17.0.35",
|
|
180
|
+
"esbuild": "^0.28.0",
|
|
181
|
+
"source-map-support": "^0.5.21",
|
|
182
|
+
"typescript": "^6.0.3"
|
|
183
|
+
},
|
|
184
|
+
"dependencies": {
|
|
185
|
+
"@inquirer/prompts": "^8.4.2",
|
|
186
|
+
"@ts-for-gir/templates": "^4.0.0",
|
|
187
|
+
"colorette": "^2.0.20",
|
|
188
|
+
"cosmiconfig": "^9.0.1",
|
|
189
|
+
"ejs": "^5.0.2",
|
|
190
|
+
"glob": "^13.0.6",
|
|
191
|
+
"inquirer": "^13.4.2",
|
|
192
|
+
"typedoc": "^0.28.19",
|
|
193
|
+
"yargs": "^18.0.0"
|
|
194
|
+
}
|
|
195
|
+
}
|
package/src/commands/create.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { spawnSync } from "node:child_process";
|
|
6
|
-
import { cpSync, existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
6
|
+
import { cpSync, existsSync, mkdirSync, readdirSync, readFileSync, realpathSync, writeFileSync } from "node:fs";
|
|
7
7
|
import { dirname, join, resolve } from "node:path";
|
|
8
8
|
import { fileURLToPath } from "node:url";
|
|
9
9
|
|
|
@@ -19,7 +19,8 @@ const command = "create [name]";
|
|
|
19
19
|
const description = "Scaffold a new GJS TypeScript project from a template";
|
|
20
20
|
|
|
21
21
|
const examples: ReadonlyArray<[string, string?]> = [
|
|
22
|
-
[`${APP_NAME} create my-app --template types-
|
|
22
|
+
[`${APP_NAME} create my-app --template types-gjsify`, "Scaffold a Node-free GJS app via gjsify (recommended)"],
|
|
23
|
+
[`${APP_NAME} create my-app --template types-npm`, "Scaffold using the @girs/* NPM types + node/esbuild"],
|
|
23
24
|
[`${APP_NAME} create my-app --template types-locally`, "Scaffold and generate types into ./@types/ locally"],
|
|
24
25
|
[
|
|
25
26
|
`${APP_NAME} create my-app --template types-workspace`,
|
|
@@ -30,15 +31,20 @@ const examples: ReadonlyArray<[string, string?]> = [
|
|
|
30
31
|
|
|
31
32
|
const TEMPLATE_CHOICES: ReadonlyArray<{ value: CreateTemplateId; name: string; description: string }> = [
|
|
32
33
|
{
|
|
33
|
-
value: "types-
|
|
34
|
-
name: "types-
|
|
35
|
-
description: "
|
|
34
|
+
value: "types-gjsify",
|
|
35
|
+
name: "types-gjsify",
|
|
36
|
+
description: "Node-free: @girs/* from NPM, all dev scripts (install/build/run/format) routed through gjsify",
|
|
36
37
|
},
|
|
37
38
|
{
|
|
38
39
|
value: "types-npm",
|
|
39
40
|
name: "types-npm",
|
|
40
41
|
description: "Use pre-generated types from the @girs/* NPM packages",
|
|
41
42
|
},
|
|
43
|
+
{
|
|
44
|
+
value: "types-locally",
|
|
45
|
+
name: "types-locally",
|
|
46
|
+
description: "Generate GIR types directly into ./@types/ (no package format, no @girs/* deps)",
|
|
47
|
+
},
|
|
42
48
|
{
|
|
43
49
|
value: "types-workspace",
|
|
44
50
|
name: "types-workspace",
|
|
@@ -55,18 +61,44 @@ const builder = createBuilder<CreateCommandArgs>(createOptions, examples);
|
|
|
55
61
|
function findTemplatesRoot(): string {
|
|
56
62
|
const __filename = fileURLToPath(import.meta.url);
|
|
57
63
|
const __dirname = dirname(__filename);
|
|
64
|
+
// Resolve symlinks too. When the CLI is installed via `npm i -g`,
|
|
65
|
+
// `gjsify install -g`, or any tool that lands a symlink in the user's PATH
|
|
66
|
+
// (Yarn Berry's bin links, asdf shims, ...), `import.meta.url` resolves to
|
|
67
|
+
// the symlink path — `<dir>/../dist-templates` would then look for the
|
|
68
|
+
// templates next to the symlink (e.g. `~/.local/bin/../dist-templates`)
|
|
69
|
+
// instead of next to the real package. Resolving via realpath first lets
|
|
70
|
+
// the same `<dir>/../dist-templates` candidate hit the actual install dir.
|
|
71
|
+
let realDirname = __dirname;
|
|
72
|
+
try {
|
|
73
|
+
realDirname = dirname(realpathSync(__filename));
|
|
74
|
+
} catch {
|
|
75
|
+
// `realpathSync` can throw on bundled paths that don't exist on disk
|
|
76
|
+
// (e.g. virtual entries in a single-file binary). Fall through to the
|
|
77
|
+
// direct __dirname — the candidate list below is a superset and will
|
|
78
|
+
// still find templates when they live alongside the bundle.
|
|
79
|
+
}
|
|
58
80
|
const candidates = [
|
|
59
|
-
//
|
|
81
|
+
// Symlink-resolved binary (`npm i -g` / `gjsify install -g`): the
|
|
82
|
+
// realpath-aware candidate is required when the CLI is launched via a
|
|
83
|
+
// `~/.local/bin/<name>` symlink that points at the real package's
|
|
84
|
+
// `bin/<name>`. Try it first so the success path is symmetric across
|
|
85
|
+
// install modes.
|
|
86
|
+
resolve(realDirname, "..", "dist-templates"),
|
|
87
|
+
// Bundled production binary invoked at its real path (no symlink),
|
|
88
|
+
// or a tarball extracted into a flat `bin/` + `dist-templates/` layout.
|
|
60
89
|
resolve(__dirname, "..", "dist-templates"),
|
|
61
90
|
// Source layout (src/commands/create.ts): ../../dist-templates then ../../templates
|
|
62
91
|
resolve(__dirname, "..", "..", "dist-templates"),
|
|
63
92
|
resolve(__dirname, "..", "..", "templates"),
|
|
64
93
|
];
|
|
94
|
+
const seen = new Set<string>();
|
|
65
95
|
for (const path of candidates) {
|
|
96
|
+
if (seen.has(path)) continue;
|
|
97
|
+
seen.add(path);
|
|
66
98
|
if (existsSync(path)) return path;
|
|
67
99
|
}
|
|
68
100
|
throw new Error(
|
|
69
|
-
`Could not locate templates directory. Looked in:\n ${
|
|
101
|
+
`Could not locate templates directory. Looked in:\n ${[...seen].join("\n ")}\n` +
|
|
70
102
|
"If you are running from source, make sure packages/cli/templates/ exists. " +
|
|
71
103
|
"If you are running the published CLI, make sure dist-templates/ was packed.",
|
|
72
104
|
);
|
|
@@ -119,11 +151,36 @@ function walkAndSubstitute(rootDir: string, projectName: string): void {
|
|
|
119
151
|
}
|
|
120
152
|
}
|
|
121
153
|
|
|
154
|
+
declare const __GJS_BUNDLE__: boolean | undefined;
|
|
155
|
+
|
|
122
156
|
const handler = async (args: ConfigFlags) => {
|
|
123
157
|
const opts = args as unknown as CreateCommandArgs;
|
|
124
158
|
const log = new Logger(opts.verbose ?? false, "CreateCommand");
|
|
125
159
|
|
|
126
|
-
|
|
160
|
+
let templatesRoot: string;
|
|
161
|
+
try {
|
|
162
|
+
templatesRoot = findTemplatesRoot();
|
|
163
|
+
} catch (err) {
|
|
164
|
+
// `dist-templates/` not next to the running file. Two known scenarios:
|
|
165
|
+
// 1. `install.js` (or any flow) deployed only the single-file GJS
|
|
166
|
+
// binary without the package tree. We can't scaffold without
|
|
167
|
+
// templates — point the user at the working install path.
|
|
168
|
+
// 2. Source-mode mis-checkout (no `packages/cli/templates/`). Surface
|
|
169
|
+
// the original error so the developer can fix their layout.
|
|
170
|
+
// The `__GJS_BUNDLE__` define lets us discriminate at build time.
|
|
171
|
+
if (typeof __GJS_BUNDLE__ !== "undefined") {
|
|
172
|
+
process.stderr.write(
|
|
173
|
+
"The 'create' command needs templates that aren't shipped alongside this binary.\n" +
|
|
174
|
+
"Install the full package instead so `dist-templates/` lives next to the bin:\n" +
|
|
175
|
+
" gjsify install -g @ts-for-gir/cli\n" +
|
|
176
|
+
" npm install -g @ts-for-gir/cli\n" +
|
|
177
|
+
" npx @ts-for-gir/cli create ... # one-shot, no install\n",
|
|
178
|
+
);
|
|
179
|
+
process.exitCode = 1;
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
throw err;
|
|
183
|
+
}
|
|
127
184
|
const available = listTemplates(templatesRoot);
|
|
128
185
|
if (available.length === 0) {
|
|
129
186
|
throw new Error(`No templates found in ${templatesRoot}`);
|
|
@@ -175,19 +232,30 @@ const handler = async (args: ConfigFlags) => {
|
|
|
175
232
|
log.success(`Scaffolded ${template} into ${targetDir}`);
|
|
176
233
|
|
|
177
234
|
if (opts.install) {
|
|
178
|
-
|
|
179
|
-
|
|
235
|
+
// types-gjsify is Node-free at runtime — bootstrap deps via `gjsify install`
|
|
236
|
+
// so the user's first impression matches the rest of the template's scripts.
|
|
237
|
+
// Other templates remain on npm (matches the prior behavior + their README).
|
|
238
|
+
const installer = template === "types-gjsify" ? "gjsify" : "npm";
|
|
239
|
+
const installerArgs = template === "types-gjsify" ? ["install"] : ["install", "--no-audit", "--no-fund"];
|
|
240
|
+
log.info(`Running ${installer} install...`);
|
|
241
|
+
const result = spawnSync(installer, installerArgs, {
|
|
180
242
|
cwd: targetDir,
|
|
181
243
|
stdio: "inherit",
|
|
182
244
|
});
|
|
183
245
|
if (result.status !== 0) {
|
|
184
|
-
log.warn(
|
|
246
|
+
log.warn(`${installer} install failed; you can re-run it manually in the project directory.`);
|
|
185
247
|
}
|
|
186
248
|
}
|
|
187
249
|
|
|
188
250
|
log.info("\nNext steps:");
|
|
189
251
|
log.white(` cd ${projectName}`);
|
|
190
|
-
if (!opts.install)
|
|
252
|
+
if (!opts.install) {
|
|
253
|
+
if (template === "types-gjsify") {
|
|
254
|
+
log.white(" gjsify install");
|
|
255
|
+
} else {
|
|
256
|
+
log.white(" npm install");
|
|
257
|
+
}
|
|
258
|
+
}
|
|
191
259
|
switch (template) {
|
|
192
260
|
case "types-locally":
|
|
193
261
|
log.white(" npm run generate");
|
|
@@ -202,6 +270,10 @@ const handler = async (args: ConfigFlags) => {
|
|
|
202
270
|
log.white(" npm run build:types && npm install");
|
|
203
271
|
log.white(" npm run build:app && npm start");
|
|
204
272
|
break;
|
|
273
|
+
case "types-gjsify":
|
|
274
|
+
log.white(" gjsify run check");
|
|
275
|
+
log.white(" gjsify run build && gjsify run start");
|
|
276
|
+
break;
|
|
205
277
|
}
|
|
206
278
|
};
|
|
207
279
|
|
package/src/commands/index.ts
CHANGED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Everything you need for the `ts-for-gir self-update` command is located here
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { chmodSync, existsSync, renameSync, writeFileSync } from "node:fs";
|
|
6
|
+
import { tmpdir } from "node:os";
|
|
7
|
+
import { join } from "node:path";
|
|
8
|
+
|
|
9
|
+
import { APP_NAME, APP_VERSION } from "@ts-for-gir/lib";
|
|
10
|
+
|
|
11
|
+
import type { SelfUpdateCommandArgs } from "../types/index.ts";
|
|
12
|
+
|
|
13
|
+
const REPO = "gjsify/ts-for-gir";
|
|
14
|
+
const GITHUB_API = "https://api.github.com";
|
|
15
|
+
const GJS_ASSET_NAME = "ts-for-gir-gjs";
|
|
16
|
+
|
|
17
|
+
function getCurrentBinaryPath(): string | null {
|
|
18
|
+
const p = process.argv[1] ?? null;
|
|
19
|
+
if (!p) return null;
|
|
20
|
+
// Refuse to update in dev mode (source file or node_modules path)
|
|
21
|
+
if (p.endsWith(".ts") || p.includes("node_modules")) return null;
|
|
22
|
+
return p;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async function fetchJson(url: string): Promise<unknown> {
|
|
26
|
+
const headers: Record<string, string> = {
|
|
27
|
+
Accept: "application/vnd.github.v3+json",
|
|
28
|
+
"User-Agent": `ts-for-gir/${APP_VERSION}`,
|
|
29
|
+
};
|
|
30
|
+
const token = process.env.GITHUB_TOKEN;
|
|
31
|
+
if (token) headers.Authorization = `token ${token}`;
|
|
32
|
+
|
|
33
|
+
const response = await fetch(url, { headers });
|
|
34
|
+
if (!response.ok) {
|
|
35
|
+
throw new Error(`HTTP ${response.status} from ${url}`);
|
|
36
|
+
}
|
|
37
|
+
return response.json();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async function downloadBinary(url: string, destPath: string): Promise<void> {
|
|
41
|
+
const response = await fetch(url, {
|
|
42
|
+
headers: { "User-Agent": `ts-for-gir/${APP_VERSION}` },
|
|
43
|
+
});
|
|
44
|
+
if (!response.ok) {
|
|
45
|
+
throw new Error(`HTTP ${response.status} downloading binary`);
|
|
46
|
+
}
|
|
47
|
+
const buffer = await response.arrayBuffer();
|
|
48
|
+
const tmpPath = join(tmpdir(), `ts-for-gir-update-${Date.now()}`);
|
|
49
|
+
writeFileSync(tmpPath, Buffer.from(buffer));
|
|
50
|
+
chmodSync(tmpPath, 0o755);
|
|
51
|
+
renameSync(tmpPath, destPath); // atomic on POSIX
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const command = "self-update";
|
|
55
|
+
const description = "Update ts-for-gir to the latest version from GitHub releases";
|
|
56
|
+
const examples: ReadonlyArray<[string, string?]> = [
|
|
57
|
+
[`${APP_NAME} self-update`, "Check for updates and install the latest version"],
|
|
58
|
+
[`${APP_NAME} self-update --check`, "Only check for a newer version, do not install"],
|
|
59
|
+
[`${APP_NAME} self-update --force`, "Force reinstall even if already on the latest version"],
|
|
60
|
+
];
|
|
61
|
+
|
|
62
|
+
const builder = (yargs: import("yargs").Argv) =>
|
|
63
|
+
yargs
|
|
64
|
+
.option("check", {
|
|
65
|
+
description: "Only check for a newer version, do not install",
|
|
66
|
+
type: "boolean",
|
|
67
|
+
default: false,
|
|
68
|
+
})
|
|
69
|
+
.option("force", {
|
|
70
|
+
description: "Force reinstall even if already on the latest version",
|
|
71
|
+
type: "boolean",
|
|
72
|
+
default: false,
|
|
73
|
+
})
|
|
74
|
+
.example(examples as [string, string?][]);
|
|
75
|
+
|
|
76
|
+
const handler = async (args: SelfUpdateCommandArgs): Promise<void> => {
|
|
77
|
+
console.log(`Checking for updates... (current: v${APP_VERSION})`);
|
|
78
|
+
|
|
79
|
+
let release: Record<string, unknown>;
|
|
80
|
+
try {
|
|
81
|
+
release = (await fetchJson(`${GITHUB_API}/repos/${REPO}/releases/latest`)) as Record<string, unknown>;
|
|
82
|
+
} catch (err) {
|
|
83
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
84
|
+
process.stderr.write(`Failed to fetch release information: ${msg}\n`);
|
|
85
|
+
process.exitCode = 1;
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const latestVersion = (release.tag_name as string).replace(/^v/, "");
|
|
90
|
+
|
|
91
|
+
if (latestVersion === APP_VERSION && !args.force) {
|
|
92
|
+
console.log(`Already up to date (v${APP_VERSION})`);
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (args.check) {
|
|
97
|
+
console.log(`New version available: v${latestVersion} (current: v${APP_VERSION})`);
|
|
98
|
+
console.log(`Run \`${APP_NAME} self-update\` to install it.`);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
console.log(`Updating to v${latestVersion}...`);
|
|
103
|
+
|
|
104
|
+
const assets = release.assets as Array<Record<string, string>>;
|
|
105
|
+
const asset = assets.find((a) => a.name === GJS_ASSET_NAME);
|
|
106
|
+
if (!asset) {
|
|
107
|
+
process.stderr.write(
|
|
108
|
+
`No GJS binary found in release ${release.tag_name}.\n` +
|
|
109
|
+
"self-update requires the GJS bundle to be installed via install.js.\n" +
|
|
110
|
+
"For npm installations use: npm update -g @ts-for-gir/cli\n",
|
|
111
|
+
);
|
|
112
|
+
process.exitCode = 1;
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const currentPath = getCurrentBinaryPath();
|
|
117
|
+
if (!currentPath || !existsSync(currentPath)) {
|
|
118
|
+
process.stderr.write(
|
|
119
|
+
"Cannot determine current binary path for update.\n" +
|
|
120
|
+
"self-update only works when running the installed GJS binary.\n",
|
|
121
|
+
);
|
|
122
|
+
process.exitCode = 1;
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
try {
|
|
127
|
+
await downloadBinary(asset.browser_download_url, currentPath);
|
|
128
|
+
console.log(`Successfully updated to v${latestVersion}`);
|
|
129
|
+
} catch (err) {
|
|
130
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
131
|
+
process.stderr.write(`Update failed: ${msg}\n`);
|
|
132
|
+
process.exitCode = 1;
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
export const selfUpdate = {
|
|
137
|
+
command,
|
|
138
|
+
description,
|
|
139
|
+
builder,
|
|
140
|
+
handler,
|
|
141
|
+
examples,
|
|
142
|
+
};
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { dirname, resolve } from "node:path";
|
|
6
|
+
import { pathToFileURL } from "node:url";
|
|
6
7
|
import type { ConfigFlags, OptionsGeneration, UserConfig, UserConfigLoadResult } from "@ts-for-gir/lib";
|
|
7
8
|
import { APP_NAME, isEqual } from "@ts-for-gir/lib";
|
|
8
9
|
import { type Options as ConfigSearchOptions, cosmiconfig } from "cosmiconfig";
|
|
@@ -18,9 +19,12 @@ import { docOptions, options } from "./options.ts";
|
|
|
18
19
|
export async function loadConfigFile(configName?: string): Promise<UserConfigLoadResult | null> {
|
|
19
20
|
const configSearchOptions: Partial<ConfigSearchOptions> = {
|
|
20
21
|
loaders: {
|
|
21
|
-
// ESM loader
|
|
22
|
+
// ESM loader. cosmiconfig hands us an absolute filesystem path; Node's import()
|
|
23
|
+
// tolerates that as a non-spec extension, but spec-compliant runtimes (GJS /
|
|
24
|
+
// SpiderMonkey) reject it with "Module not found: <abs-path>". Convert to a
|
|
25
|
+
// file:// URL so the loader works in both runtimes.
|
|
22
26
|
".js": async (filepath) => {
|
|
23
|
-
const file = await import(filepath);
|
|
27
|
+
const file = await import(pathToFileURL(filepath).href);
|
|
24
28
|
|
|
25
29
|
// Files with `exports.default = { ... }`
|
|
26
30
|
if (file?.default?.default) {
|
package/src/config/defaults.ts
CHANGED
|
@@ -53,6 +53,20 @@ function getDefaultGirDirectories(): string[] {
|
|
|
53
53
|
"/usr/lib/x86_64-linux-gnu/mutter-*",
|
|
54
54
|
];
|
|
55
55
|
|
|
56
|
+
// Flatpak: `--filesystem=host` exposes the host's filesystem under
|
|
57
|
+
// /run/host. The GNOME runtime ships GIR typelibs but not the XML, so
|
|
58
|
+
// inside the sandbox we must read from /run/host/usr/share/gir-1.0.
|
|
59
|
+
// Detected via FLATPAK_ID (set for every Flatpak-launched process) or
|
|
60
|
+
// the .flatpak-info marker file (always present in the sandbox).
|
|
61
|
+
if (process.env.FLATPAK_ID || existsSync("/.flatpak-info")) {
|
|
62
|
+
girDirectories.unshift(
|
|
63
|
+
"/run/host/usr/local/share/gir-1.0",
|
|
64
|
+
"/run/host/usr/share/gir-1.0",
|
|
65
|
+
"/run/host/usr/share/*/gir-1.0",
|
|
66
|
+
"/run/host/usr/lib/x86_64-linux-gnu/mutter-*",
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
56
70
|
// NixOS and other distributions does not have a /usr/local/share directory.
|
|
57
71
|
// Instead, the nix store paths with Gir files are set as XDG_DATA_DIRS.
|
|
58
72
|
// See https://github.com/NixOS/nixpkgs/blob/96e18717904dfedcd884541e5a92bf9ff632cf39/pkgs/development/libraries/gobject-introspection/setup-hook.sh#L7-L10
|
package/src/config/options.ts
CHANGED
|
@@ -257,8 +257,8 @@ export const createOptions = {
|
|
|
257
257
|
template: {
|
|
258
258
|
type: "string" as const,
|
|
259
259
|
alias: "t",
|
|
260
|
-
description: "Template to scaffold (types-locally, types-npm, types-workspace)",
|
|
261
|
-
choices: ["types-locally", "types-npm", "types-workspace"] as const,
|
|
260
|
+
description: "Template to scaffold (types-locally, types-npm, types-workspace, types-gjsify)",
|
|
261
|
+
choices: ["types-locally", "types-npm", "types-workspace", "types-gjsify"] as const,
|
|
262
262
|
},
|
|
263
263
|
install: {
|
|
264
264
|
type: "boolean" as const,
|