@gtkx/codegen 1.4.0 → 1.6.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 +1 -1
- package/dist/analysis/descriptor-render.d.ts +1 -0
- package/dist/analysis/descriptor-render.d.ts.map +1 -1
- package/dist/analysis/descriptor-render.js +56 -28
- package/dist/analysis/descriptor-render.js.map +1 -1
- package/dist/analysis/descriptor.d.ts +3 -1
- package/dist/analysis/descriptor.d.ts.map +1 -1
- package/dist/analysis/descriptor.js +10 -9
- package/dist/analysis/descriptor.js.map +1 -1
- package/dist/compile.d.ts.map +1 -1
- package/dist/compile.js +24 -3
- package/dist/compile.js.map +1 -1
- package/dist/docs/api-reference.d.ts +2 -0
- package/dist/docs/api-reference.d.ts.map +1 -1
- package/dist/docs/api-reference.js +2 -1
- 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 +44 -12
- package/dist/docs/pipeline.js.map +1 -1
- package/dist/fingerprint.d.ts +3 -0
- package/dist/fingerprint.d.ts.map +1 -1
- package/dist/fingerprint.js +4 -0
- package/dist/fingerprint.js.map +1 -1
- package/dist/gi.d.ts +1 -0
- package/dist/gi.d.ts.map +1 -1
- package/dist/gi.js +4 -1
- package/dist/gi.js.map +1 -1
- package/dist/gir/libraries.d.ts +12 -5
- package/dist/gir/libraries.d.ts.map +1 -1
- package/dist/gir/libraries.js +50 -14
- package/dist/gir/libraries.js.map +1 -1
- package/dist/gir/library.d.ts +5 -0
- package/dist/gir/library.d.ts.map +1 -1
- package/dist/gir/library.js +6 -0
- package/dist/gir/library.js.map +1 -1
- package/dist/internal.d.ts +1 -0
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +1 -0
- package/dist/internal.js.map +1 -1
- package/dist/jsx.d.ts +1 -0
- package/dist/jsx.d.ts.map +1 -1
- package/dist/jsx.js +2 -0
- package/dist/jsx.js.map +1 -1
- package/dist/runner.d.ts +2 -0
- package/dist/runner.d.ts.map +1 -1
- package/dist/runner.js +3 -1
- package/dist/runner.js.map +1 -1
- package/dist/store/gi/bootstrap.d.ts +4 -0
- package/dist/store/gi/bootstrap.d.ts.map +1 -0
- package/dist/store/gi/bootstrap.js +48 -0
- package/dist/store/gi/bootstrap.js.map +1 -0
- package/dist/store/gi/class.d.ts.map +1 -1
- package/dist/store/gi/class.js +75 -28
- package/dist/store/gi/class.js.map +1 -1
- package/dist/store/gi/constructor-props.d.ts.map +1 -1
- package/dist/store/gi/constructor-props.js +2 -1
- package/dist/store/gi/constructor-props.js.map +1 -1
- package/dist/store/gi/enum.js +3 -3
- package/dist/store/gi/enum.js.map +1 -1
- package/dist/store/gi/folded.d.ts +14 -0
- package/dist/store/gi/folded.d.ts.map +1 -0
- package/dist/store/gi/folded.js +35 -0
- package/dist/store/gi/folded.js.map +1 -0
- package/dist/store/gi/function.d.ts.map +1 -1
- package/dist/store/gi/function.js +22 -3
- package/dist/store/gi/function.js.map +1 -1
- package/dist/store/gi/gtype-binding.d.ts.map +1 -1
- package/dist/store/gi/gtype-binding.js +11 -1
- package/dist/store/gi/gtype-binding.js.map +1 -1
- package/dist/store/gi/interface.d.ts.map +1 -1
- package/dist/store/gi/interface.js +43 -4
- package/dist/store/gi/interface.js.map +1 -1
- package/dist/store/gi/method.d.ts.map +1 -1
- package/dist/store/gi/method.js +2 -0
- package/dist/store/gi/method.js.map +1 -1
- package/dist/store/gi/pipeline.d.ts +5 -1
- package/dist/store/gi/pipeline.d.ts.map +1 -1
- package/dist/store/gi/pipeline.js +13 -1
- package/dist/store/gi/pipeline.js.map +1 -1
- package/dist/store/gi/property-accessor.js +1 -1
- package/dist/store/gi/property-accessor.js.map +1 -1
- package/dist/store/gi/record-field-accessor.d.ts.map +1 -1
- package/dist/store/gi/record-field-accessor.js +3 -3
- package/dist/store/gi/record-field-accessor.js.map +1 -1
- package/dist/store/gi/record.d.ts.map +1 -1
- package/dist/store/gi/record.js +44 -12
- package/dist/store/gi/record.js.map +1 -1
- package/dist/store/gi/registration.js +2 -2
- package/dist/store/gi/registration.js.map +1 -1
- package/dist/store/gi/return-wrap.js +1 -1
- package/dist/store/gi/return-wrap.js.map +1 -1
- package/dist/store/gi/signal.d.ts.map +1 -1
- package/dist/store/gi/signal.js +7 -3
- 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 +1 -1
- package/dist/store/gi/vtable.js.map +1 -1
- package/dist/store/gi-store.d.ts +1 -0
- package/dist/store/gi-store.d.ts.map +1 -1
- package/dist/store/gi-store.js +16 -7
- package/dist/store/gi-store.js.map +1 -1
- package/dist/store/jsx/element-components.d.ts.map +1 -1
- package/dist/store/jsx/element-components.js +64 -10
- package/dist/store/jsx/element-components.js.map +1 -1
- package/dist/store/jsx/element-prop-types.d.ts +2 -0
- package/dist/store/jsx/element-prop-types.d.ts.map +1 -1
- package/dist/store/jsx/element-prop-types.js +2 -0
- package/dist/store/jsx/element-prop-types.js.map +1 -1
- package/dist/store/jsx/metadata.d.ts.map +1 -1
- package/dist/store/jsx/metadata.js +28 -1
- package/dist/store/jsx/metadata.js.map +1 -1
- package/dist/store/jsx-store.d.ts +1 -0
- package/dist/store/jsx-store.d.ts.map +1 -1
- package/dist/store/jsx-store.js +7 -2
- package/dist/store/jsx-store.js.map +1 -1
- package/dist/store/resolve-store.d.ts.map +1 -1
- package/dist/store/resolve-store.js +2 -0
- 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 +1 -1
- package/dist/store/store-fs.js.map +1 -1
- package/dist/writer/context.d.ts +17 -0
- package/dist/writer/context.d.ts.map +1 -1
- package/dist/writer/context.js +83 -11
- package/dist/writer/context.js.map +1 -1
- package/dist/writer/emit.d.ts +2 -1
- package/dist/writer/emit.d.ts.map +1 -1
- package/dist/writer/emit.js +2 -1
- package/dist/writer/emit.js.map +1 -1
- package/dist/writer/imports.d.ts.map +1 -1
- package/dist/writer/imports.js +6 -1
- package/dist/writer/imports.js.map +1 -1
- package/dist/writer/module.d.ts +1 -0
- package/dist/writer/module.d.ts.map +1 -1
- package/dist/writer/module.js +6 -1
- package/dist/writer/module.js.map +1 -1
- package/overrides/glib/regex.ts.ejs +2 -0
- package/package.json +4 -4
- package/src/analysis/descriptor-render.ts +79 -30
- package/src/analysis/descriptor.ts +19 -11
- package/src/compile.ts +42 -3
- package/src/docs/api-reference.ts +4 -1
- package/src/docs/pipeline.ts +64 -13
- package/src/fingerprint.ts +7 -0
- package/src/gi.ts +6 -1
- package/src/gir/libraries.ts +64 -16
- package/src/gir/library.ts +9 -0
- package/src/internal.ts +1 -0
- package/src/jsx.ts +3 -0
- package/src/runner.ts +5 -1
- package/src/store/gi/bootstrap.ts +64 -0
- package/src/store/gi/class.ts +100 -29
- package/src/store/gi/constructor-props.ts +2 -1
- package/src/store/gi/enum.ts +4 -4
- package/src/store/gi/folded.ts +57 -0
- package/src/store/gi/function.ts +22 -3
- package/src/store/gi/gtype-binding.ts +15 -2
- package/src/store/gi/interface.ts +64 -7
- package/src/store/gi/method.ts +2 -0
- package/src/store/gi/pipeline.ts +21 -2
- package/src/store/gi/property-accessor.ts +1 -1
- package/src/store/gi/record-field-accessor.ts +5 -3
- package/src/store/gi/record.ts +61 -14
- package/src/store/gi/registration.ts +2 -2
- package/src/store/gi/return-wrap.ts +1 -1
- package/src/store/gi/signal.ts +8 -3
- package/src/store/gi/vtable.ts +1 -0
- package/src/store/gi-store.ts +19 -7
- package/src/store/jsx/element-components.ts +107 -10
- package/src/store/jsx/element-prop-types.ts +4 -0
- package/src/store/jsx/metadata.ts +41 -0
- package/src/store/jsx-store.ts +10 -4
- package/src/store/resolve-store.ts +2 -0
- package/src/store/store-fs.ts +3 -2
- package/src/writer/context.ts +109 -16
- package/src/writer/emit.ts +3 -1
- package/src/writer/imports.ts +9 -1
- package/src/writer/module.ts +9 -1
package/src/fingerprint.ts
CHANGED
|
@@ -17,6 +17,7 @@ type GiInputs = {
|
|
|
17
17
|
isValueUnwrapped: boolean;
|
|
18
18
|
isFinishTrimmed: boolean;
|
|
19
19
|
isInoutInPlace: boolean;
|
|
20
|
+
isTreeShaken: boolean;
|
|
20
21
|
};
|
|
21
22
|
|
|
22
23
|
type GiFingerprint = {
|
|
@@ -30,6 +31,7 @@ type ModuleExport = { module: string; export: string };
|
|
|
30
31
|
|
|
31
32
|
type DocsFingerprintInput = {
|
|
32
33
|
basePath: string;
|
|
34
|
+
linkStyle: string;
|
|
33
35
|
props: Record<string, ModuleExport>;
|
|
34
36
|
omittedProps: Record<string, string[]>;
|
|
35
37
|
};
|
|
@@ -46,6 +48,7 @@ type JsxFingerprintInput = {
|
|
|
46
48
|
lazyElements: string[];
|
|
47
49
|
props: Record<string, ModuleExport>;
|
|
48
50
|
omittedProps: Record<string, string[]>;
|
|
51
|
+
isTreeShaken: boolean;
|
|
49
52
|
};
|
|
50
53
|
|
|
51
54
|
type JsxFingerprint = {
|
|
@@ -206,6 +209,8 @@ const hashGi = (inputs: GiInputs): string => {
|
|
|
206
209
|
hash.update("\n");
|
|
207
210
|
hash.update(String(inputs.isInoutInPlace));
|
|
208
211
|
hash.update("\n");
|
|
212
|
+
hash.update(String(inputs.isTreeShaken));
|
|
213
|
+
hash.update("\n");
|
|
209
214
|
hash.update(String(inputs.storeVersion));
|
|
210
215
|
const girFiles = sortOrdinal(inputs.girFiles);
|
|
211
216
|
|
|
@@ -270,6 +275,7 @@ const hashDocs = (giValue: string, input: DocsFingerprintInput): string =>
|
|
|
270
275
|
JSON.stringify([
|
|
271
276
|
giValue,
|
|
272
277
|
input.basePath,
|
|
278
|
+
input.linkStyle,
|
|
273
279
|
serializeModuleExports(input.props),
|
|
274
280
|
serializeOmittedProps(input.omittedProps),
|
|
275
281
|
]),
|
|
@@ -311,6 +317,7 @@ const hashJsx = (input: JsxFingerprintInput): string =>
|
|
|
311
317
|
sortOrdinal(input.lazyElements),
|
|
312
318
|
serializeModuleExports(input.props),
|
|
313
319
|
serializeOmittedProps(input.omittedProps),
|
|
320
|
+
input.isTreeShaken,
|
|
314
321
|
]),
|
|
315
322
|
)
|
|
316
323
|
.digest("hex");
|
package/src/gi.ts
CHANGED
|
@@ -15,6 +15,7 @@ type GiCodegenOptions = {
|
|
|
15
15
|
isValueUnwrapped: boolean;
|
|
16
16
|
isFinishTrimmed: boolean;
|
|
17
17
|
isInoutInPlace: boolean;
|
|
18
|
+
isTreeShaken: boolean;
|
|
18
19
|
};
|
|
19
20
|
|
|
20
21
|
type SplitNamespaces = {
|
|
@@ -39,9 +40,12 @@ const splitNamespaces = (library: Library): SplitNamespaces => {
|
|
|
39
40
|
continue;
|
|
40
41
|
}
|
|
41
42
|
|
|
43
|
+
const generated = generateNamespaceModule(namespace, library);
|
|
44
|
+
|
|
42
45
|
namespaces.push({
|
|
43
46
|
directory: namespaceDirectory(namespace),
|
|
44
|
-
rawSource:
|
|
47
|
+
rawSource: generated.source,
|
|
48
|
+
rawBootstrapSource: generated.bootstrapSource,
|
|
45
49
|
girFile: namespace.girFile,
|
|
46
50
|
});
|
|
47
51
|
}
|
|
@@ -62,6 +66,7 @@ const runGiCodegen = (library: Library, options: GiCodegenOptions): number => {
|
|
|
62
66
|
isValueUnwrapped,
|
|
63
67
|
isFinishTrimmed,
|
|
64
68
|
isInoutInPlace,
|
|
69
|
+
isTreeShaken: options.isTreeShaken,
|
|
65
70
|
});
|
|
66
71
|
|
|
67
72
|
writeGiStore(gi, namespaces, externalNamespaces, {
|
package/src/gir/libraries.ts
CHANGED
|
@@ -17,36 +17,84 @@ type LibrarySelection = "*" | string[] | undefined;
|
|
|
17
17
|
const LIBRARIES_WILDCARD = "*";
|
|
18
18
|
const GIR_LIBRARY_PATTERN = /^[A-Za-z][A-Za-z0-9]*-\d+(?:\.\d+)*$/;
|
|
19
19
|
const DEFAULT_LIBRARIES: string[] = ["Gtk-4.0"];
|
|
20
|
+
const ADWAITA_DEFAULT_LIBRARIES: string[] = ["Gtk-4.0", "Adw-1"];
|
|
20
21
|
const GIR_FILE_SUFFIX = ".gir";
|
|
21
22
|
|
|
22
23
|
/**
|
|
23
|
-
* Expands a `libraries` config value into the GIR identifiers to generate from:
|
|
24
|
-
* nothing is configured, everything installed for `"*"`, and otherwise the given list with
|
|
25
|
-
*
|
|
24
|
+
* Expands a `libraries` config value into the GIR identifiers to generate from: the mandatory set alone
|
|
25
|
+
* when nothing is configured, everything installed for `"*"`, and otherwise the given list with the
|
|
26
|
+
* mandatory set prepended.
|
|
27
|
+
*
|
|
28
|
+
* The mandatory set is `"Gtk-4.0"`, which joins a list that does not already name a Gtk version. Under
|
|
29
|
+
* `isAdwaitaDefault` it is `"Gtk-4.0"` and `"Adw-1"`, and it joins `"*"` as well as an explicit list.
|
|
30
|
+
* Each entry is mandatory by namespace rather than by version, so a list that pins another version of
|
|
31
|
+
* Gtk or Adwaita keeps its pin.
|
|
26
32
|
*
|
|
27
33
|
* @throws If `"*"` matched no `.gir` file anywhere on the GIR path.
|
|
28
34
|
*/
|
|
29
|
-
const resolveLibraries = (libraries: LibrarySelection, girPath: string[]): string[] => {
|
|
35
|
+
const resolveLibraries = (libraries: LibrarySelection, girPath: string[], isAdwaitaDefault = false): string[] => {
|
|
30
36
|
if (libraries === undefined) {
|
|
31
|
-
return [...
|
|
37
|
+
return [...mandatoryLibraries(isAdwaitaDefault)];
|
|
32
38
|
}
|
|
33
39
|
|
|
34
40
|
if (libraries === LIBRARIES_WILDCARD) {
|
|
35
|
-
|
|
41
|
+
return installedLibraries(girPath, isAdwaitaDefault);
|
|
42
|
+
}
|
|
36
43
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
44
|
+
if (isAdwaitaDefault) {
|
|
45
|
+
return withMandatory(ADWAITA_DEFAULT_LIBRARIES, libraries);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return withDefaultGtk(libraries);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const redundantLibraries = (libraries: LibrarySelection, isAdwaitaDefault = false): string[] => {
|
|
52
|
+
if (!isAdwaitaDefault || !Array.isArray(libraries)) {
|
|
53
|
+
return [];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return libraries.filter((entry) => ADWAITA_DEFAULT_LIBRARIES.includes(entry));
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const mandatoryLibraries = (isAdwaitaDefault: boolean): string[] =>
|
|
60
|
+
isAdwaitaDefault ? ADWAITA_DEFAULT_LIBRARIES : DEFAULT_LIBRARIES;
|
|
43
61
|
|
|
44
|
-
|
|
62
|
+
const installedLibraries = (girPath: string[], isAdwaitaDefault: boolean): string[] => {
|
|
63
|
+
const discovered = discoverGirNamespaces(girPath);
|
|
64
|
+
|
|
65
|
+
if (discovered.length === 0) {
|
|
66
|
+
throw new Error(
|
|
67
|
+
`gtkx.config.ts: \`libraries: "*"\` matched no .gir files in [${girPath.join(", ")}]. ` +
|
|
68
|
+
"Install gobject-introspection data packages, or list the libraries explicitly.",
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (isAdwaitaDefault) {
|
|
73
|
+
return withMandatory(ADWAITA_DEFAULT_LIBRARIES, discovered);
|
|
45
74
|
}
|
|
46
75
|
|
|
47
|
-
|
|
76
|
+
return discovered;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const getNamespace = (library: string): string => {
|
|
80
|
+
const separator = library.indexOf("-");
|
|
81
|
+
|
|
82
|
+
return separator === -1 ? library : library.slice(0, separator);
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const withMandatory = (mandatory: string[], selected: string[]): string[] => {
|
|
86
|
+
const named: Set<string> = new Set(selected.map((entry) => getNamespace(entry)));
|
|
87
|
+
const missing = mandatory.filter((library) => !named.has(getNamespace(library)));
|
|
88
|
+
|
|
89
|
+
return [...new Set([...missing, ...selected])];
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
const withDefaultGtk = (libraries: string[]): string[] => {
|
|
93
|
+
if (libraries.some((library) => library.startsWith("Gtk-"))) {
|
|
94
|
+
return [...new Set(libraries)];
|
|
95
|
+
}
|
|
48
96
|
|
|
49
|
-
return [...new Set([...
|
|
97
|
+
return [...new Set([...DEFAULT_LIBRARIES, ...libraries])];
|
|
50
98
|
};
|
|
51
99
|
|
|
52
100
|
const readDirEntries = (dir: string): string[] => {
|
|
@@ -121,4 +169,4 @@ const compareVersions = (a: string, b: string): number => {
|
|
|
121
169
|
return 0;
|
|
122
170
|
};
|
|
123
171
|
|
|
124
|
-
export { resolveLibraries, discoverGirNamespaces, type LibrarySelection };
|
|
172
|
+
export { resolveLibraries, redundantLibraries, discoverGirNamespaces, LIBRARIES_WILDCARD, type LibrarySelection };
|
package/src/gir/library.ts
CHANGED
|
@@ -34,6 +34,8 @@ type FutureBehavior = {
|
|
|
34
34
|
isFinishTrimmed?: boolean;
|
|
35
35
|
/** Whether a handle-passing inout parameter is mutated in place rather than packed into the result. */
|
|
36
36
|
isInoutInPlace?: boolean;
|
|
37
|
+
/** Whether registrations fold into each class so bundlers can drop unused ones. */
|
|
38
|
+
isTreeShaken?: boolean;
|
|
37
39
|
};
|
|
38
40
|
|
|
39
41
|
/** A namespace whose header has been read and whose shell is registered, before its body is parsed. */
|
|
@@ -105,6 +107,7 @@ class Library {
|
|
|
105
107
|
library.isValueUnwrappedValue = future.isValueUnwrapped === true;
|
|
106
108
|
library.isFinishTrimmedValue = future.isFinishTrimmed === true;
|
|
107
109
|
library.isInoutInPlaceValue = future.isInoutInPlace === true;
|
|
110
|
+
library.isTreeShakenValue = future.isTreeShaken === true;
|
|
108
111
|
this.drive(library, libraries, girPath);
|
|
109
112
|
|
|
110
113
|
return library;
|
|
@@ -120,6 +123,7 @@ class Library {
|
|
|
120
123
|
private isValueUnwrappedValue = false;
|
|
121
124
|
private isFinishTrimmedValue = false;
|
|
122
125
|
private isInoutInPlaceValue = false;
|
|
126
|
+
private isTreeShakenValue = false;
|
|
123
127
|
|
|
124
128
|
/** Creates a library with no namespaces loaded; {@link Library.load} builds a populated one. */
|
|
125
129
|
constructor() {
|
|
@@ -369,6 +373,11 @@ class Library {
|
|
|
369
373
|
return this.isInoutInPlaceValue;
|
|
370
374
|
}
|
|
371
375
|
|
|
376
|
+
/** Whether registrations fold into each class so bundlers can drop unused ones. */
|
|
377
|
+
public get isTreeShaken(): boolean {
|
|
378
|
+
return this.isTreeShakenValue;
|
|
379
|
+
}
|
|
380
|
+
|
|
372
381
|
/** Paths of the `.gir` files that were read, in the order they were discovered. */
|
|
373
382
|
public get girFiles(): string[] {
|
|
374
383
|
return this.girFilesValue;
|
package/src/internal.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { writeDocs } from "./docs/pipeline.js";
|
|
2
|
+
export { LIBRARIES_WILDCARD, redundantLibraries } from "./gir/libraries.js";
|
|
2
3
|
export { runGlCodegen } from "./runner.js";
|
|
3
4
|
export { getShadowingStorePaths, sweepProjectStaging } from "./store/resolve-store.js";
|
|
4
5
|
export { ensureStoreLinks } from "./store/store-links.js";
|
package/src/jsx.ts
CHANGED
|
@@ -24,6 +24,7 @@ type RunJsxCodegenOptions = {
|
|
|
24
24
|
userOmittedProps: OmittedProps;
|
|
25
25
|
isGiRegenerated: boolean;
|
|
26
26
|
isForced: boolean;
|
|
27
|
+
isTreeShaken: boolean;
|
|
27
28
|
};
|
|
28
29
|
|
|
29
30
|
type RunJsxCodegenResult = {
|
|
@@ -45,6 +46,7 @@ const runJsxCodegen = async (options: RunJsxCodegenOptions): Promise<RunJsxCodeg
|
|
|
45
46
|
lazyElements,
|
|
46
47
|
props,
|
|
47
48
|
omittedProps,
|
|
49
|
+
isTreeShaken: options.isTreeShaken,
|
|
48
50
|
};
|
|
49
51
|
|
|
50
52
|
if (!options.isForced && !options.isGiRegenerated) {
|
|
@@ -69,6 +71,7 @@ const runJsxCodegen = async (options: RunJsxCodegenOptions): Promise<RunJsxCodeg
|
|
|
69
71
|
options: options.jsx,
|
|
70
72
|
namespaces,
|
|
71
73
|
metadata,
|
|
74
|
+
isTreeShaken: options.isTreeShaken,
|
|
72
75
|
externalPackages: storeExternalPackages(library),
|
|
73
76
|
rawFiles: [
|
|
74
77
|
{
|
package/src/runner.ts
CHANGED
|
@@ -48,6 +48,8 @@ type CodegenRunnerOptions = {
|
|
|
48
48
|
isFinishTrimmed?: boolean;
|
|
49
49
|
/** Mutates a handle-passing inout parameter in place instead of packing it into the result; defaults to false. */
|
|
50
50
|
isInoutInPlace?: boolean;
|
|
51
|
+
/** Folds registrations into each class so bundlers can drop unused ones; defaults to false. */
|
|
52
|
+
isTreeShaken?: boolean;
|
|
51
53
|
};
|
|
52
54
|
|
|
53
55
|
/** What a `runCodegen` run produced. */
|
|
@@ -152,6 +154,7 @@ const emitJsxStore = async (input: {
|
|
|
152
154
|
...jsxUserOptions(options),
|
|
153
155
|
isGiRegenerated,
|
|
154
156
|
isForced: options.isForced === true,
|
|
157
|
+
isTreeShaken: options.isTreeShaken === true,
|
|
155
158
|
});
|
|
156
159
|
|
|
157
160
|
return {
|
|
@@ -173,7 +176,8 @@ const emitStoresWithConfig = async (config: {
|
|
|
173
176
|
const isValueUnwrapped = options.isValueUnwrapped === true;
|
|
174
177
|
const isFinishTrimmed = options.isFinishTrimmed === true;
|
|
175
178
|
const isInoutInPlace = options.isInoutInPlace === true;
|
|
176
|
-
const
|
|
179
|
+
const isTreeShaken = options.isTreeShaken === true;
|
|
180
|
+
const future = { isByteArrayTyped, isValueUnwrapped, isFinishTrimmed, isInoutInPlace, isTreeShaken };
|
|
177
181
|
let library: Library | undefined;
|
|
178
182
|
const loadLibrary = (): Library => (library ??= Library.load(libraries, girPath, future));
|
|
179
183
|
const giInputs = { girFiles: [] as string[], libraries, girPath, storeVersion: gi.version, ...future };
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { sortStrings, sourceStringLiteral } from "@gtkx/utils";
|
|
2
|
+
import type { ModuleContext } from "../../writer/context.js";
|
|
3
|
+
import { namespaceDirectory } from "../../gir/namespace.js";
|
|
4
|
+
|
|
5
|
+
const PATCHING_OVERRIDES: Record<string, string[]> = {
|
|
6
|
+
glib: ["./overrides/regex.js"],
|
|
7
|
+
gobject: ["./overrides/object.js", "./overrides/param-spec-getters.js", "./overrides/value.js"],
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
const CORE_WRAPPERS: Record<string, string[]> = {
|
|
11
|
+
glib: ["Error", "Variant"],
|
|
12
|
+
gobject: ["ParamSpec", "Value"],
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const renderDependencyImports = (context: ModuleContext): string[] => [
|
|
16
|
+
...sortStrings(context.dependencies).map((dependency) => `import "../${dependency}/bootstrap.js";`),
|
|
17
|
+
...sortStrings(context.externalDependencies).map((packageName) => `import ${sourceStringLiteral(packageName)};`),
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
const renderOverrideImports = (directory: string): string[] =>
|
|
21
|
+
(PATCHING_OVERRIDES[directory] ?? []).map((override) => `import ${sourceStringLiteral(override)};`);
|
|
22
|
+
|
|
23
|
+
const renderRuntimeImport = (context: ModuleContext, coreWrappers: string[]): string[] => {
|
|
24
|
+
const runtimeImports = new Set(context.bootstrapRuntimeImports);
|
|
25
|
+
|
|
26
|
+
if (coreWrappers.length > 0) {
|
|
27
|
+
runtimeImports.add("retainWrapperClasses");
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (runtimeImports.size === 0) {
|
|
31
|
+
return [];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return [`import { ${sortStrings(runtimeImports).join(", ")} } from "@gtkx/runtime";`];
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const renderModuleImports = (context: ModuleContext, directory: string, coreWrappers: string[]): string[] => {
|
|
38
|
+
const moduleImports = sortStrings(new Set([...context.bootstrapModuleExports, ...coreWrappers]));
|
|
39
|
+
|
|
40
|
+
return moduleImports.length === 0 ? [] : [`import { ${moduleImports.join(", ")} } from "./${directory}.js";`];
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const renderBootstrapModule = (context: ModuleContext): string => {
|
|
44
|
+
const directory = namespaceDirectory(context.namespace);
|
|
45
|
+
const coreWrappers = CORE_WRAPPERS[directory] ?? [];
|
|
46
|
+
|
|
47
|
+
const retention = coreWrappers.length === 0
|
|
48
|
+
? []
|
|
49
|
+
: [`retainWrapperClasses([${coreWrappers.join(", ")}]);`];
|
|
50
|
+
|
|
51
|
+
const lines = [
|
|
52
|
+
...renderDependencyImports(context),
|
|
53
|
+
...renderOverrideImports(directory),
|
|
54
|
+
...renderRuntimeImport(context, coreWrappers),
|
|
55
|
+
...renderModuleImports(context, directory, coreWrappers),
|
|
56
|
+
"",
|
|
57
|
+
...retention,
|
|
58
|
+
...context.bootstrapCalls,
|
|
59
|
+
];
|
|
60
|
+
|
|
61
|
+
return `${lines.join("\n")}\n`;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export { renderBootstrapModule };
|
package/src/store/gi/class.ts
CHANGED
|
@@ -34,6 +34,7 @@ import {
|
|
|
34
34
|
} from "./callables.js";
|
|
35
35
|
import { renderClassConstructor, renderConstructorPropsInterface } from "./constructor-props.js";
|
|
36
36
|
import { getDoc } from "./doc-spec.js";
|
|
37
|
+
import { declareFoldedClass, localClassName } from "./folded.js";
|
|
37
38
|
import { gtypeMemberDeclaration, renderSourceGtype } from "./gtype-binding.js";
|
|
38
39
|
import { methodExportName } from "./method.js";
|
|
39
40
|
import { renderPropertyDeclarations } from "./properties.js";
|
|
@@ -78,6 +79,14 @@ type AppendInstanceMethodsOptions = {
|
|
|
78
79
|
className: string;
|
|
79
80
|
};
|
|
80
81
|
|
|
82
|
+
type TreeShakenClassOptions = {
|
|
83
|
+
klass: GirClass;
|
|
84
|
+
className: string;
|
|
85
|
+
heritage: string;
|
|
86
|
+
body: string;
|
|
87
|
+
implemented: ImplementedRef[];
|
|
88
|
+
};
|
|
89
|
+
|
|
81
90
|
const generateClass = (context: ModuleContext, klass: GirClass): void => {
|
|
82
91
|
if (!isEmittableEntity(klass)) {
|
|
83
92
|
return;
|
|
@@ -95,18 +104,25 @@ const generateClass = (context: ModuleContext, klass: GirClass): void => {
|
|
|
95
104
|
const parentExpression = resolveParent(context, klass);
|
|
96
105
|
const extendsClause = renderExtendsClause(context, parentExpression, klass, callables);
|
|
97
106
|
const implemented = resolveImplementedRefs(context, klass);
|
|
98
|
-
const
|
|
99
|
-
|
|
107
|
+
const implementsClause = renderImplementsClause(implemented);
|
|
108
|
+
|
|
109
|
+
if (context.isTreeShaken) {
|
|
110
|
+
context.beginRegistrations();
|
|
111
|
+
}
|
|
112
|
+
|
|
100
113
|
const { members, accessors } = renderClassMembers(context, klass, callables, parentExpression !== undefined);
|
|
101
114
|
const body = indentMembers(members);
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
115
|
+
const heritage = `${extendsClause}${implementsClause}`;
|
|
116
|
+
|
|
117
|
+
if (context.isTreeShaken) {
|
|
118
|
+
declareTreeShakenClass(context, { klass, className, heritage, body, implemented });
|
|
119
|
+
} else {
|
|
120
|
+
context.declare({
|
|
121
|
+
name: className,
|
|
122
|
+
code: `${getDoc(klass)}export ${classModifier(klass)}class ${className}${heritage} {\n${body}\n}`,
|
|
123
|
+
owner: klass.name,
|
|
124
|
+
});
|
|
125
|
+
}
|
|
110
126
|
|
|
111
127
|
context.declare({
|
|
112
128
|
name: `${className}ConstructorProps`,
|
|
@@ -114,8 +130,37 @@ const generateClass = (context: ModuleContext, klass: GirClass): void => {
|
|
|
114
130
|
});
|
|
115
131
|
|
|
116
132
|
appendMemberDeclarations({ context, klass, className, accessors, implemented });
|
|
117
|
-
|
|
118
|
-
|
|
133
|
+
|
|
134
|
+
if (!context.isTreeShaken) {
|
|
135
|
+
appendInstallMixins(context, className, implemented);
|
|
136
|
+
appendClassRegistrations(context, klass, className);
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
const classModifier = (klass: GirClass): string => (klass.isAbstract ? "abstract " : "");
|
|
141
|
+
|
|
142
|
+
const renderImplementsClause = (implemented: ImplementedRef[]): string => {
|
|
143
|
+
const typeRefs = implemented.map((ref) => omittedTypeRef(ref.typeRef, ref.conflicts));
|
|
144
|
+
|
|
145
|
+
return typeRefs.length === 0 ? "" : ` implements ${typeRefs.join(", ")}`;
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
const declareTreeShakenClass = (context: ModuleContext, options: TreeShakenClassOptions): void => {
|
|
149
|
+
const { klass, className, heritage, body, implemented } = options;
|
|
150
|
+
const localName = localClassName(className);
|
|
151
|
+
appendInstallMixins(context, localName, implemented);
|
|
152
|
+
appendClassRegistrations(context, klass, localName);
|
|
153
|
+
const registrations = context.takeRegistrations();
|
|
154
|
+
|
|
155
|
+
declareFoldedClass({
|
|
156
|
+
context,
|
|
157
|
+
className,
|
|
158
|
+
doc: getDoc(klass),
|
|
159
|
+
owner: klass.name,
|
|
160
|
+
localDeclaration: `${classModifier(klass)}class ${localName}${heritage} {\n${body}\n}`,
|
|
161
|
+
registrations,
|
|
162
|
+
hasInstanceInterface: true,
|
|
163
|
+
});
|
|
119
164
|
};
|
|
120
165
|
|
|
121
166
|
const appendMemberDeclarations = (options: MemberDeclarationsOptions): void => {
|
|
@@ -224,37 +269,56 @@ const appendInstanceMethods = (options: AppendInstanceMethodsOptions): void => {
|
|
|
224
269
|
}
|
|
225
270
|
};
|
|
226
271
|
|
|
227
|
-
const appendInstallMixins = (context: ModuleContext,
|
|
272
|
+
const appendInstallMixins = (context: ModuleContext, targetName: string, implemented: ImplementedRef[]): void => {
|
|
228
273
|
if (implemented.length === 0) {
|
|
229
274
|
return;
|
|
230
275
|
}
|
|
231
276
|
|
|
232
|
-
context.
|
|
233
|
-
|
|
234
|
-
|
|
277
|
+
if (!context.isTreeShaken) {
|
|
278
|
+
context.addRuntimeImport("installMixins");
|
|
279
|
+
const makerRefs = implemented.map((ref) => ref.makerRef);
|
|
280
|
+
const localRefs = makerRefs.filter((ref) => !ref.includes("."));
|
|
235
281
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
282
|
+
context.module.appendRegistration(`installMixins(${targetName}, [${makerRefs.join(", ")}]);`, [
|
|
283
|
+
targetName,
|
|
284
|
+
...localRefs,
|
|
285
|
+
]);
|
|
286
|
+
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
const registered = implemented.filter((ref) => ref.interfaceKlass.glibGetType !== undefined);
|
|
291
|
+
const unregistered = implemented.filter((ref) => ref.interfaceKlass.glibGetType === undefined);
|
|
292
|
+
|
|
293
|
+
if (registered.length > 0) {
|
|
294
|
+
context.addRuntimeImport("installInterfaces");
|
|
295
|
+
const refs = registered.map((ref) => ref.typeRef);
|
|
296
|
+
context.collectRegistration(`installInterfaces(${targetName}, [${refs.join(", ")}]);`);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
if (unregistered.length > 0) {
|
|
300
|
+
context.addRuntimeImport("installMixins");
|
|
301
|
+
const refs = unregistered.map((ref) => ref.makerRef);
|
|
302
|
+
context.collectRegistration(`installMixins(${targetName}, [${refs.join(", ")}]);`);
|
|
303
|
+
}
|
|
240
304
|
};
|
|
241
305
|
|
|
242
|
-
const appendClassRegistrations = (context: ModuleContext, klass: GirClass,
|
|
306
|
+
const appendClassRegistrations = (context: ModuleContext, klass: GirClass, targetName: string): void => {
|
|
243
307
|
const gtypeExpr = renderSourceGtype(context, klass);
|
|
244
308
|
|
|
245
309
|
appendWrapperClassRegistration(context, {
|
|
246
|
-
className,
|
|
310
|
+
className: targetName,
|
|
247
311
|
gtypeExpr,
|
|
248
312
|
vfuncs: renderVfuncMetadata(context, klass),
|
|
249
313
|
});
|
|
250
314
|
|
|
251
|
-
appendClassStructRegistration(context, klass,
|
|
315
|
+
appendClassStructRegistration(context, klass, targetName, gtypeExpr);
|
|
252
316
|
};
|
|
253
317
|
|
|
254
318
|
const appendClassStructRegistration = (
|
|
255
319
|
context: ModuleContext,
|
|
256
320
|
klass: GirClass,
|
|
257
|
-
|
|
321
|
+
targetName: string,
|
|
258
322
|
gtypeExpr: string | undefined,
|
|
259
323
|
): void => {
|
|
260
324
|
const typeStruct = klass.glibTypeStruct;
|
|
@@ -272,8 +336,8 @@ const appendClassStructRegistration = (
|
|
|
272
336
|
const structName = sanitizeTypeIdentifier(resolved.value.name);
|
|
273
337
|
context.addRuntimeImport("registerClassStruct");
|
|
274
338
|
|
|
275
|
-
context.
|
|
276
|
-
|
|
339
|
+
context.collectRegistration(`registerClassStruct(${targetName}, ${structName});`, [
|
|
340
|
+
targetName,
|
|
277
341
|
structName,
|
|
278
342
|
]);
|
|
279
343
|
};
|
|
@@ -445,9 +509,16 @@ const renderExtendsClause = (
|
|
|
445
509
|
const resolveParent = (context: ModuleContext, klass: GirClass): string | undefined => {
|
|
446
510
|
const parent = getParentRef(klass);
|
|
447
511
|
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
512
|
+
if (parent === undefined) {
|
|
513
|
+
return undefined;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
const qualified = context.qualify(
|
|
517
|
+
parent.namespaceName ?? context.namespace.name,
|
|
518
|
+
sanitizeTypeIdentifier(parent.typeName),
|
|
519
|
+
);
|
|
520
|
+
|
|
521
|
+
return context.isTreeShaken ? context.hoistBaseRef(qualified) : qualified;
|
|
451
522
|
};
|
|
452
523
|
|
|
453
524
|
export { generateClass };
|
|
@@ -96,7 +96,8 @@ const renderTranslatingConstructor = (context: ModuleContext, props: GirProperty
|
|
|
96
96
|
context.addRuntimeImport("t");
|
|
97
97
|
context.addRuntimeImport("registerConstructProperties");
|
|
98
98
|
const bindings = renderConstructBindings(context, props);
|
|
99
|
-
context.
|
|
99
|
+
const target = context.isTreeShaken ? `_${className}` : className;
|
|
100
|
+
context.collectRegistration(`registerConstructProperties(${target}, ${bindings});`, [className]);
|
|
100
101
|
|
|
101
102
|
return renderBlock(`constructor(props: ${className}ConstructorProps = {})`, "super(props);");
|
|
102
103
|
};
|
package/src/store/gi/enum.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type { EnumMember, GirEnum } from "../../gir/enum.js";
|
|
|
3
3
|
import type { ModuleContext } from "../../writer/context.js";
|
|
4
4
|
import { hasAnnotations } from "../../gir/annotations.js";
|
|
5
5
|
import { isEmittableEntity } from "../../gir/emittable.js";
|
|
6
|
-
import { indent } from "../../writer/emit.js";
|
|
6
|
+
import { indent, pure } from "../../writer/emit.js";
|
|
7
7
|
import { getDoc } from "./doc-spec.js";
|
|
8
8
|
|
|
9
9
|
type KeyedMember = EnumMember & { key: string };
|
|
@@ -58,11 +58,11 @@ const appendErrorDomain = (
|
|
|
58
58
|
owner: enumeration.name,
|
|
59
59
|
});
|
|
60
60
|
|
|
61
|
+
const domain = pure(`createErrorDomain(${quarkExpression}, { ${memberEntries.join(", ")} })`);
|
|
62
|
+
|
|
61
63
|
context.declare({
|
|
62
64
|
name,
|
|
63
|
-
code:
|
|
64
|
-
`${doc}export const ${name}: ErrorDomain<${shape}> = ` +
|
|
65
|
-
`createErrorDomain(${quarkExpression}, { ${memberEntries.join(", ")} });`,
|
|
65
|
+
code: `${doc}export const ${name}: ErrorDomain<${shape}> = ${domain};`,
|
|
66
66
|
});
|
|
67
67
|
};
|
|
68
68
|
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { sourceStringLiteral } from "@gtkx/utils";
|
|
2
|
+
import type { ModuleContext } from "../../writer/context.js";
|
|
3
|
+
import { indent } from "../../writer/emit.js";
|
|
4
|
+
|
|
5
|
+
type FoldedClassOptions = {
|
|
6
|
+
context: ModuleContext;
|
|
7
|
+
className: string;
|
|
8
|
+
doc: string;
|
|
9
|
+
owner: string;
|
|
10
|
+
localDeclaration: string;
|
|
11
|
+
registrations: string[];
|
|
12
|
+
hasInstanceInterface: boolean;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const localClassName = (className: string): string => `_${className}`;
|
|
16
|
+
|
|
17
|
+
const renderNameStatement = (className: string): string =>
|
|
18
|
+
`globalThis.Object.defineProperty(${localClassName(className)}, "name", ` +
|
|
19
|
+
`{ value: ${sourceStringLiteral(className)}, configurable: true });`;
|
|
20
|
+
|
|
21
|
+
const declareFoldedClass = (options: FoldedClassOptions): void => {
|
|
22
|
+
const { context, className, doc, owner, localDeclaration, registrations, hasInstanceInterface } = options;
|
|
23
|
+
const localName = localClassName(className);
|
|
24
|
+
context.module.appendDeclaration({ name: localName, code: localDeclaration, isLocal: true });
|
|
25
|
+
|
|
26
|
+
const body = [renderNameStatement(className), ...registrations, `return ${localName};`]
|
|
27
|
+
.map((statement) => indent(statement, 1))
|
|
28
|
+
.join("\n");
|
|
29
|
+
|
|
30
|
+
if (!hasInstanceInterface) {
|
|
31
|
+
context.declare({
|
|
32
|
+
name: className,
|
|
33
|
+
code: `${doc}export const ${className}: typeof ${localName} = /* @__PURE__ */ (() => {\n${body}\n})();`,
|
|
34
|
+
owner,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
context.declare({
|
|
41
|
+
name: className,
|
|
42
|
+
code: `export interface ${className} extends ${localName} {}`,
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
context.addRuntimeTypeImport("WrapperClass");
|
|
46
|
+
const constType = `WrapperClass<typeof ${localName}, ${className}>`;
|
|
47
|
+
|
|
48
|
+
context.declare({
|
|
49
|
+
name: className,
|
|
50
|
+
code:
|
|
51
|
+
`${doc}export const ${className}: ${constType} = ` +
|
|
52
|
+
`/* @__PURE__ */ (() => {\n${body}\n})() as ${constType};`,
|
|
53
|
+
owner,
|
|
54
|
+
});
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export { declareFoldedClass, localClassName };
|