@gtkx/codegen 1.2.2 → 1.3.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 +2 -1
- package/dist/analysis/descriptor-render.d.ts +7 -1
- package/dist/analysis/descriptor-render.d.ts.map +1 -1
- package/dist/analysis/descriptor-render.js +36 -15
- package/dist/analysis/descriptor-render.js.map +1 -1
- package/dist/analysis/descriptor.d.ts +4 -1
- package/dist/analysis/descriptor.d.ts.map +1 -1
- package/dist/analysis/descriptor.js +11 -2
- package/dist/analysis/descriptor.js.map +1 -1
- package/dist/analysis/param-capability.d.ts +5 -2
- package/dist/analysis/param-capability.d.ts.map +1 -1
- package/dist/analysis/param-capability.js +36 -4
- package/dist/analysis/param-capability.js.map +1 -1
- package/dist/analysis/param-structure.d.ts +1 -1
- package/dist/analysis/param-structure.d.ts.map +1 -1
- package/dist/analysis/param-structure.js.map +1 -1
- package/dist/analysis/ts-type.d.ts +1 -1
- package/dist/analysis/ts-type.d.ts.map +1 -1
- package/dist/analysis/ts-type.js +28 -10
- package/dist/analysis/ts-type.js.map +1 -1
- package/dist/compile.js +1 -1
- package/dist/compile.js.map +1 -1
- package/dist/docs/api-reference.d.ts +6 -0
- package/dist/docs/api-reference.d.ts.map +1 -1
- package/dist/docs/api-reference.js +11 -2
- package/dist/docs/api-reference.js.map +1 -1
- package/dist/docs/pipeline.d.ts +3 -0
- package/dist/docs/pipeline.d.ts.map +1 -1
- package/dist/docs/pipeline.js +10 -1
- package/dist/docs/pipeline.js.map +1 -1
- package/dist/fingerprint.d.ts +5 -0
- package/dist/fingerprint.d.ts.map +1 -1
- package/dist/fingerprint.js +107 -15
- package/dist/fingerprint.js.map +1 -1
- package/dist/gi.d.ts +3 -0
- package/dist/gi.d.ts.map +1 -1
- package/dist/gi.js +29 -7
- package/dist/gi.js.map +1 -1
- package/dist/gir/external-namespaces.d.ts +8 -0
- package/dist/gir/external-namespaces.d.ts.map +1 -0
- package/dist/gir/external-namespaces.js +4 -0
- package/dist/gir/external-namespaces.js.map +1 -0
- package/dist/gir/finish-overrides.d.ts +3 -0
- package/dist/gir/finish-overrides.d.ts.map +1 -0
- package/dist/gir/finish-overrides.js +5 -0
- package/dist/gir/finish-overrides.js.map +1 -0
- package/dist/gir/function.d.ts +5 -2
- package/dist/gir/function.d.ts.map +1 -1
- package/dist/gir/function.js +34 -5
- package/dist/gir/function.js.map +1 -1
- package/dist/gir/hidden-symbols.d.ts +3 -0
- package/dist/gir/hidden-symbols.d.ts.map +1 -0
- package/dist/gir/hidden-symbols.js +39 -0
- package/dist/gir/hidden-symbols.js.map +1 -0
- package/dist/gir/library.d.ts +22 -2
- package/dist/gir/library.d.ts.map +1 -1
- package/dist/gir/library.js +21 -3
- package/dist/gir/library.js.map +1 -1
- package/dist/gir/ucs4-overrides.d.ts +3 -0
- package/dist/gir/ucs4-overrides.d.ts.map +1 -0
- package/dist/gir/ucs4-overrides.js +7 -0
- package/dist/gir/ucs4-overrides.js.map +1 -0
- package/dist/jsx.d.ts.map +1 -1
- package/dist/jsx.js +27 -8
- package/dist/jsx.js.map +1 -1
- package/dist/runner.d.ts +8 -0
- package/dist/runner.d.ts.map +1 -1
- package/dist/runner.js +9 -3
- package/dist/runner.js.map +1 -1
- package/dist/store/external-package-links.d.ts +6 -0
- package/dist/store/external-package-links.d.ts.map +1 -0
- package/dist/store/external-package-links.js +158 -0
- package/dist/store/external-package-links.js.map +1 -0
- package/dist/store/gi/callable-doc.d.ts.map +1 -1
- package/dist/store/gi/callable-doc.js +4 -4
- package/dist/store/gi/callable-doc.js.map +1 -1
- package/dist/store/gi/callables.js +1 -1
- package/dist/store/gi/callables.js.map +1 -1
- package/dist/store/gi/class.d.ts.map +1 -1
- package/dist/store/gi/class.js +17 -0
- package/dist/store/gi/class.js.map +1 -1
- package/dist/store/gi/constructor-props.js +1 -1
- package/dist/store/gi/constructor-props.js.map +1 -1
- package/dist/store/gi/function.d.ts.map +1 -1
- package/dist/store/gi/function.js +2 -1
- package/dist/store/gi/function.js.map +1 -1
- package/dist/store/gi/gtype-binding.d.ts +2 -1
- package/dist/store/gi/gtype-binding.d.ts.map +1 -1
- package/dist/store/gi/gtype-binding.js +6 -1
- package/dist/store/gi/gtype-binding.js.map +1 -1
- package/dist/store/gi/method.d.ts +7 -2
- package/dist/store/gi/method.d.ts.map +1 -1
- package/dist/store/gi/method.js +126 -30
- package/dist/store/gi/method.js.map +1 -1
- package/dist/store/gi/param-marshal.d.ts +8 -1
- package/dist/store/gi/param-marshal.d.ts.map +1 -1
- package/dist/store/gi/param-marshal.js +52 -4
- package/dist/store/gi/param-marshal.js.map +1 -1
- package/dist/store/gi/record-constructor.d.ts.map +1 -1
- package/dist/store/gi/record-constructor.js +2 -3
- package/dist/store/gi/record-constructor.js.map +1 -1
- package/dist/store/gi/record-field-accessor.d.ts +2 -1
- package/dist/store/gi/record-field-accessor.d.ts.map +1 -1
- package/dist/store/gi/record-field-accessor.js +9 -3
- package/dist/store/gi/record-field-accessor.js.map +1 -1
- package/dist/store/gi/runtime-override.js +1 -1
- package/dist/store/gi/runtime-override.js.map +1 -1
- package/dist/store/gi/signal.js +2 -2
- package/dist/store/gi/signal.js.map +1 -1
- package/dist/store/gi/vtable.d.ts.map +1 -1
- package/dist/store/gi/vtable.js +82 -12
- package/dist/store/gi/vtable.js.map +1 -1
- package/dist/store/gi-store.d.ts +7 -2
- package/dist/store/gi-store.d.ts.map +1 -1
- package/dist/store/gi-store.js +19 -4
- package/dist/store/gi-store.js.map +1 -1
- package/dist/store/jsx/jsx.d.ts.map +1 -1
- package/dist/store/jsx/jsx.js +3 -1
- package/dist/store/jsx/jsx.js.map +1 -1
- package/dist/store/jsx-store.d.ts +8 -1
- package/dist/store/jsx-store.d.ts.map +1 -1
- package/dist/store/jsx-store.js +9 -2
- package/dist/store/jsx-store.js.map +1 -1
- package/dist/store/resolve-store.d.ts +2 -1
- package/dist/store/resolve-store.d.ts.map +1 -1
- package/dist/store/resolve-store.js +2 -1
- package/dist/store/resolve-store.js.map +1 -1
- package/dist/store/store-fs.d.ts +2 -1
- package/dist/store/store-fs.d.ts.map +1 -1
- package/dist/store/store-fs.js +8 -3
- package/dist/store/store-fs.js.map +1 -1
- package/dist/writer/context.d.ts.map +1 -1
- package/dist/writer/context.js +8 -0
- package/dist/writer/context.js.map +1 -1
- package/dist/writer/gtk-doc.d.ts.map +1 -1
- package/dist/writer/gtk-doc.js +27 -1
- package/dist/writer/gtk-doc.js.map +1 -1
- package/overrides/gdk/rgba.ts.ejs +15 -1
- package/overrides/glib/index.ts.ejs +3 -0
- package/overrides/glib/regex.ts.ejs +66 -0
- package/overrides/gobject/index.ts.ejs +3 -0
- package/overrides/gobject/object-class.ts.ejs +27 -0
- package/overrides/gobject/param-spec-getters.ts.ejs +57 -0
- package/overrides/gobject/param-spec.ts.ejs +21 -0
- package/overrides/gobject/value.ts.ejs +6 -1
- package/overrides/graphene/structs.ts.ejs +38 -3
- package/overrides/gtk/index.ts.ejs +2 -0
- package/overrides/gtk/widget-class.ts.ejs +28 -0
- package/package.json +6 -5
- package/src/analysis/descriptor-render.ts +59 -16
- package/src/analysis/descriptor.ts +15 -3
- package/src/analysis/param-capability.ts +68 -5
- package/src/analysis/param-structure.ts +1 -1
- package/src/analysis/ts-type.ts +45 -11
- package/src/compile.ts +1 -1
- package/src/docs/api-reference.ts +20 -2
- package/src/docs/pipeline.ts +15 -1
- package/src/fingerprint.ts +144 -16
- package/src/gi.ts +44 -9
- package/src/gir/external-namespaces.ts +8 -0
- package/src/gir/finish-overrides.ts +5 -0
- package/src/gir/function.ts +52 -14
- package/src/gir/hidden-symbols.ts +39 -0
- package/src/gir/library.ts +36 -3
- package/src/gir/ucs4-overrides.ts +7 -0
- package/src/jsx.ts +33 -8
- package/src/runner.ts +17 -3
- package/src/store/external-package-links.ts +226 -0
- package/src/store/gi/callable-doc.ts +8 -4
- package/src/store/gi/callables.ts +1 -1
- package/src/store/gi/class.ts +29 -0
- package/src/store/gi/constructor-props.ts +1 -1
- package/src/store/gi/function.ts +2 -1
- package/src/store/gi/gtype-binding.ts +8 -1
- package/src/store/gi/method.ts +189 -36
- package/src/store/gi/param-marshal.ts +67 -4
- package/src/store/gi/record-constructor.ts +8 -3
- package/src/store/gi/record-field-accessor.ts +11 -2
- package/src/store/gi/runtime-override.ts +1 -1
- package/src/store/gi/signal.ts +2 -2
- package/src/store/gi/vtable.ts +118 -11
- package/src/store/gi-store.ts +33 -3
- package/src/store/jsx/jsx.ts +3 -1
- package/src/store/jsx-store.ts +23 -7
- package/src/store/resolve-store.ts +2 -1
- package/src/store/store-fs.ts +10 -2
- package/src/writer/context.ts +11 -0
- package/src/writer/gtk-doc.ts +38 -1
- package/overrides/cairo/context.ts.ejs +0 -1269
- package/overrides/cairo/font-face.ts.ejs +0 -151
- package/overrides/cairo/font-options.ts.ejs +0 -199
- package/overrides/cairo/image-surface.ts.ejs +0 -132
- package/overrides/cairo/index.ts.ejs +0 -22
- package/overrides/cairo/matrix.ts.ejs +0 -171
- package/overrides/cairo/pattern.ts.ejs +0 -476
- package/overrides/cairo/recording-surface.ts.ejs +0 -102
- package/overrides/cairo/region.ts.ejs +0 -237
- package/overrides/cairo/scaled-font.ts.ejs +0 -330
- package/overrides/cairo/surface.ts.ejs +0 -296
package/src/fingerprint.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { createHash } from "node:crypto";
|
|
1
|
+
import { createHash, type Hash } from "node:crypto";
|
|
3
2
|
import { type Dirent, existsSync, readdirSync, readFileSync } from "node:fs";
|
|
4
|
-
import {
|
|
3
|
+
import { createRequire } from "node:module";
|
|
4
|
+
import { dirname, join, relative, resolve } from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
6
|
import packageManifest from "../package.json" with { type: "json" };
|
|
7
|
+
import { EXTERNAL_NAMESPACES } from "./gir/external-namespaces.js";
|
|
7
8
|
import { arrayGuard, hasFields, isNumber, isString, optionalGuard } from "./guards.js";
|
|
8
9
|
import { readJsonFile } from "./json.js";
|
|
9
10
|
|
|
@@ -11,7 +12,11 @@ type GiInputs = {
|
|
|
11
12
|
girFiles: string[];
|
|
12
13
|
libraries: string[];
|
|
13
14
|
girPath: string[];
|
|
15
|
+
storeVersion: string | undefined;
|
|
14
16
|
isByteArrayTyped: boolean;
|
|
17
|
+
isValueUnwrapped: boolean;
|
|
18
|
+
isFinishTrimmed: boolean;
|
|
19
|
+
isInoutInPlace: boolean;
|
|
15
20
|
};
|
|
16
21
|
|
|
17
22
|
type GiFingerprint = {
|
|
@@ -36,6 +41,7 @@ type DocsFingerprint = {
|
|
|
36
41
|
|
|
37
42
|
type JsxFingerprintInput = {
|
|
38
43
|
reactVersion: string;
|
|
44
|
+
reactSubexports: string[];
|
|
39
45
|
components: Record<string, ModuleExport>;
|
|
40
46
|
lazyElements: string[];
|
|
41
47
|
props: Record<string, ModuleExport>;
|
|
@@ -47,25 +53,139 @@ type JsxFingerprint = {
|
|
|
47
53
|
intrinsicElementCount: number;
|
|
48
54
|
};
|
|
49
55
|
|
|
56
|
+
type InstalledManifest = { name: string; version: string };
|
|
57
|
+
|
|
50
58
|
const FINGERPRINT_FILENAME = ".codegen-fingerprint.json";
|
|
51
|
-
const
|
|
52
|
-
const OVERRIDES_ROOT =
|
|
59
|
+
const PACKAGE_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
60
|
+
const OVERRIDES_ROOT = join(PACKAGE_ROOT, "overrides");
|
|
61
|
+
const requireFromCodegen = createRequire(import.meta.url);
|
|
62
|
+
const codegenHashCache: Map<string, string> = new Map();
|
|
63
|
+
|
|
64
|
+
const compareOrdinal = (a: string, b: string): number => {
|
|
65
|
+
if (a < b) {
|
|
66
|
+
return -1;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return a > b ? 1 : 0;
|
|
70
|
+
};
|
|
53
71
|
|
|
54
|
-
const
|
|
72
|
+
const sortOrdinal = (values: string[]): string[] => values.toSorted(compareOrdinal);
|
|
73
|
+
const sortAlpha = (values: string[]): string => sortOrdinal(values).join(",");
|
|
55
74
|
|
|
56
|
-
const
|
|
57
|
-
if (!existsSync(
|
|
75
|
+
const filesUnder = (root: string): string[] => {
|
|
76
|
+
if (!existsSync(root)) {
|
|
58
77
|
return [];
|
|
59
78
|
}
|
|
60
79
|
|
|
61
|
-
return readdirSync(
|
|
80
|
+
return readdirSync(root, { recursive: true, withFileTypes: true })
|
|
62
81
|
.filter((entry: Dirent) => entry.isFile())
|
|
63
82
|
.map((entry: Dirent) => join(entry.parentPath, entry.name));
|
|
64
83
|
};
|
|
65
84
|
|
|
85
|
+
const hashTree = (hash: Hash, label: string, root: string): void => {
|
|
86
|
+
const files = sortOrdinal(filesUnder(root));
|
|
87
|
+
|
|
88
|
+
for (const file of files) {
|
|
89
|
+
hash.update("\n");
|
|
90
|
+
hash.update(join(label, relative(root, file)));
|
|
91
|
+
hash.update("\0");
|
|
92
|
+
hash.update(readFileSync(file));
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const isInstalledManifest = (value: unknown): value is InstalledManifest =>
|
|
97
|
+
hasFields<InstalledManifest>(value, { name: isString, version: isString });
|
|
98
|
+
|
|
99
|
+
const tryResolve = (specifier: string): string | undefined => {
|
|
100
|
+
try {
|
|
101
|
+
return requireFromCodegen.resolve(specifier);
|
|
102
|
+
} catch {
|
|
103
|
+
return undefined;
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const manifestVersion = (path: string | undefined, name: string): string | undefined => {
|
|
108
|
+
if (path === undefined) {
|
|
109
|
+
return undefined;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const manifest = readJsonFile(path);
|
|
113
|
+
|
|
114
|
+
return isInstalledManifest(manifest) && manifest.name === name ? manifest.version : undefined;
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
const packageRootFor = (name: string): string | undefined => {
|
|
118
|
+
const entry = tryResolve(name);
|
|
119
|
+
|
|
120
|
+
if (entry === undefined) {
|
|
121
|
+
return undefined;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
for (let directory = dirname(entry); directory !== dirname(directory); directory = dirname(directory)) {
|
|
125
|
+
if (manifestVersion(join(directory, "package.json"), name) !== undefined) {
|
|
126
|
+
return directory;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return undefined;
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
const installedVersion = (name: string): string | undefined => {
|
|
134
|
+
const direct = manifestVersion(tryResolve(`${name}/package.json`), name);
|
|
135
|
+
|
|
136
|
+
if (direct !== undefined) {
|
|
137
|
+
return direct;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const root = packageRootFor(name);
|
|
141
|
+
|
|
142
|
+
return root === undefined ? undefined : manifestVersion(join(root, "package.json"), name);
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
const dependencyVersions = (): string[] =>
|
|
146
|
+
sortOrdinal(
|
|
147
|
+
Object.entries(packageManifest.dependencies)
|
|
148
|
+
.filter(([name]) => !name.startsWith("@types/"))
|
|
149
|
+
.map(([name, range]) => `${name}@${installedVersion(name) ?? range}`),
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
const hashPackageCode = (hash: Hash, label: string, root: string): void => {
|
|
153
|
+
hashTree(hash, join(label, "src"), join(root, "src"));
|
|
154
|
+
hashTree(hash, join(label, "dist"), join(root, "dist"));
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
const computeCodegenHash = (): string => {
|
|
158
|
+
const hash = createHash("sha256");
|
|
159
|
+
hash.update(dependencyVersions().join(","));
|
|
160
|
+
hashPackageCode(hash, "codegen", PACKAGE_ROOT);
|
|
161
|
+
hashTree(hash, "overrides", OVERRIDES_ROOT);
|
|
162
|
+
const utilsRoot = packageRootFor("@gtkx/utils");
|
|
163
|
+
|
|
164
|
+
if (utilsRoot !== undefined) {
|
|
165
|
+
hashPackageCode(hash, "@gtkx/utils", utilsRoot);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return hash.digest("hex");
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
const codegenHash = (): string => {
|
|
172
|
+
const cached = codegenHashCache.get("codegen");
|
|
173
|
+
|
|
174
|
+
if (cached !== undefined) {
|
|
175
|
+
return cached;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const value = computeCodegenHash();
|
|
179
|
+
codegenHashCache.set("codegen", value);
|
|
180
|
+
|
|
181
|
+
return value;
|
|
182
|
+
};
|
|
183
|
+
|
|
66
184
|
const hashGi = (inputs: GiInputs): string => {
|
|
67
185
|
const hash = createHash("sha256");
|
|
68
|
-
hash.update(
|
|
186
|
+
hash.update(codegenHash());
|
|
187
|
+
hash.update("\n");
|
|
188
|
+
hash.update(JSON.stringify(EXTERNAL_NAMESPACES));
|
|
69
189
|
hash.update("\n");
|
|
70
190
|
hash.update(sortAlpha(inputs.libraries));
|
|
71
191
|
hash.update("\n");
|
|
@@ -73,9 +193,16 @@ const hashGi = (inputs: GiInputs): string => {
|
|
|
73
193
|
hash.update("\n");
|
|
74
194
|
hash.update(String(inputs.isByteArrayTyped));
|
|
75
195
|
hash.update("\n");
|
|
76
|
-
|
|
196
|
+
hash.update(String(inputs.isValueUnwrapped));
|
|
197
|
+
hash.update("\n");
|
|
198
|
+
hash.update(String(inputs.isFinishTrimmed));
|
|
199
|
+
hash.update("\n");
|
|
200
|
+
hash.update(String(inputs.isInoutInPlace));
|
|
201
|
+
hash.update("\n");
|
|
202
|
+
hash.update(String(inputs.storeVersion));
|
|
203
|
+
const girFiles = sortOrdinal(inputs.girFiles);
|
|
77
204
|
|
|
78
|
-
for (const file of
|
|
205
|
+
for (const file of girFiles) {
|
|
79
206
|
hash.update("\n");
|
|
80
207
|
hash.update(file);
|
|
81
208
|
hash.update("\0");
|
|
@@ -161,19 +288,20 @@ const isDocsOutputFresh = (outDir: string, inputs: GiInputs, input: DocsFingerpr
|
|
|
161
288
|
};
|
|
162
289
|
|
|
163
290
|
const serializeModuleExports = (map: Record<string, ModuleExport>): [string, string, string][] =>
|
|
164
|
-
|
|
291
|
+
sortOrdinal(Object.keys(map)).map((type) => [type, map[type]?.module ?? "", map[type]?.export ?? ""]);
|
|
165
292
|
|
|
166
293
|
const serializeOmittedProps = (map: Record<string, string[]>): [string, string][] =>
|
|
167
|
-
|
|
294
|
+
sortOrdinal(Object.keys(map)).map((type) => [type, sortAlpha(map[type] ?? [])]);
|
|
168
295
|
|
|
169
296
|
const hashJsx = (input: JsxFingerprintInput): string =>
|
|
170
297
|
createHash("sha256")
|
|
171
298
|
.update(
|
|
172
299
|
JSON.stringify([
|
|
173
|
-
|
|
300
|
+
codegenHash(),
|
|
174
301
|
input.reactVersion,
|
|
302
|
+
sortOrdinal(input.reactSubexports),
|
|
175
303
|
serializeModuleExports(input.components),
|
|
176
|
-
|
|
304
|
+
sortOrdinal(input.lazyElements),
|
|
177
305
|
serializeModuleExports(input.props),
|
|
178
306
|
serializeOmittedProps(input.omittedProps),
|
|
179
307
|
]),
|
package/src/gi.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { Library } from "./gir/library.js";
|
|
2
2
|
import type { StoreOptions } from "./store/store-fs.js";
|
|
3
3
|
import { computeGiFingerprint } from "./fingerprint.js";
|
|
4
|
+
import { externalPackageFor } from "./gir/external-namespaces.js";
|
|
4
5
|
import { namespaceDirectory } from "./gir/namespace.js";
|
|
5
|
-
import { type GiNamespaceInput, writeGiStore } from "./store/gi-store.js";
|
|
6
|
+
import { type GiExternalNamespaceInput, type GiNamespaceInput, writeGiStore } from "./store/gi-store.js";
|
|
6
7
|
import { generateNamespaceModule } from "./store/gi/pipeline.js";
|
|
7
8
|
|
|
8
9
|
type GiCodegenOptions = {
|
|
@@ -10,25 +11,59 @@ type GiCodegenOptions = {
|
|
|
10
11
|
libraries: string[];
|
|
11
12
|
girPath: string[];
|
|
12
13
|
isByteArrayTyped: boolean;
|
|
14
|
+
isValueUnwrapped: boolean;
|
|
15
|
+
isFinishTrimmed: boolean;
|
|
16
|
+
isInoutInPlace: boolean;
|
|
13
17
|
};
|
|
14
18
|
|
|
15
|
-
|
|
16
|
-
|
|
19
|
+
type SplitNamespaces = {
|
|
20
|
+
namespaces: GiNamespaceInput[];
|
|
21
|
+
externalNamespaces: GiExternalNamespaceInput[];
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const splitNamespaces = (library: Library): SplitNamespaces => {
|
|
25
|
+
const namespaces: GiNamespaceInput[] = [];
|
|
26
|
+
const externalNamespaces: GiExternalNamespaceInput[] = [];
|
|
27
|
+
|
|
28
|
+
for (const namespace of library.namespaces.values()) {
|
|
29
|
+
const packageName = externalPackageFor(namespace.name);
|
|
30
|
+
|
|
31
|
+
if (packageName !== undefined) {
|
|
32
|
+
externalNamespaces.push({
|
|
33
|
+
directory: namespaceDirectory(namespace),
|
|
34
|
+
packageName,
|
|
35
|
+
girFile: namespace.girFile,
|
|
36
|
+
});
|
|
17
37
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
namespaces.push({
|
|
42
|
+
directory: namespaceDirectory(namespace),
|
|
43
|
+
rawSource: generateNamespaceModule(namespace, library),
|
|
44
|
+
girFile: namespace.girFile,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return { namespaces, externalNamespaces };
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const runGiCodegen = (library: Library, options: GiCodegenOptions): number => {
|
|
52
|
+
const { gi, libraries, girPath, isByteArrayTyped, isValueUnwrapped, isFinishTrimmed, isInoutInPlace } = options;
|
|
53
|
+
const { namespaces, externalNamespaces } = splitNamespaces(library);
|
|
23
54
|
|
|
24
55
|
const fingerprint = computeGiFingerprint({
|
|
25
56
|
girFiles: library.girFiles,
|
|
26
57
|
libraries: [...libraries],
|
|
27
58
|
girPath: [...girPath],
|
|
59
|
+
storeVersion: gi.version,
|
|
28
60
|
isByteArrayTyped,
|
|
61
|
+
isValueUnwrapped,
|
|
62
|
+
isFinishTrimmed,
|
|
63
|
+
isInoutInPlace,
|
|
29
64
|
});
|
|
30
65
|
|
|
31
|
-
writeGiStore(gi, namespaces, fingerprint);
|
|
66
|
+
writeGiStore(gi, namespaces, externalNamespaces, fingerprint);
|
|
32
67
|
|
|
33
68
|
return library.namespaces.size;
|
|
34
69
|
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
type ExternalNamespace = { namespace: string; packageName: string };
|
|
2
|
+
|
|
3
|
+
const EXTERNAL_NAMESPACES: ExternalNamespace[] = [{ namespace: "cairo", packageName: "@gtkx/cairo" }];
|
|
4
|
+
|
|
5
|
+
const externalPackageFor = (namespaceName: string): string | undefined =>
|
|
6
|
+
EXTERNAL_NAMESPACES.find((entry) => entry.namespace === namespaceName)?.packageName;
|
|
7
|
+
|
|
8
|
+
export { EXTERNAL_NAMESPACES, externalPackageFor, type ExternalNamespace };
|
package/src/gir/function.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import type { GirAnnotations } from "./annotations.js";
|
|
2
2
|
import type { ParseContext } from "./type-id.js";
|
|
3
3
|
import { type CursorParameterNames, PARAMETERS_MISSING_ARRAY_EXTENT } from "./cursor-overrides.js";
|
|
4
|
+
import { FUNCTIONS_MISSING_FINISH_FUNC } from "./finish-overrides.js";
|
|
5
|
+
import { HIDDEN_SYMBOLS } from "./hidden-symbols.js";
|
|
4
6
|
import { PARAMETERS_MISSING_NULLABLE_ANNOTATION } from "./nullable-overrides.js";
|
|
5
7
|
import { type GirParameter, type GirReturnValue, parameterFromNode, parseCallable } from "./parameter.js";
|
|
6
8
|
import { attr, getChild, type RawNode } from "./parse.js";
|
|
9
|
+
import { RETURNS_MISSING_UCS4_ARRAY_TYPE } from "./ucs4-overrides.js";
|
|
7
10
|
|
|
8
11
|
/** A callable declared by a GIR namespace, class, or record: a function, a method, or a constructor. */
|
|
9
12
|
type GirFunction = {
|
|
@@ -17,13 +20,16 @@ type GirFunction = {
|
|
|
17
20
|
cIdentifier: string | undefined;
|
|
18
21
|
/** Whether the C function takes a trailing `GError` out parameter and can fail. */
|
|
19
22
|
throws: boolean;
|
|
20
|
-
/** Whether the
|
|
23
|
+
/** Whether the callable is bindable: the GIR marks it introspectable and GTKX does not hide it. */
|
|
21
24
|
introspectable: boolean;
|
|
22
25
|
/** Qualified `Type.member` the GIR redirects the callable to, from its `moved-to` annotation. */
|
|
23
26
|
movedTo: string | undefined;
|
|
24
27
|
/** Name of the callable that shadows this one, from the GIR's `shadowed-by` annotation. */
|
|
25
28
|
shadowedBy: string | undefined;
|
|
26
|
-
/**
|
|
29
|
+
/**
|
|
30
|
+
* Name of the callable that completes this asynchronous one, from the GIR's `glib:finish-func`
|
|
31
|
+
* or a GTKX override for a GIR that lacks the annotation.
|
|
32
|
+
*/
|
|
27
33
|
finishFunc: string | undefined;
|
|
28
34
|
/** The instance the callable is invoked on, absent for constructors and namespace-level functions. */
|
|
29
35
|
instance: GirParameter | undefined;
|
|
@@ -84,20 +90,52 @@ const bindMissingArrayExtent = (fn: GirFunction): GirFunction => {
|
|
|
84
90
|
return fn;
|
|
85
91
|
};
|
|
86
92
|
|
|
93
|
+
const bindMissingUcs4ReturnArray = (fn: GirFunction, context: ParseContext): GirFunction => {
|
|
94
|
+
if (fn.cIdentifier !== undefined && RETURNS_MISSING_UCS4_ARRAY_TYPE.has(fn.cIdentifier)) {
|
|
95
|
+
fn.returnValue.type = context.addContainer({
|
|
96
|
+
kind: "carray",
|
|
97
|
+
element: context.addPrimitive("unichar"),
|
|
98
|
+
elementCType: "gunichar",
|
|
99
|
+
arrayCType: "gunichar*",
|
|
100
|
+
lengthParameterIndex: undefined,
|
|
101
|
+
fixedSize: undefined,
|
|
102
|
+
isZeroTerminated: true,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return fn;
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
const annotatedFinishFunc = (node: RawNode, cIdentifier: string | undefined): string | undefined => {
|
|
110
|
+
const annotated = attr(node, "glib:finish-func");
|
|
111
|
+
|
|
112
|
+
if (annotated !== undefined) {
|
|
113
|
+
return annotated;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return cIdentifier === undefined ? undefined : FUNCTIONS_MISSING_FINISH_FUNC.get(cIdentifier);
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
const isHiddenSymbol = (cIdentifier: string | undefined): boolean =>
|
|
120
|
+
cIdentifier !== undefined && HIDDEN_SYMBOLS.has(cIdentifier);
|
|
121
|
+
|
|
87
122
|
const functionFromNode = (node: RawNode, context: ParseContext): GirFunction => {
|
|
88
123
|
const instanceNode = getChild(getChild(node, "parameters"), "instance-parameter");
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
124
|
+
const callable = parseCallable(node, context);
|
|
125
|
+
const cIdentifier = attr(node, "c:identifier");
|
|
126
|
+
|
|
127
|
+
const fn: GirFunction = {
|
|
128
|
+
...callable,
|
|
129
|
+
introspectable: callable.introspectable && !isHiddenSymbol(cIdentifier),
|
|
130
|
+
name: attr(node, "shadows") ?? attr(node, "name") ?? "",
|
|
131
|
+
cIdentifier,
|
|
132
|
+
movedTo: attr(node, "moved-to"),
|
|
133
|
+
shadowedBy: attr(node, "shadowed-by"),
|
|
134
|
+
finishFunc: annotatedFinishFunc(node, cIdentifier),
|
|
135
|
+
instance: instanceNode === undefined ? undefined : parameterFromNode(instanceNode, context),
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
return bindMissingUcs4ReturnArray(bindMissingArrayExtent(relaxMissingNullable(fn)), context);
|
|
101
139
|
};
|
|
102
140
|
|
|
103
141
|
export { functionFromNode, type GirFunction };
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
const HIDDEN_SYMBOLS: Set<string> = new Set([
|
|
2
|
+
"g_action_map_add_action_entries",
|
|
3
|
+
"g_ascii_dtostr",
|
|
4
|
+
"g_ascii_formatd",
|
|
5
|
+
"g_file_info_set_attribute",
|
|
6
|
+
"g_file_set_attribute",
|
|
7
|
+
"g_log_set_writer_func",
|
|
8
|
+
"g_object_get_data",
|
|
9
|
+
"g_object_get_qdata",
|
|
10
|
+
"g_object_set_data",
|
|
11
|
+
"g_object_set_data_full",
|
|
12
|
+
"g_object_set_qdata",
|
|
13
|
+
"g_object_set_qdata_full",
|
|
14
|
+
"g_object_steal_data",
|
|
15
|
+
"g_object_steal_qdata",
|
|
16
|
+
"g_param_spec_get_qdata",
|
|
17
|
+
"g_param_spec_set_qdata",
|
|
18
|
+
"g_param_spec_set_qdata_full",
|
|
19
|
+
"g_param_spec_steal_qdata",
|
|
20
|
+
"g_ref_string_acquire",
|
|
21
|
+
"g_ref_string_length",
|
|
22
|
+
"g_ref_string_new",
|
|
23
|
+
"g_ref_string_new_intern",
|
|
24
|
+
"g_ref_string_new_len",
|
|
25
|
+
"g_ref_string_release",
|
|
26
|
+
"g_stpcpy",
|
|
27
|
+
"g_strcanon",
|
|
28
|
+
"g_strchomp",
|
|
29
|
+
"g_strchug",
|
|
30
|
+
"g_strdelimit",
|
|
31
|
+
"g_strdown",
|
|
32
|
+
"g_strreverse",
|
|
33
|
+
"g_strup",
|
|
34
|
+
"g_thread_exit",
|
|
35
|
+
"g_thread_new",
|
|
36
|
+
"g_thread_try_new",
|
|
37
|
+
]);
|
|
38
|
+
|
|
39
|
+
export { HIDDEN_SYMBOLS };
|
package/src/gir/library.ts
CHANGED
|
@@ -24,6 +24,18 @@ type TypeTable = {
|
|
|
24
24
|
index: Map<string, number>;
|
|
25
25
|
};
|
|
26
26
|
|
|
27
|
+
/** Behavior a project opted into ahead of the next major version, through the `future` block of its config. */
|
|
28
|
+
type FutureBehavior = {
|
|
29
|
+
/** Whether byte sequences render as `Uint8Array` rather than `number[]`. */
|
|
30
|
+
isByteArrayTyped?: boolean;
|
|
31
|
+
/** Whether a `GObject.Value` a binding hands back surfaces as what it holds rather than as the value. */
|
|
32
|
+
isValueUnwrapped?: boolean;
|
|
33
|
+
/** Whether a promisified result drops the leading success boolean of a throwing finish function. */
|
|
34
|
+
isFinishTrimmed?: boolean;
|
|
35
|
+
/** Whether a handle-passing inout parameter is mutated in place rather than packed into the result. */
|
|
36
|
+
isInoutInPlace?: boolean;
|
|
37
|
+
};
|
|
38
|
+
|
|
27
39
|
/** A namespace whose header has been read and whose shell is registered, before its body is parsed. */
|
|
28
40
|
type DiscoveredNamespace = {
|
|
29
41
|
/** Attributes and includes read from the namespace's GIR file. */
|
|
@@ -84,12 +96,15 @@ class Library {
|
|
|
84
96
|
*
|
|
85
97
|
* @param libraries GIR identifiers to load, such as `Gtk-4.0`.
|
|
86
98
|
* @param girPath Directories searched, in order, for each `.gir` file.
|
|
87
|
-
* @param
|
|
99
|
+
* @param future Behavior the project opted into ahead of the next major version.
|
|
88
100
|
* @returns A library holding every namespace that was parsed.
|
|
89
101
|
*/
|
|
90
|
-
static load(libraries: string[], girPath: string[],
|
|
102
|
+
static load(libraries: string[], girPath: string[], future: FutureBehavior = {}): Library {
|
|
91
103
|
const library = new Library();
|
|
92
|
-
library.isByteArrayTypedValue = isByteArrayTyped;
|
|
104
|
+
library.isByteArrayTypedValue = future.isByteArrayTyped === true;
|
|
105
|
+
library.isValueUnwrappedValue = future.isValueUnwrapped === true;
|
|
106
|
+
library.isFinishTrimmedValue = future.isFinishTrimmed === true;
|
|
107
|
+
library.isInoutInPlaceValue = future.isInoutInPlace === true;
|
|
93
108
|
this.drive(library, libraries, girPath);
|
|
94
109
|
|
|
95
110
|
return library;
|
|
@@ -102,6 +117,9 @@ class Library {
|
|
|
102
117
|
private typeTables: TypeTable[] = [];
|
|
103
118
|
private girFilesValue: string[] = [];
|
|
104
119
|
private isByteArrayTypedValue = false;
|
|
120
|
+
private isValueUnwrappedValue = false;
|
|
121
|
+
private isFinishTrimmedValue = false;
|
|
122
|
+
private isInoutInPlaceValue = false;
|
|
105
123
|
|
|
106
124
|
/** Creates a library with no namespaces loaded; {@link Library.load} builds a populated one. */
|
|
107
125
|
constructor() {
|
|
@@ -336,6 +354,21 @@ class Library {
|
|
|
336
354
|
return this.isByteArrayTypedValue;
|
|
337
355
|
}
|
|
338
356
|
|
|
357
|
+
/** Whether a `GObject.Value` a binding hands back surfaces as what it holds rather than as the value. */
|
|
358
|
+
public get isValueUnwrapped(): boolean {
|
|
359
|
+
return this.isValueUnwrappedValue;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/** Whether a promisified result drops the leading success boolean of a throwing finish function. */
|
|
363
|
+
public get isFinishTrimmed(): boolean {
|
|
364
|
+
return this.isFinishTrimmedValue;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/** Whether a handle-passing inout parameter is mutated in place rather than packed into the result. */
|
|
368
|
+
public get isInoutInPlace(): boolean {
|
|
369
|
+
return this.isInoutInPlaceValue;
|
|
370
|
+
}
|
|
371
|
+
|
|
339
372
|
/** Paths of the `.gir` files that were read, in the order they were discovered. */
|
|
340
373
|
public get girFiles(): string[] {
|
|
341
374
|
return this.girFilesValue;
|
package/src/jsx.ts
CHANGED
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
type JsxFingerprintInput,
|
|
7
7
|
jsxStoreFreshness,
|
|
8
8
|
} from "./fingerprint.js";
|
|
9
|
+
import { externalPackageFor } from "./gir/external-namespaces.js";
|
|
9
10
|
import { type ModuleExport, readBuiltinElements } from "./react/element-config.js";
|
|
10
11
|
import { writeJsxStore } from "./store/jsx-store.js";
|
|
11
12
|
import { ELEMENTS_FILENAME, renderGeneratedElements } from "./store/jsx/generated-elements.js";
|
|
@@ -39,6 +40,7 @@ const runJsxCodegen = async (options: RunJsxCodegenOptions): Promise<RunJsxCodeg
|
|
|
39
40
|
|
|
40
41
|
const fingerprintInput: JsxFingerprintInput = {
|
|
41
42
|
reactVersion: options.jsx.version,
|
|
43
|
+
reactSubexports: options.reactSubexports,
|
|
42
44
|
components,
|
|
43
45
|
lazyElements,
|
|
44
46
|
props,
|
|
@@ -53,7 +55,9 @@ const runJsxCodegen = async (options: RunJsxCodegenOptions): Promise<RunJsxCodeg
|
|
|
53
55
|
}
|
|
54
56
|
}
|
|
55
57
|
|
|
56
|
-
const
|
|
58
|
+
const library = options.getLibrary();
|
|
59
|
+
|
|
60
|
+
const { namespaces, metadata, intrinsicElementCount, elements } = generateJsxFiles(library, {
|
|
57
61
|
reactSubexports: options.reactSubexports,
|
|
58
62
|
components,
|
|
59
63
|
lazyElements,
|
|
@@ -61,15 +65,36 @@ const runJsxCodegen = async (options: RunJsxCodegenOptions): Promise<RunJsxCodeg
|
|
|
61
65
|
omittedProps,
|
|
62
66
|
});
|
|
63
67
|
|
|
64
|
-
writeJsxStore(
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
68
|
+
writeJsxStore({
|
|
69
|
+
options: options.jsx,
|
|
70
|
+
namespaces,
|
|
71
|
+
metadata,
|
|
72
|
+
externalPackages: storeExternalPackages(library),
|
|
73
|
+
rawFiles: [
|
|
74
|
+
{
|
|
75
|
+
relativePath: FINGERPRINT_FILENAME,
|
|
76
|
+
content:
|
|
77
|
+
`${JSON.stringify(computeJsxFingerprint(fingerprintInput, intrinsicElementCount), null, 2)}\n`,
|
|
78
|
+
},
|
|
79
|
+
{ relativePath: ELEMENTS_FILENAME, content: renderGeneratedElements(elements) },
|
|
80
|
+
],
|
|
81
|
+
});
|
|
71
82
|
|
|
72
83
|
return { isRegenerated: true, intrinsicElementCount };
|
|
73
84
|
};
|
|
74
85
|
|
|
86
|
+
const storeExternalPackages = (library: Library): string[] => {
|
|
87
|
+
const packages: Set<string> = new Set();
|
|
88
|
+
|
|
89
|
+
for (const namespace of library.namespaces.values()) {
|
|
90
|
+
const packageName = externalPackageFor(namespace.name);
|
|
91
|
+
|
|
92
|
+
if (packageName !== undefined) {
|
|
93
|
+
packages.add(packageName);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return [...packages];
|
|
98
|
+
};
|
|
99
|
+
|
|
75
100
|
export { runJsxCodegen };
|
package/src/runner.ts
CHANGED
|
@@ -8,6 +8,7 @@ import { runGiCodegen } from "./gi.js";
|
|
|
8
8
|
import { Library } from "./gir/library.js";
|
|
9
9
|
import { generateGlModules, type GlGenerationReport } from "./khronos/pipeline.js";
|
|
10
10
|
import { sweepStagingDirs } from "./staging.js";
|
|
11
|
+
import { externalPackageNotices } from "./store/external-package-links.js";
|
|
11
12
|
import { ensureStoreLink, type StoreOptions } from "./store/store-fs.js";
|
|
12
13
|
|
|
13
14
|
type GlCodegenOptions = {
|
|
@@ -41,6 +42,12 @@ type CodegenRunnerOptions = {
|
|
|
41
42
|
isForced?: boolean;
|
|
42
43
|
/** Emits GIR byte sequences as `Uint8Array` rather than `number[]`; defaults to false. */
|
|
43
44
|
isByteArrayTyped?: boolean;
|
|
45
|
+
/** Surfaces a `GObject.Value` a binding hands back as what it holds rather than as the value; defaults to false. */
|
|
46
|
+
isValueUnwrapped?: boolean;
|
|
47
|
+
/** Drops the leading success boolean from promisified results of a throwing finish; defaults to false. */
|
|
48
|
+
isFinishTrimmed?: boolean;
|
|
49
|
+
/** Mutates a handle-passing inout parameter in place instead of packing it into the result; defaults to false. */
|
|
50
|
+
isInoutInPlace?: boolean;
|
|
44
51
|
};
|
|
45
52
|
|
|
46
53
|
/** What a `runCodegen` run produced. */
|
|
@@ -51,6 +58,8 @@ type CodegenRunnerResult = {
|
|
|
51
58
|
namespaces: number;
|
|
52
59
|
/** How many JSX elements the jsx store binds, zero when no jsx store was requested. */
|
|
53
60
|
intrinsicElements: number;
|
|
61
|
+
/** Deprecation notices about how the store was wired, one line each; empty when nothing needs attention. */
|
|
62
|
+
notices: string[];
|
|
54
63
|
/** Wall-clock duration of the run, in milliseconds. */
|
|
55
64
|
duration: number;
|
|
56
65
|
};
|
|
@@ -83,6 +92,7 @@ const runCodegen = async (options: CodegenRunnerOptions): Promise<CodegenRunnerR
|
|
|
83
92
|
isRegenerated: store.isRegenerated,
|
|
84
93
|
namespaces: store.namespaces,
|
|
85
94
|
intrinsicElements: store.intrinsicElements,
|
|
95
|
+
notices: externalPackageNotices(options.gi),
|
|
86
96
|
duration: Date.now() - start,
|
|
87
97
|
};
|
|
88
98
|
};
|
|
@@ -160,13 +170,17 @@ const emitStoresWithConfig = async (config: {
|
|
|
160
170
|
}): Promise<StoreResult> => {
|
|
161
171
|
const { options, gi, jsx, libraries, girPath } = config;
|
|
162
172
|
const isByteArrayTyped = options.isByteArrayTyped === true;
|
|
173
|
+
const isValueUnwrapped = options.isValueUnwrapped === true;
|
|
174
|
+
const isFinishTrimmed = options.isFinishTrimmed === true;
|
|
175
|
+
const isInoutInPlace = options.isInoutInPlace === true;
|
|
176
|
+
const future = { isByteArrayTyped, isValueUnwrapped, isFinishTrimmed, isInoutInPlace };
|
|
163
177
|
let library: Library | undefined;
|
|
164
|
-
const loadLibrary = (): Library => (library ??= Library.load(libraries, girPath,
|
|
165
|
-
const giInputs = { girFiles: [] as string[], libraries, girPath,
|
|
178
|
+
const loadLibrary = (): Library => (library ??= Library.load(libraries, girPath, future));
|
|
179
|
+
const giInputs = { girFiles: [] as string[], libraries, girPath, storeVersion: gi.version, ...future };
|
|
166
180
|
const isGiRegenerated = options.isForced === true || !isGiStoreFresh(gi.storeDir, giInputs);
|
|
167
181
|
|
|
168
182
|
const namespaces = isGiRegenerated
|
|
169
|
-
? runGiCodegen(loadLibrary(), { gi, libraries, girPath,
|
|
183
|
+
? runGiCodegen(loadLibrary(), { gi, libraries, girPath, ...future })
|
|
170
184
|
: 0;
|
|
171
185
|
|
|
172
186
|
if (jsx === undefined) {
|