@gtkx/codegen 1.2.2 → 1.4.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 +6 -4
- 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 +37 -15
- package/dist/analysis/descriptor-render.js.map +1 -1
- package/dist/analysis/descriptor.d.ts +5 -1
- package/dist/analysis/descriptor.d.ts.map +1 -1
- package/dist/analysis/descriptor.js +12 -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 +111 -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 +33 -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/guards.d.ts +2 -1
- package/dist/guards.d.ts.map +1 -1
- package/dist/guards.js +3 -1
- package/dist/guards.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- 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/generated-libraries.d.ts +26 -0
- package/dist/store/gi/generated-libraries.d.ts.map +1 -0
- package/dist/store/gi/generated-libraries.js +53 -0
- package/dist/store/gi/generated-libraries.js.map +1 -0
- 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 +12 -2
- package/dist/store/gi-store.d.ts.map +1 -1
- package/dist/store/gi-store.js +24 -5
- 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/metadata.d.ts.map +1 -1
- package/dist/store/jsx/metadata.js +35 -60
- package/dist/store/jsx/metadata.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 +3 -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 +7 -6
- package/src/analysis/descriptor-render.ts +60 -16
- package/src/analysis/descriptor.ts +17 -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 +151 -16
- package/src/gi.ts +48 -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/guards.ts +6 -1
- package/src/index.ts +2 -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/generated-libraries.ts +91 -0
- 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 +48 -5
- package/src/store/jsx/jsx.ts +3 -1
- package/src/store/jsx/metadata.ts +46 -99
- package/src/store/jsx-store.ts +23 -7
- package/src/store/resolve-store.ts +3 -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/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/guards.ts
CHANGED
|
@@ -12,6 +12,11 @@ const isString = (value: unknown): value is string => typeof value === "string";
|
|
|
12
12
|
const arrayGuard = <T>(isEntry: Guard<T>): Guard<T[]> =>
|
|
13
13
|
(value: unknown): value is T[] => Array.isArray(value) && value.every((entry: unknown) => isEntry(entry));
|
|
14
14
|
|
|
15
|
+
const recordGuard = <T>(isEntry: Guard<T>): Guard<Record<string, T>> =>
|
|
16
|
+
(value: unknown): value is Record<string, T> =>
|
|
17
|
+
isRecord(value) && !Array.isArray(value) &&
|
|
18
|
+
Object.values(value).every((entry: unknown) => isEntry(entry));
|
|
19
|
+
|
|
15
20
|
const optionalGuard = <T>(isPresent: Guard<T>): OptionalGuard<T> =>
|
|
16
21
|
Object.assign((value: unknown): value is T | undefined => value === undefined || isPresent(value), {
|
|
17
22
|
__optional__: true as const,
|
|
@@ -20,4 +25,4 @@ const optionalGuard = <T>(isPresent: Guard<T>): OptionalGuard<T> =>
|
|
|
20
25
|
const hasFields = <T extends object>(value: unknown, guards: FieldGuards<T>): value is T =>
|
|
21
26
|
isRecord(value) && Object.entries(guards).every(([name, guard]) => (guard as Guard<unknown>)(value[name]));
|
|
22
27
|
|
|
23
|
-
export { arrayGuard, hasFields, isBoolean, isNumber, isString, optionalGuard };
|
|
28
|
+
export { arrayGuard, hasFields, isBoolean, isNumber, isString, optionalGuard, recordGuard };
|
package/src/index.ts
CHANGED
|
@@ -20,6 +20,8 @@ export { type BuiltinElements, type ModuleExport, readBuiltinElements } from "./
|
|
|
20
20
|
/** @public */
|
|
21
21
|
export { type CodegenRunnerOptions, type CodegenRunnerResult, runCodegen } from "./runner.js";
|
|
22
22
|
/** @public */
|
|
23
|
+
export { type GeneratedLibraries, readGeneratedLibraries } from "./store/gi/generated-libraries.js";
|
|
24
|
+
/** @public */
|
|
23
25
|
export type { ElementProps } from "./store/jsx/element-prop-imports.js";
|
|
24
26
|
/** @public */
|
|
25
27
|
export { type GeneratedElement, readGeneratedElements } from "./store/jsx/generated-elements.js";
|
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) {
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import { existsSync, readFileSync, realpathSync, rmSync } from "node:fs";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
import { EXTERNAL_NAMESPACES, type ExternalNamespace } from "../gir/external-namespaces.js";
|
|
5
|
+
import { nodeModulesChain } from "./resolve-store.js";
|
|
6
|
+
import { type StoreLink, symlinkRelative } from "./store-fs.js";
|
|
7
|
+
|
|
8
|
+
type ExternalPackageSource = "store" | "hoisted" | "codegen";
|
|
9
|
+
|
|
10
|
+
type ExternalPackageResolution = {
|
|
11
|
+
packageName: string;
|
|
12
|
+
directory: string;
|
|
13
|
+
dir: string;
|
|
14
|
+
source: ExternalPackageSource;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const DEPENDENCY_FIELDS = ["dependencies", "devDependencies", "peerDependencies", "optionalDependencies"];
|
|
18
|
+
const codegenRequire = createRequire(import.meta.url);
|
|
19
|
+
const codegenPackageDirs: Map<string, string | undefined> = new Map();
|
|
20
|
+
const ensuredStores: Set<string> = new Set();
|
|
21
|
+
|
|
22
|
+
const storeAnchor = (link: StoreLink): string => dirname(dirname(link.linkDir));
|
|
23
|
+
const namespaceShimDirectory = (entry: ExternalNamespace): string => entry.namespace.toLowerCase();
|
|
24
|
+
|
|
25
|
+
const resolveFromStore = (link: StoreLink, packageName: string): string | undefined => {
|
|
26
|
+
const chain = nodeModulesChain(dirname(storeAnchor(link)));
|
|
27
|
+
|
|
28
|
+
for (const nodeModules of chain) {
|
|
29
|
+
const manifest = join(nodeModules, packageName, "package.json");
|
|
30
|
+
|
|
31
|
+
if (existsSync(manifest)) {
|
|
32
|
+
return dirname(realpathSync(manifest));
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return undefined;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const projectManifestPath = (link: StoreLink): string => join(dirname(storeAnchor(link)), "package.json");
|
|
40
|
+
|
|
41
|
+
const readManifest = (manifestPath: string): Record<string, unknown> | undefined => {
|
|
42
|
+
try {
|
|
43
|
+
return JSON.parse(readFileSync(manifestPath, "utf8")) as Record<string, unknown>;
|
|
44
|
+
} catch {
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const sectionNames = (section: unknown): string[] =>
|
|
50
|
+
typeof section === "object" && section !== null ? Object.keys(section) : [];
|
|
51
|
+
|
|
52
|
+
const declaredDependencies = (manifest: Record<string, unknown>): Set<string> =>
|
|
53
|
+
new Set(DEPENDENCY_FIELDS.flatMap((field) => sectionNames(manifest[field])));
|
|
54
|
+
|
|
55
|
+
const isDeclaredByProject = (link: StoreLink, packageName: string): boolean => {
|
|
56
|
+
const manifest = readManifest(projectManifestPath(link));
|
|
57
|
+
|
|
58
|
+
return manifest === undefined || declaredDependencies(manifest).has(packageName);
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const resolveFromCodegen = (packageName: string): string | undefined => {
|
|
62
|
+
if (codegenPackageDirs.has(packageName)) {
|
|
63
|
+
return codegenPackageDirs.get(packageName);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
let dir: string | undefined;
|
|
67
|
+
|
|
68
|
+
try {
|
|
69
|
+
dir = dirname(realpathSync(codegenRequire.resolve(`${packageName}/package.json`)));
|
|
70
|
+
} catch {
|
|
71
|
+
dir = undefined;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
codegenPackageDirs.set(packageName, dir);
|
|
75
|
+
|
|
76
|
+
return dir;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const resolveEntry = (link: StoreLink, entry: ExternalNamespace): ExternalPackageResolution | undefined => {
|
|
80
|
+
const directory = namespaceShimDirectory(entry);
|
|
81
|
+
const chainResolved = resolveFromStore(link, entry.packageName);
|
|
82
|
+
|
|
83
|
+
if (chainResolved !== undefined) {
|
|
84
|
+
const source = isDeclaredByProject(link, entry.packageName) ? "store" : "hoisted";
|
|
85
|
+
|
|
86
|
+
return { packageName: entry.packageName, directory, dir: chainResolved, source };
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const codegenDir = resolveFromCodegen(entry.packageName);
|
|
90
|
+
|
|
91
|
+
if (codegenDir !== undefined) {
|
|
92
|
+
return { packageName: entry.packageName, directory, dir: codegenDir, source: "codegen" };
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return undefined;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
const resolveExternalPackages = (link: StoreLink): ExternalPackageResolution[] => {
|
|
99
|
+
const resolutions: ExternalPackageResolution[] = [];
|
|
100
|
+
|
|
101
|
+
for (const entry of EXTERNAL_NAMESPACES) {
|
|
102
|
+
const resolution = resolveEntry(link, entry);
|
|
103
|
+
|
|
104
|
+
if (resolution !== undefined) {
|
|
105
|
+
resolutions.push(resolution);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return resolutions;
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
const isLinkedTo = (linkPath: string, dir: string): boolean => {
|
|
113
|
+
try {
|
|
114
|
+
return realpathSync(linkPath) === realpathSync(dir);
|
|
115
|
+
} catch {
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
const applyLink = (storeDir: string, resolution: ExternalPackageResolution): void => {
|
|
121
|
+
const linkPath = join(storeDir, "node_modules", resolution.packageName);
|
|
122
|
+
|
|
123
|
+
if (resolution.source === "codegen") {
|
|
124
|
+
if (!isLinkedTo(linkPath, resolution.dir)) {
|
|
125
|
+
symlinkRelative(linkPath, resolution.dir);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
rmSync(linkPath, { recursive: true, force: true });
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
const tryApplyLink = (storeDir: string, resolution: ExternalPackageResolution): void => {
|
|
135
|
+
try {
|
|
136
|
+
applyLink(storeDir, resolution);
|
|
137
|
+
} catch {
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
const ensureExternalPackageLinks = (link: StoreLink): void => {
|
|
143
|
+
if (ensuredStores.has(link.storeDir)) {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (!existsSync(join(link.storeDir, "package.json"))) {
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
for (const resolution of resolveExternalPackages(link)) {
|
|
152
|
+
tryApplyLink(link.storeDir, resolution);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
ensuredStores.add(link.storeDir);
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
const resetExternalPackageLinks = (storeDir: string): void => {
|
|
159
|
+
ensuredStores.delete(storeDir);
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
const externalPackageNotice = (resolution: ExternalPackageResolution): string =>
|
|
163
|
+
`${resolution.packageName} is not installed in this project, so the copy @gtkx/codegen depends on was ` +
|
|
164
|
+
`linked into the generated store; add ${resolution.packageName} to your dependencies, because GTKX 2.0 ` +
|
|
165
|
+
"stops doing this.";
|
|
166
|
+
|
|
167
|
+
const hoistedPackageNotice = (resolution: ExternalPackageResolution): string =>
|
|
168
|
+
`${resolution.packageName} is not declared in this project's package.json and only resolves because ` +
|
|
169
|
+
`your package manager hoisted it; add ${resolution.packageName} to your dependencies, because GTKX 2.0 ` +
|
|
170
|
+
"requires the direct dependency.";
|
|
171
|
+
|
|
172
|
+
const hasShim = (storeDir: string, entry: ExternalNamespace): boolean =>
|
|
173
|
+
existsSync(join(storeDir, namespaceShimDirectory(entry), "index.js"));
|
|
174
|
+
|
|
175
|
+
const hasStoreLocalLink = (storeDir: string, packageName: string): boolean =>
|
|
176
|
+
existsSync(join(storeDir, "node_modules", packageName, "package.json"));
|
|
177
|
+
|
|
178
|
+
const unresolvableMessage = (link: StoreLink, entry: ExternalNamespace): string =>
|
|
179
|
+
`Cannot resolve ${entry.packageName} from ${storeAnchor(link)} or from @gtkx/codegen; ` +
|
|
180
|
+
"install it next to @gtkx/runtime.";
|
|
181
|
+
|
|
182
|
+
const linkFailedMessage = (link: StoreLink, entry: ExternalNamespace): string =>
|
|
183
|
+
`Cannot link ${entry.packageName} into the generated store at ${link.storeDir}; ` +
|
|
184
|
+
`install ${entry.packageName} next to @gtkx/runtime.`;
|
|
185
|
+
|
|
186
|
+
const entryNotice = (link: StoreLink, entry: ExternalNamespace): string | undefined => {
|
|
187
|
+
if (!hasShim(link.storeDir, entry)) {
|
|
188
|
+
return undefined;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const resolution = resolveEntry(link, entry);
|
|
192
|
+
|
|
193
|
+
if (resolution === undefined) {
|
|
194
|
+
throw new Error(unresolvableMessage(link, entry));
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (resolution.source === "store") {
|
|
198
|
+
return undefined;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
if (resolution.source === "hoisted") {
|
|
202
|
+
return hoistedPackageNotice(resolution);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if (!hasStoreLocalLink(link.storeDir, resolution.packageName)) {
|
|
206
|
+
throw new Error(linkFailedMessage(link, entry));
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
return externalPackageNotice(resolution);
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
const externalPackageNotices = (link: StoreLink): string[] => {
|
|
213
|
+
const notices: string[] = [];
|
|
214
|
+
|
|
215
|
+
for (const entry of EXTERNAL_NAMESPACES) {
|
|
216
|
+
const notice = entryNotice(link, entry);
|
|
217
|
+
|
|
218
|
+
if (notice !== undefined) {
|
|
219
|
+
notices.push(notice);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return notices;
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
export { ensureExternalPackageLinks, externalPackageNotices, resetExternalPackageLinks };
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
} from "../../analysis/param-structure.js";
|
|
13
13
|
import { renderJsDoc } from "../../writer/doc.js";
|
|
14
14
|
import { annotationSpec, THROWS_TEXT } from "./doc-spec.js";
|
|
15
|
-
import { isCallbackParameter, returnedOutParameters } from "./method.js";
|
|
15
|
+
import { isCallbackParameter, returnedOutParameters, shouldTrimFinishBoolean } from "./method.js";
|
|
16
16
|
|
|
17
17
|
type CallableDocOptions = {
|
|
18
18
|
finishFn?: GirFunction | undefined;
|
|
@@ -53,9 +53,9 @@ const tupleReturnsText = (primary: string | undefined, outs: InputParameter[]):
|
|
|
53
53
|
return bullets.length === 0 ? undefined : `Tuple of:\n\n${bullets.join("\n")}`;
|
|
54
54
|
};
|
|
55
55
|
|
|
56
|
-
const returnsText = (context: ModuleContext, fn: GirFunction): string | undefined => {
|
|
56
|
+
const returnsText = (context: ModuleContext, fn: GirFunction, isPrimaryTrimmed: boolean): string | undefined => {
|
|
57
57
|
const outs = returnedOutParameters(context, fn);
|
|
58
|
-
const isPrimaryOmitted = shouldOmitPrimaryReturn(context.library, fn.returnValue);
|
|
58
|
+
const isPrimaryOmitted = isPrimaryTrimmed || shouldOmitPrimaryReturn(context.library, fn.returnValue);
|
|
59
59
|
const primary = isPrimaryOmitted ? undefined : fn.returnValue.doc;
|
|
60
60
|
|
|
61
61
|
if (outs.length === 0) {
|
|
@@ -92,7 +92,11 @@ const callableSpec = (context: ModuleContext, callable: GirFunction, options: Ca
|
|
|
92
92
|
(parameter) => options.finishFn !== undefined && isCallbackParameter(context, parameter),
|
|
93
93
|
options.renames,
|
|
94
94
|
),
|
|
95
|
-
returns: returnsText(
|
|
95
|
+
returns: returnsText(
|
|
96
|
+
context,
|
|
97
|
+
options.finishFn ?? callable,
|
|
98
|
+
options.finishFn !== undefined && shouldTrimFinishBoolean(context, options.finishFn),
|
|
99
|
+
),
|
|
96
100
|
throws: canCallableThrow(callable, options.finishFn) ? THROWS_TEXT : undefined,
|
|
97
101
|
});
|
|
98
102
|
|
|
@@ -358,7 +358,7 @@ const renderPromisifiedCallable = (
|
|
|
358
358
|
const body = renderPromisifiedBody(
|
|
359
359
|
context,
|
|
360
360
|
callable,
|
|
361
|
-
finishCallExpression(callable, finishFn, member.ownerName),
|
|
361
|
+
{ fn: finishFn, expression: finishCallExpression(callable, finishFn, member.ownerName) },
|
|
362
362
|
toCamelIdentifier(cIdentifier),
|
|
363
363
|
);
|
|
364
364
|
|
package/src/store/gi/class.ts
CHANGED
|
@@ -247,6 +247,35 @@ const appendClassRegistrations = (context: ModuleContext, klass: GirClass, class
|
|
|
247
247
|
gtypeExpr,
|
|
248
248
|
vfuncs: renderVfuncMetadata(context, klass),
|
|
249
249
|
});
|
|
250
|
+
|
|
251
|
+
appendClassStructRegistration(context, klass, className, gtypeExpr);
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
const appendClassStructRegistration = (
|
|
255
|
+
context: ModuleContext,
|
|
256
|
+
klass: GirClass,
|
|
257
|
+
className: string,
|
|
258
|
+
gtypeExpr: string | undefined,
|
|
259
|
+
): void => {
|
|
260
|
+
const typeStruct = klass.glibTypeStruct;
|
|
261
|
+
|
|
262
|
+
if (gtypeExpr === undefined || typeStruct === undefined) {
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const resolved = context.library.resolveType(context.namespace.name, typeStruct);
|
|
267
|
+
|
|
268
|
+
if (resolved?.kind !== "record" || !isEmittableEntity(resolved.value)) {
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
const structName = sanitizeTypeIdentifier(resolved.value.name);
|
|
273
|
+
context.addRuntimeImport("registerClassStruct");
|
|
274
|
+
|
|
275
|
+
context.module.appendRegistration(`registerClassStruct(${className}, ${structName});`, [
|
|
276
|
+
className,
|
|
277
|
+
structName,
|
|
278
|
+
]);
|
|
250
279
|
};
|
|
251
280
|
|
|
252
281
|
const addAncestorInterfaceKeys = (context: ModuleContext, ancestor: ResolvedAncestor, keys: Set<string>): void => {
|
|
@@ -76,7 +76,7 @@ const renderRootConstructor = (context: ModuleContext): string => {
|
|
|
76
76
|
context.addRuntimeTypeImport("AnyClass");
|
|
77
77
|
context.addRuntimeImport("getClassType");
|
|
78
78
|
context.addRuntimeImport("newObjectWithProperties");
|
|
79
|
-
const body = "newObjectWithProperties(getClassType(this.constructor as AnyClass), props, this);";
|
|
79
|
+
const body = "return newObjectWithProperties(getClassType(this.constructor as AnyClass), props, this);";
|
|
80
80
|
|
|
81
81
|
return renderBlock("constructor(props: object = {})", body);
|
|
82
82
|
};
|
package/src/store/gi/function.ts
CHANGED
|
@@ -48,6 +48,7 @@ const renderFnExpression = (context: ModuleContext, fn: GirFunction): string | u
|
|
|
48
48
|
args: arrayLiteral(params),
|
|
49
49
|
returns: returnPlan.descriptor,
|
|
50
50
|
isReturnSkipped: returnPlan.isSkipped,
|
|
51
|
+
isReturnUnpacked: returnPlan.isUnpacked,
|
|
51
52
|
canThrow: fn.throws,
|
|
52
53
|
});
|
|
53
54
|
};
|
|
@@ -132,7 +133,7 @@ const matchNamespaceFinish = (context: ModuleContext, fn: GirFunction): Namespac
|
|
|
132
133
|
const renderPromisifiedNamespaceFunction = (options: NamespaceFunctionOptions, finish: NamespaceFinish): string => {
|
|
133
134
|
const { context, fn, exportName, bindingName } = options;
|
|
134
135
|
const { signature, returnType } = renderPromisifiedSignature(context, fn, finish.fn);
|
|
135
|
-
const body = renderPromisifiedBody(context, fn, finish.exportName, bindingName);
|
|
136
|
+
const body = renderPromisifiedBody(context, fn, { fn: finish.fn, expression: finish.exportName }, bindingName);
|
|
136
137
|
|
|
137
138
|
return renderBlock(`export function ${exportName}(${signature}): ${returnType}`, body);
|
|
138
139
|
};
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { sortStrings } from "@gtkx/utils";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import type { GirNamespace } from "../../gir/namespace.js";
|
|
4
|
+
import { arrayGuard, hasFields, isString, recordGuard } from "../../guards.js";
|
|
5
|
+
import { readJsonFile } from "../../json.js";
|
|
6
|
+
|
|
7
|
+
/** What a generated `@gtkx/gi` store binds, and the library releases it was generated against. */
|
|
8
|
+
type GeneratedLibraries = {
|
|
9
|
+
/** GIR identifiers the store binds, such as `Gtk-4.0`, expanded from the project's `libraries`. */
|
|
10
|
+
libraries: string[];
|
|
11
|
+
/**
|
|
12
|
+
* `MAJOR.MINOR` release, keyed by GIR identifier. A library whose GIR declares no `MAJOR_VERSION`
|
|
13
|
+
* and `MINOR_VERSION` is absent, so an entry is present only for those that name their release.
|
|
14
|
+
*/
|
|
15
|
+
versions: Record<string, string>;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const LIBRARIES_FILENAME = "libraries.json";
|
|
19
|
+
const MAJOR_CONSTANT = "MAJOR_VERSION";
|
|
20
|
+
const MINOR_CONSTANT = "MINOR_VERSION";
|
|
21
|
+
const DIGITS = /^\d+$/;
|
|
22
|
+
|
|
23
|
+
const constantValue = (namespace: GirNamespace, name: string): string | undefined => {
|
|
24
|
+
const constant = namespace.constants.find((entry) => entry.name === name);
|
|
25
|
+
|
|
26
|
+
return constant !== undefined && DIGITS.test(constant.value) ? constant.value : undefined;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const namespaceVersion = (namespace: GirNamespace): string | undefined => {
|
|
30
|
+
const major = constantValue(namespace, MAJOR_CONSTANT);
|
|
31
|
+
const minor = constantValue(namespace, MINOR_CONSTANT);
|
|
32
|
+
|
|
33
|
+
return major === undefined || minor === undefined ? undefined : `${major}.${minor}`;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const getNamespaceName = (library: string): string => {
|
|
37
|
+
const separator = library.indexOf("-");
|
|
38
|
+
|
|
39
|
+
return separator === -1 ? library : library.slice(0, separator);
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const collectGeneratedLibraries = (
|
|
43
|
+
namespaces: Map<string, GirNamespace>,
|
|
44
|
+
libraries: string[],
|
|
45
|
+
): GeneratedLibraries => {
|
|
46
|
+
const sorted = sortStrings(libraries);
|
|
47
|
+
const versions: Record<string, string> = {};
|
|
48
|
+
|
|
49
|
+
for (const library of sorted) {
|
|
50
|
+
const namespace = namespaces.get(getNamespaceName(library));
|
|
51
|
+
const version = namespace === undefined ? undefined : namespaceVersion(namespace);
|
|
52
|
+
|
|
53
|
+
if (version !== undefined) {
|
|
54
|
+
versions[library] = version;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return { libraries: sorted, versions };
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const renderGeneratedLibraries = (generated: GeneratedLibraries): string =>
|
|
62
|
+
`${JSON.stringify(generated, null, 2)}\n`;
|
|
63
|
+
|
|
64
|
+
const isGeneratedLibraries = (value: unknown): value is GeneratedLibraries =>
|
|
65
|
+
hasFields<GeneratedLibraries>(value, {
|
|
66
|
+
libraries: arrayGuard(isString),
|
|
67
|
+
versions: recordGuard(isString),
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Reads which GIR libraries a generated `@gtkx/gi` store binds and which release of each its GIR declared,
|
|
72
|
+
* out of the inventory codegen writes into the store. Answers "what does this project bind, and how new does
|
|
73
|
+
* the installed library have to be" without parsing a `.gir` file or querying pkg-config.
|
|
74
|
+
*
|
|
75
|
+
* @param giStoreDir The gi store directory, as given by `resolveStore(projectRoot).gi.storeDir`.
|
|
76
|
+
* @returns What the store recorded, or null when it holds no inventory codegen wrote, which covers an absent,
|
|
77
|
+
* unreadable, unparseable and structurally foreign store file alike.
|
|
78
|
+
*/
|
|
79
|
+
const readGeneratedLibraries = (giStoreDir: string): GeneratedLibraries | null => {
|
|
80
|
+
const parsed = readJsonFile(join(giStoreDir, LIBRARIES_FILENAME));
|
|
81
|
+
|
|
82
|
+
return isGeneratedLibraries(parsed) ? parsed : null;
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
export {
|
|
86
|
+
LIBRARIES_FILENAME,
|
|
87
|
+
collectGeneratedLibraries,
|
|
88
|
+
type GeneratedLibraries,
|
|
89
|
+
readGeneratedLibraries,
|
|
90
|
+
renderGeneratedLibraries,
|
|
91
|
+
};
|