@gtkx/codegen 0.21.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/LICENSE +373 -0
- package/dist/dsl/context.d.ts +104 -0
- package/dist/dsl/context.d.ts.map +1 -0
- package/dist/dsl/context.js +140 -0
- package/dist/dsl/context.js.map +1 -0
- package/dist/dsl/emit.d.ts +28 -0
- package/dist/dsl/emit.d.ts.map +1 -0
- package/dist/dsl/emit.js +41 -0
- package/dist/dsl/emit.js.map +1 -0
- package/dist/dsl/identifier.d.ts +28 -0
- package/dist/dsl/identifier.d.ts.map +1 -0
- package/dist/dsl/identifier.js +45 -0
- package/dist/dsl/identifier.js.map +1 -0
- package/dist/dsl/imports.d.ts +58 -0
- package/dist/dsl/imports.d.ts.map +1 -0
- package/dist/dsl/imports.js +107 -0
- package/dist/dsl/imports.js.map +1 -0
- package/dist/dsl/module.d.ts +53 -0
- package/dist/dsl/module.d.ts.map +1 -0
- package/dist/dsl/module.js +76 -0
- package/dist/dsl/module.js.map +1 -0
- package/dist/ffi/pipeline.d.ts +19 -0
- package/dist/ffi/pipeline.d.ts.map +1 -0
- package/dist/ffi/pipeline.js +107 -0
- package/dist/ffi/pipeline.js.map +1 -0
- package/dist/fingerprint.d.ts +30 -0
- package/dist/fingerprint.d.ts.map +1 -0
- package/dist/fingerprint.js +33 -0
- package/dist/fingerprint.js.map +1 -0
- package/dist/gi-store.d.ts +34 -0
- package/dist/gi-store.d.ts.map +1 -0
- package/dist/gi-store.js +154 -0
- package/dist/gi-store.js.map +1 -0
- package/dist/gir/boxed.d.ts +66 -0
- package/dist/gir/boxed.d.ts.map +1 -0
- package/dist/gir/boxed.js +49 -0
- package/dist/gir/boxed.js.map +1 -0
- package/dist/gir/callback.d.ts +15 -0
- package/dist/gir/callback.d.ts.map +1 -0
- package/dist/gir/callback.js +17 -0
- package/dist/gir/callback.js.map +1 -0
- package/dist/gir/class.d.ts +49 -0
- package/dist/gir/class.d.ts.map +1 -0
- package/dist/gir/class.js +42 -0
- package/dist/gir/class.js.map +1 -0
- package/dist/gir/enum.d.ts +39 -0
- package/dist/gir/enum.d.ts.map +1 -0
- package/dist/gir/enum.js +24 -0
- package/dist/gir/enum.js.map +1 -0
- package/dist/gir/field.d.ts +27 -0
- package/dist/gir/field.d.ts.map +1 -0
- package/dist/gir/field.js +19 -0
- package/dist/gir/field.js.map +1 -0
- package/dist/gir/function.d.ts +47 -0
- package/dist/gir/function.d.ts.map +1 -0
- package/dist/gir/function.js +28 -0
- package/dist/gir/function.js.map +1 -0
- package/dist/gir/namespace.d.ts +65 -0
- package/dist/gir/namespace.d.ts.map +1 -0
- package/dist/gir/namespace.js +60 -0
- package/dist/gir/namespace.js.map +1 -0
- package/dist/gir/parameter.d.ts +82 -0
- package/dist/gir/parameter.d.ts.map +1 -0
- package/dist/gir/parameter.js +66 -0
- package/dist/gir/parameter.js.map +1 -0
- package/dist/gir/parse.d.ts +78 -0
- package/dist/gir/parse.d.ts.map +1 -0
- package/dist/gir/parse.js +155 -0
- package/dist/gir/parse.js.map +1 -0
- package/dist/gir/primitives.d.ts +36 -0
- package/dist/gir/primitives.d.ts.map +1 -0
- package/dist/gir/primitives.js +109 -0
- package/dist/gir/primitives.js.map +1 -0
- package/dist/gir/property.d.ts +29 -0
- package/dist/gir/property.d.ts.map +1 -0
- package/dist/gir/property.js +16 -0
- package/dist/gir/property.js.map +1 -0
- package/dist/gir/qualified-name.d.ts +37 -0
- package/dist/gir/qualified-name.d.ts.map +1 -0
- package/dist/gir/qualified-name.js +39 -0
- package/dist/gir/qualified-name.js.map +1 -0
- package/dist/gir/qualify.d.ts +32 -0
- package/dist/gir/qualify.d.ts.map +1 -0
- package/dist/gir/qualify.js +60 -0
- package/dist/gir/qualify.js.map +1 -0
- package/dist/gir/repository.d.ts +82 -0
- package/dist/gir/repository.d.ts.map +1 -0
- package/dist/gir/repository.js +122 -0
- package/dist/gir/repository.js.map +1 -0
- package/dist/gir/signal.d.ts +22 -0
- package/dist/gir/signal.d.ts.map +1 -0
- package/dist/gir/signal.js +20 -0
- package/dist/gir/signal.js.map +1 -0
- package/dist/gir/size.d.ts +67 -0
- package/dist/gir/size.d.ts.map +1 -0
- package/dist/gir/size.js +87 -0
- package/dist/gir/size.js.map +1 -0
- package/dist/gir/type-ref.d.ts +79 -0
- package/dist/gir/type-ref.d.ts.map +1 -0
- package/dist/gir/type-ref.js +101 -0
- package/dist/gir/type-ref.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/jsx-store.d.ts +22 -0
- package/dist/jsx-store.d.ts.map +1 -0
- package/dist/jsx-store.js +40 -0
- package/dist/jsx-store.js.map +1 -0
- package/dist/react/compounds-meta.d.ts +18 -0
- package/dist/react/compounds-meta.d.ts.map +1 -0
- package/dist/react/compounds-meta.js +93 -0
- package/dist/react/compounds-meta.js.map +1 -0
- package/dist/react/compounds.d.ts +27 -0
- package/dist/react/compounds.d.ts.map +1 -0
- package/dist/react/compounds.js +164 -0
- package/dist/react/compounds.js.map +1 -0
- package/dist/react/internal.d.ts +14 -0
- package/dist/react/internal.d.ts.map +1 -0
- package/dist/react/internal.js +79 -0
- package/dist/react/internal.js.map +1 -0
- package/dist/react/jsx.d.ts +22 -0
- package/dist/react/jsx.d.ts.map +1 -0
- package/dist/react/jsx.js +134 -0
- package/dist/react/jsx.js.map +1 -0
- package/dist/react/pipeline.d.ts +13 -0
- package/dist/react/pipeline.d.ts.map +1 -0
- package/dist/react/pipeline.js +25 -0
- package/dist/react/pipeline.js.map +1 -0
- package/dist/react/props.d.ts +38 -0
- package/dist/react/props.d.ts.map +1 -0
- package/dist/react/props.js +231 -0
- package/dist/react/props.js.map +1 -0
- package/dist/react/slot-props.d.ts +10 -0
- package/dist/react/slot-props.d.ts.map +1 -0
- package/dist/react/slot-props.js +56 -0
- package/dist/react/slot-props.js.map +1 -0
- package/dist/react/widgets.d.ts +83 -0
- package/dist/react/widgets.d.ts.map +1 -0
- package/dist/react/widgets.js +152 -0
- package/dist/react/widgets.js.map +1 -0
- package/dist/runner.d.ts +55 -0
- package/dist/runner.d.ts.map +1 -0
- package/dist/runner.js +60 -0
- package/dist/runner.js.map +1 -0
- package/dist/store-fs.d.ts +109 -0
- package/dist/store-fs.d.ts.map +1 -0
- package/dist/store-fs.js +98 -0
- package/dist/store-fs.js.map +1 -0
- package/dist/transpile.d.ts +32 -0
- package/dist/transpile.d.ts.map +1 -0
- package/dist/transpile.js +63 -0
- package/dist/transpile.js.map +1 -0
- package/dist/typecheck-store.d.ts +41 -0
- package/dist/typecheck-store.d.ts.map +1 -0
- package/dist/typecheck-store.js +102 -0
- package/dist/typecheck-store.js.map +1 -0
- package/dist/writers/alias.d.ts +13 -0
- package/dist/writers/alias.d.ts.map +1 -0
- package/dist/writers/alias.js +17 -0
- package/dist/writers/alias.js.map +1 -0
- package/dist/writers/async.d.ts +22 -0
- package/dist/writers/async.d.ts.map +1 -0
- package/dist/writers/async.js +48 -0
- package/dist/writers/async.js.map +1 -0
- package/dist/writers/boxed-constructor.d.ts +26 -0
- package/dist/writers/boxed-constructor.d.ts.map +1 -0
- package/dist/writers/boxed-constructor.js +85 -0
- package/dist/writers/boxed-constructor.js.map +1 -0
- package/dist/writers/boxed-field-accessor.d.ts +18 -0
- package/dist/writers/boxed-field-accessor.d.ts.map +1 -0
- package/dist/writers/boxed-field-accessor.js +260 -0
- package/dist/writers/boxed-field-accessor.js.map +1 -0
- package/dist/writers/boxed-layout.d.ts +27 -0
- package/dist/writers/boxed-layout.d.ts.map +1 -0
- package/dist/writers/boxed-layout.js +128 -0
- package/dist/writers/boxed-layout.js.map +1 -0
- package/dist/writers/boxed.d.ts +20 -0
- package/dist/writers/boxed.d.ts.map +1 -0
- package/dist/writers/boxed.js +71 -0
- package/dist/writers/boxed.js.map +1 -0
- package/dist/writers/callables.d.ts +124 -0
- package/dist/writers/callables.d.ts.map +1 -0
- package/dist/writers/callables.js +283 -0
- package/dist/writers/callables.js.map +1 -0
- package/dist/writers/callback.d.ts +16 -0
- package/dist/writers/callback.d.ts.map +1 -0
- package/dist/writers/callback.js +38 -0
- package/dist/writers/callback.js.map +1 -0
- package/dist/writers/class-struct-record.d.ts +31 -0
- package/dist/writers/class-struct-record.d.ts.map +1 -0
- package/dist/writers/class-struct-record.js +67 -0
- package/dist/writers/class-struct-record.js.map +1 -0
- package/dist/writers/class-struct.d.ts +22 -0
- package/dist/writers/class-struct.d.ts.map +1 -0
- package/dist/writers/class-struct.js +85 -0
- package/dist/writers/class-struct.js.map +1 -0
- package/dist/writers/class.d.ts +16 -0
- package/dist/writers/class.d.ts.map +1 -0
- package/dist/writers/class.js +307 -0
- package/dist/writers/class.js.map +1 -0
- package/dist/writers/constant.d.ts +15 -0
- package/dist/writers/constant.d.ts.map +1 -0
- package/dist/writers/constant.js +23 -0
- package/dist/writers/constant.js.map +1 -0
- package/dist/writers/constants.d.ts +15 -0
- package/dist/writers/constants.d.ts.map +1 -0
- package/dist/writers/constants.js +23 -0
- package/dist/writers/constants.js.map +1 -0
- package/dist/writers/constructor-props.d.ts +32 -0
- package/dist/writers/constructor-props.d.ts.map +1 -0
- package/dist/writers/constructor-props.js +110 -0
- package/dist/writers/constructor-props.js.map +1 -0
- package/dist/writers/enum.d.ts +21 -0
- package/dist/writers/enum.d.ts.map +1 -0
- package/dist/writers/enum.js +48 -0
- package/dist/writers/enum.js.map +1 -0
- package/dist/writers/function.d.ts +40 -0
- package/dist/writers/function.d.ts.map +1 -0
- package/dist/writers/function.js +127 -0
- package/dist/writers/function.js.map +1 -0
- package/dist/writers/gtype-binding.d.ts +19 -0
- package/dist/writers/gtype-binding.d.ts.map +1 -0
- package/dist/writers/gtype-binding.js +40 -0
- package/dist/writers/gtype-binding.js.map +1 -0
- package/dist/writers/inheritance.d.ts +48 -0
- package/dist/writers/inheritance.d.ts.map +1 -0
- package/dist/writers/inheritance.js +90 -0
- package/dist/writers/inheritance.js.map +1 -0
- package/dist/writers/interface.d.ts +16 -0
- package/dist/writers/interface.d.ts.map +1 -0
- package/dist/writers/interface.js +155 -0
- package/dist/writers/interface.js.map +1 -0
- package/dist/writers/method.d.ts +150 -0
- package/dist/writers/method.d.ts.map +1 -0
- package/dist/writers/method.js +510 -0
- package/dist/writers/method.js.map +1 -0
- package/dist/writers/param-classify.d.ts +93 -0
- package/dist/writers/param-classify.d.ts.map +1 -0
- package/dist/writers/param-classify.js +163 -0
- package/dist/writers/param-classify.js.map +1 -0
- package/dist/writers/property-accessor.d.ts +19 -0
- package/dist/writers/property-accessor.d.ts.map +1 -0
- package/dist/writers/property-accessor.js +117 -0
- package/dist/writers/property-accessor.js.map +1 -0
- package/dist/writers/registration.d.ts +27 -0
- package/dist/writers/registration.d.ts.map +1 -0
- package/dist/writers/registration.js +30 -0
- package/dist/writers/registration.js.map +1 -0
- package/dist/writers/return-wrap.d.ts +39 -0
- package/dist/writers/return-wrap.d.ts.map +1 -0
- package/dist/writers/return-wrap.js +152 -0
- package/dist/writers/return-wrap.js.map +1 -0
- package/dist/writers/runtime-override.d.ts +18 -0
- package/dist/writers/runtime-override.d.ts.map +1 -0
- package/dist/writers/runtime-override.js +44 -0
- package/dist/writers/runtime-override.js.map +1 -0
- package/dist/writers/signal.d.ts +21 -0
- package/dist/writers/signal.d.ts.map +1 -0
- package/dist/writers/signal.js +260 -0
- package/dist/writers/signal.js.map +1 -0
- package/dist/writers/ts-type.d.ts +50 -0
- package/dist/writers/ts-type.d.ts.map +1 -0
- package/dist/writers/ts-type.js +75 -0
- package/dist/writers/ts-type.js.map +1 -0
- package/dist/writers/types-ts.d.ts +27 -0
- package/dist/writers/types-ts.d.ts.map +1 -0
- package/dist/writers/types-ts.js +97 -0
- package/dist/writers/types-ts.js.map +1 -0
- package/dist/writers/value.d.ts +89 -0
- package/dist/writers/value.d.ts.map +1 -0
- package/dist/writers/value.js +402 -0
- package/dist/writers/value.js.map +1 -0
- package/package.json +55 -0
- package/src/dsl/context.ts +146 -0
- package/src/dsl/emit.ts +42 -0
- package/src/dsl/identifier.ts +52 -0
- package/src/dsl/imports.ts +109 -0
- package/src/dsl/module.ts +75 -0
- package/src/ffi/pipeline.ts +113 -0
- package/src/fingerprint.ts +50 -0
- package/src/gi-store.ts +199 -0
- package/src/gir/boxed.ts +94 -0
- package/src/gir/callback.ts +26 -0
- package/src/gir/class.ts +79 -0
- package/src/gir/enum.ts +55 -0
- package/src/gir/field.ts +40 -0
- package/src/gir/function.ts +67 -0
- package/src/gir/namespace.ts +118 -0
- package/src/gir/parameter.ts +120 -0
- package/src/gir/parse.ts +171 -0
- package/src/gir/primitives.ts +137 -0
- package/src/gir/property.ts +39 -0
- package/src/gir/qualified-name.ts +55 -0
- package/src/gir/qualify.ts +64 -0
- package/src/gir/repository.ts +149 -0
- package/src/gir/signal.ts +36 -0
- package/src/gir/size.ts +129 -0
- package/src/gir/type-ref.ts +180 -0
- package/src/index.ts +16 -0
- package/src/jsx-store.ts +53 -0
- package/src/react/compounds-meta.ts +99 -0
- package/src/react/compounds.ts +204 -0
- package/src/react/internal.ts +91 -0
- package/src/react/jsx.ts +155 -0
- package/src/react/pipeline.ts +29 -0
- package/src/react/props.ts +307 -0
- package/src/react/slot-props.ts +57 -0
- package/src/react/widgets.ts +185 -0
- package/src/runner.ts +89 -0
- package/src/store-fs.ts +157 -0
- package/src/transpile.ts +80 -0
- package/src/typecheck-store.ts +136 -0
- package/src/writers/alias.ts +19 -0
- package/src/writers/async.ts +44 -0
- package/src/writers/boxed-constructor.ts +105 -0
- package/src/writers/boxed-field-accessor.ts +306 -0
- package/src/writers/boxed-layout.ts +166 -0
- package/src/writers/boxed.ts +77 -0
- package/src/writers/callables.ts +339 -0
- package/src/writers/callback.ts +40 -0
- package/src/writers/class-struct-record.ts +75 -0
- package/src/writers/class-struct.ts +96 -0
- package/src/writers/class.ts +384 -0
- package/src/writers/constant.ts +29 -0
- package/src/writers/constructor-props.ts +130 -0
- package/src/writers/enum.ts +53 -0
- package/src/writers/function.ts +136 -0
- package/src/writers/gtype-binding.ts +48 -0
- package/src/writers/inheritance.ts +104 -0
- package/src/writers/interface.ts +168 -0
- package/src/writers/method.ts +678 -0
- package/src/writers/param-classify.ts +178 -0
- package/src/writers/property-accessor.ts +139 -0
- package/src/writers/registration.ts +42 -0
- package/src/writers/return-wrap.ts +180 -0
- package/src/writers/runtime-override.ts +59 -0
- package/src/writers/signal.ts +318 -0
- package/src/writers/ts-type.ts +115 -0
- package/src/writers/value.ts +485 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { GirFunction } from "./function.js";
|
|
2
|
+
import type { GirParameter } from "./parameter.js";
|
|
3
|
+
import type { GirTypeRef } from "./type-ref.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Stamps a default namespace onto an unqualified `named` reference and
|
|
7
|
+
* recurses into composite (`array`, `list`, `hashtable`) references.
|
|
8
|
+
*
|
|
9
|
+
* GIR omits the namespace when a reference points to a sibling in the same
|
|
10
|
+
* file. When writers walk a class hierarchy across namespaces, the parent's
|
|
11
|
+
* references must be qualified with the parent's namespace before they can be
|
|
12
|
+
* resolved against the repository.
|
|
13
|
+
*
|
|
14
|
+
* Returns `undefined` for an `undefined` input so callers can pass through
|
|
15
|
+
* void return types unchanged.
|
|
16
|
+
*
|
|
17
|
+
* @param ref - The reference to qualify, or `undefined`
|
|
18
|
+
* @param defaultNamespace - The namespace to stamp on unqualified refs
|
|
19
|
+
*/
|
|
20
|
+
export const qualifyTypeRef = (ref: GirTypeRef | undefined, defaultNamespace: string): GirTypeRef | undefined => {
|
|
21
|
+
if (ref === undefined) return undefined;
|
|
22
|
+
switch (ref.kind) {
|
|
23
|
+
case "named":
|
|
24
|
+
return { ...ref, namespaceName: ref.namespaceName ?? defaultNamespace };
|
|
25
|
+
case "array":
|
|
26
|
+
return { ...ref, element: qualifyTypeRef(ref.element, defaultNamespace) ?? ref.element };
|
|
27
|
+
case "list":
|
|
28
|
+
return { ...ref, element: qualifyTypeRef(ref.element, defaultNamespace) ?? ref.element };
|
|
29
|
+
case "hashtable":
|
|
30
|
+
return {
|
|
31
|
+
...ref,
|
|
32
|
+
key: qualifyTypeRef(ref.key, defaultNamespace) ?? ref.key,
|
|
33
|
+
value: qualifyTypeRef(ref.value, defaultNamespace) ?? ref.value,
|
|
34
|
+
};
|
|
35
|
+
case "primitive":
|
|
36
|
+
case "callback":
|
|
37
|
+
case "varargs":
|
|
38
|
+
return ref;
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const qualifyParameter = (parameter: GirParameter, defaultNamespace: string): GirParameter => ({
|
|
43
|
+
...parameter,
|
|
44
|
+
type: qualifyTypeRef(parameter.type, defaultNamespace),
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Re-roots every type reference of a callable to `defaultNamespace`.
|
|
49
|
+
*
|
|
50
|
+
* Interface methods are flattened onto each implementing class, but their
|
|
51
|
+
* GIR type references are unqualified relative to the interface's own
|
|
52
|
+
* namespace. Stamping the interface namespace onto the instance parameter,
|
|
53
|
+
* each regular parameter, and the return value lets the class writer resolve
|
|
54
|
+
* and import those references as if the method had been authored on the class.
|
|
55
|
+
*
|
|
56
|
+
* @param fn - The callable whose references to qualify
|
|
57
|
+
* @param defaultNamespace - The namespace the callable's references belong to
|
|
58
|
+
*/
|
|
59
|
+
export const qualifyFunction = (fn: GirFunction, defaultNamespace: string): GirFunction => ({
|
|
60
|
+
...fn,
|
|
61
|
+
instance: fn.instance === undefined ? undefined : qualifyParameter(fn.instance, defaultNamespace),
|
|
62
|
+
parameters: fn.parameters.map((parameter) => qualifyParameter(parameter, defaultNamespace)),
|
|
63
|
+
returnValue: { ...fn.returnValue, type: qualifyTypeRef(fn.returnValue.type, defaultNamespace) },
|
|
64
|
+
});
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import type { GirBoxed } from "./boxed.js";
|
|
4
|
+
import type { GirCallback } from "./callback.js";
|
|
5
|
+
import type { GirClass } from "./class.js";
|
|
6
|
+
import type { GirEnum } from "./enum.js";
|
|
7
|
+
import { type GirNamespace, namespaceFromRepository } from "./namespace.js";
|
|
8
|
+
import { parseGirFile } from "./parse.js";
|
|
9
|
+
import type { GirTypeRef } from "./type-ref.js";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Resolved entity that a {@link GirRepository.resolveNamed} call returns.
|
|
13
|
+
*
|
|
14
|
+
* Wraps the matching entity along with the namespace it lives in, so
|
|
15
|
+
* writers can pull the namespace identifier or shared library name without
|
|
16
|
+
* a second lookup.
|
|
17
|
+
*/
|
|
18
|
+
export type ResolvedNamed =
|
|
19
|
+
| { readonly kind: "class"; readonly namespace: GirNamespace; readonly value: GirClass }
|
|
20
|
+
| { readonly kind: "interface"; readonly namespace: GirNamespace; readonly value: GirClass }
|
|
21
|
+
| { readonly kind: "boxed"; readonly namespace: GirNamespace; readonly value: GirBoxed }
|
|
22
|
+
| { readonly kind: "enum"; readonly namespace: GirNamespace; readonly value: GirEnum }
|
|
23
|
+
| { readonly kind: "callback"; readonly namespace: GirNamespace; readonly value: GirCallback }
|
|
24
|
+
| {
|
|
25
|
+
readonly kind: "alias";
|
|
26
|
+
readonly namespace: GirNamespace;
|
|
27
|
+
readonly target: string | undefined;
|
|
28
|
+
readonly targetRef: GirTypeRef | undefined;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* In-memory database of every loaded GIR namespace, indexed by name.
|
|
33
|
+
*
|
|
34
|
+
* Construct via {@link loadGirRepository}; the public API after that is the
|
|
35
|
+
* `namespaces` map and {@link resolveNamed} for cross-namespace lookups.
|
|
36
|
+
*/
|
|
37
|
+
export class GirRepository {
|
|
38
|
+
/** Namespaces keyed by their unqualified name (e.g. `"Gtk"`, `"GLib"`). */
|
|
39
|
+
public readonly namespaces: ReadonlyMap<string, GirNamespace>;
|
|
40
|
+
/** Absolute paths of every `.gir` file loaded, for staleness fingerprinting. */
|
|
41
|
+
public readonly girFiles: readonly string[];
|
|
42
|
+
private readonly entityIndex: Map<string, ResolvedNamed>;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Constructs a repository from the supplied namespace map.
|
|
46
|
+
*
|
|
47
|
+
* Callers should prefer {@link loadGirRepository} which discovers and
|
|
48
|
+
* parses files for you.
|
|
49
|
+
*
|
|
50
|
+
* @param namespaces - Namespaces keyed by unqualified name
|
|
51
|
+
* @param girFiles - Absolute paths of the `.gir` files the namespaces came from
|
|
52
|
+
*/
|
|
53
|
+
constructor(namespaces: ReadonlyMap<string, GirNamespace>, girFiles: readonly string[] = []) {
|
|
54
|
+
this.namespaces = namespaces;
|
|
55
|
+
this.girFiles = girFiles;
|
|
56
|
+
this.entityIndex = new Map();
|
|
57
|
+
for (const namespace of namespaces.values()) {
|
|
58
|
+
indexNamespace(this.entityIndex, namespace);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Looks up a type by `(namespace, name)`. Aliases are followed one step
|
|
64
|
+
* to their target. Returns `undefined` when neither the namespace nor a
|
|
65
|
+
* matching entity exists.
|
|
66
|
+
*
|
|
67
|
+
* @param namespaceName - Namespace to look in (e.g. `"GLib"`)
|
|
68
|
+
* @param typeName - Local type name within the namespace (e.g. `"Variant"`)
|
|
69
|
+
*/
|
|
70
|
+
resolveNamed(namespaceName: string, typeName: string): ResolvedNamed | undefined {
|
|
71
|
+
const key = entityKey(namespaceName, typeName);
|
|
72
|
+
const direct = this.entityIndex.get(key);
|
|
73
|
+
if (direct !== undefined) return direct;
|
|
74
|
+
return undefined;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const entityKey = (namespaceName: string, typeName: string): string => `${namespaceName}.${typeName}`;
|
|
79
|
+
|
|
80
|
+
const indexNamespace = (index: Map<string, ResolvedNamed>, namespace: GirNamespace): void => {
|
|
81
|
+
for (const value of namespace.classes) {
|
|
82
|
+
index.set(entityKey(namespace.name, value.name), { kind: "class", namespace, value });
|
|
83
|
+
}
|
|
84
|
+
for (const value of namespace.interfaces) {
|
|
85
|
+
index.set(entityKey(namespace.name, value.name), { kind: "interface", namespace, value });
|
|
86
|
+
}
|
|
87
|
+
for (const value of namespace.boxeds) {
|
|
88
|
+
index.set(entityKey(namespace.name, value.name), { kind: "boxed", namespace, value });
|
|
89
|
+
}
|
|
90
|
+
for (const value of namespace.enums) {
|
|
91
|
+
index.set(entityKey(namespace.name, value.name), { kind: "enum", namespace, value });
|
|
92
|
+
}
|
|
93
|
+
for (const value of namespace.callbacks) {
|
|
94
|
+
index.set(entityKey(namespace.name, value.name), { kind: "callback", namespace, value });
|
|
95
|
+
}
|
|
96
|
+
for (const alias of namespace.aliases) {
|
|
97
|
+
const target = alias.target?.kind === "named" ? alias.target.typeName : undefined;
|
|
98
|
+
index.set(entityKey(namespace.name, alias.name), {
|
|
99
|
+
kind: "alias",
|
|
100
|
+
namespace,
|
|
101
|
+
target,
|
|
102
|
+
targetRef: alias.target,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Discovers and parses every GIR file needed to satisfy `libraries` and
|
|
109
|
+
* their transitive `<include>` dependencies.
|
|
110
|
+
*
|
|
111
|
+
* @param libraries - Resolved `Name-Version` namespace identifiers
|
|
112
|
+
* @param girPath - Ordered list of directories to search for `.gir` files
|
|
113
|
+
* @returns A populated {@link GirRepository}
|
|
114
|
+
* @throws If any required GIR file cannot be located on `girPath`
|
|
115
|
+
*/
|
|
116
|
+
export const loadGirRepository = (libraries: readonly string[], girPath: readonly string[]): GirRepository => {
|
|
117
|
+
const namespaces = new Map<string, GirNamespace>();
|
|
118
|
+
const girFiles: string[] = [];
|
|
119
|
+
const queue: string[] = [...libraries];
|
|
120
|
+
while (queue.length > 0) {
|
|
121
|
+
const identifier = queue.shift();
|
|
122
|
+
if (identifier === undefined) continue;
|
|
123
|
+
const namespaceName = identifier.split("-")[0] ?? identifier;
|
|
124
|
+
if (namespaces.has(namespaceName)) continue;
|
|
125
|
+
const path = locateGirFile(identifier, girPath);
|
|
126
|
+
girFiles.push(path);
|
|
127
|
+
const root = parseGirFile(path);
|
|
128
|
+
const repository = root.repository;
|
|
129
|
+
if (typeof repository !== "object" || repository === null) {
|
|
130
|
+
throw new Error(`GIR file at ${path} has no <repository> root`);
|
|
131
|
+
}
|
|
132
|
+
const namespace = namespaceFromRepository(repository as Record<string, unknown>);
|
|
133
|
+
namespaces.set(namespace.name, namespace);
|
|
134
|
+
for (const include of namespace.includes) {
|
|
135
|
+
queue.push(`${include.name}-${include.version}`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return new GirRepository(namespaces, girFiles);
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
const locateGirFile = (identifier: string, girPath: readonly string[]): string => {
|
|
142
|
+
const filename = `${identifier}.gir`;
|
|
143
|
+
for (const directory of girPath) {
|
|
144
|
+
const candidate = join(directory, filename);
|
|
145
|
+
if (existsSync(candidate)) return candidate;
|
|
146
|
+
}
|
|
147
|
+
const tried = girPath.map((directory) => join(directory, filename)).join(", ");
|
|
148
|
+
throw new Error(`GIR file ${filename} not found on girPath. Tried: ${tried}`);
|
|
149
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { type GirParameter, type GirReturnValue, parameterFromNode, returnValueFromNode } from "./parameter.js";
|
|
2
|
+
import { attr, attrBool, childOf, childrenOf, type RawNode } from "./parse.js";
|
|
3
|
+
|
|
4
|
+
/** Emission stage (`<glib:signal when="…">`). */
|
|
5
|
+
type SignalWhen = "first" | "last" | "cleanup";
|
|
6
|
+
|
|
7
|
+
/** A GObject `<glib:signal>` declaration. */
|
|
8
|
+
export type GirSignal = {
|
|
9
|
+
/** GIR signal name, kebab-case (e.g. `"activate-link"`). */
|
|
10
|
+
readonly name: string;
|
|
11
|
+
readonly parameters: readonly GirParameter[];
|
|
12
|
+
readonly returnValue: GirReturnValue;
|
|
13
|
+
readonly when: SignalWhen;
|
|
14
|
+
readonly detailed: boolean;
|
|
15
|
+
readonly action: boolean;
|
|
16
|
+
readonly noRecurse: boolean;
|
|
17
|
+
readonly noHooks: boolean;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Builds a {@link GirSignal} from a `<glib:signal>` element.
|
|
22
|
+
*/
|
|
23
|
+
export const signalFromNode = (node: RawNode): GirSignal => {
|
|
24
|
+
const parametersNode = childOf(node, "parameters");
|
|
25
|
+
const parameterNodes = childrenOf(parametersNode, "parameter");
|
|
26
|
+
return {
|
|
27
|
+
name: attr(node, "name") ?? "",
|
|
28
|
+
parameters: parameterNodes.map((parameter) => parameterFromNode(parameter, false)),
|
|
29
|
+
returnValue: returnValueFromNode(childOf(node, "return-value")),
|
|
30
|
+
when: (attr(node, "when") ?? "last") as SignalWhen,
|
|
31
|
+
detailed: attrBool(node, "detailed"),
|
|
32
|
+
action: attrBool(node, "action"),
|
|
33
|
+
noRecurse: attrBool(node, "no-recurse"),
|
|
34
|
+
noHooks: attrBool(node, "no-hooks"),
|
|
35
|
+
};
|
|
36
|
+
};
|
package/src/gir/size.ts
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { PRIMITIVE_SIZE, type PrimitiveCategory } from "./primitives.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Size and alignment of a single field as it appears in a C struct laid out
|
|
5
|
+
* according to the x86-64 ABI.
|
|
6
|
+
*/
|
|
7
|
+
export type FieldLayout = {
|
|
8
|
+
/** Width of the field in bytes. */
|
|
9
|
+
readonly size: number;
|
|
10
|
+
/** Required alignment in bytes; storage offset rounds up to a multiple of this. */
|
|
11
|
+
readonly align: number;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Returns the `{ size, align }` pair for a primitive category.
|
|
16
|
+
*
|
|
17
|
+
* Pointers and pointer-sized integers (the `pointer` and 64-bit categories)
|
|
18
|
+
* report 8/8. Smaller integers and floats report their natural width.
|
|
19
|
+
*
|
|
20
|
+
* @param category - The primitive category
|
|
21
|
+
*/
|
|
22
|
+
export const layoutOfPrimitive = (category: PrimitiveCategory): FieldLayout => {
|
|
23
|
+
const size = PRIMITIVE_SIZE[category];
|
|
24
|
+
return { size, align: size === 0 ? 1 : size };
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const roundUp = (value: number, multiple: number): number => {
|
|
28
|
+
if (multiple <= 1) return value;
|
|
29
|
+
const remainder = value % multiple;
|
|
30
|
+
return remainder === 0 ? value : value + (multiple - remainder);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Layout slot for a single field that may participate in bitfield packing.
|
|
35
|
+
*
|
|
36
|
+
* `byteOffset` is always the offset of the underlying storage word; for
|
|
37
|
+
* non-bitfield fields it is the field's offset directly, and for bitfield
|
|
38
|
+
* members it is the start of the shared storage unit. `bitOffset` and
|
|
39
|
+
* `bitWidth` are populated only for bitfield members.
|
|
40
|
+
*/
|
|
41
|
+
export type FieldSlot = {
|
|
42
|
+
/** Byte offset of the storage word the field occupies. */
|
|
43
|
+
readonly byteOffset: number;
|
|
44
|
+
/** Bit position within the storage word, for bitfield members. */
|
|
45
|
+
readonly bitOffset: number | undefined;
|
|
46
|
+
/** Width in bits, for bitfield members. */
|
|
47
|
+
readonly bitWidth: number | undefined;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Describes a field for the purposes of layout computation.
|
|
52
|
+
*/
|
|
53
|
+
export type FieldLayoutInput = {
|
|
54
|
+
/** Natural byte size and alignment of the field's value type. */
|
|
55
|
+
readonly layout: FieldLayout;
|
|
56
|
+
/** When set, the field is a bitfield member with this many bits. */
|
|
57
|
+
readonly bits: number | undefined;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Computes per-field byte offsets for a record, grouping consecutive
|
|
62
|
+
* bitfield members of compatible storage widths into a shared storage
|
|
63
|
+
* word.
|
|
64
|
+
*
|
|
65
|
+
* Mirrors the GCC/Itanium ABI rules for C bitfield packing in a
|
|
66
|
+
* single-storage-word model: a new storage word is opened when the
|
|
67
|
+
* underlying type's size changes, when the new field is not a bitfield,
|
|
68
|
+
* or when adding the bits would exceed the word's bit count.
|
|
69
|
+
*
|
|
70
|
+
* A union (`isUnion`) overlays every member at byte offset 0; its size is the
|
|
71
|
+
* largest member rounded up to the strongest member alignment.
|
|
72
|
+
*
|
|
73
|
+
* @param fields - Ordered field layouts and bit widths
|
|
74
|
+
* @param isUnion - Whether the fields are union members (overlaid at offset 0)
|
|
75
|
+
* @returns Parallel slot array and the total record size in bytes
|
|
76
|
+
*/
|
|
77
|
+
export const computeFieldSlots = (
|
|
78
|
+
fields: readonly FieldLayoutInput[],
|
|
79
|
+
isUnion = false,
|
|
80
|
+
): { readonly slots: readonly FieldSlot[]; readonly size: number } => {
|
|
81
|
+
if (isUnion) {
|
|
82
|
+
let maxSize = 0;
|
|
83
|
+
let maxAlign = 1;
|
|
84
|
+
const unionSlots = fields.map((field) => {
|
|
85
|
+
maxSize = Math.max(maxSize, field.layout.size);
|
|
86
|
+
maxAlign = Math.max(maxAlign, field.layout.align);
|
|
87
|
+
return { byteOffset: 0, bitOffset: field.bits === undefined ? undefined : 0, bitWidth: field.bits };
|
|
88
|
+
});
|
|
89
|
+
return { slots: unionSlots, size: roundUp(maxSize, maxAlign) };
|
|
90
|
+
}
|
|
91
|
+
const slots: FieldSlot[] = [];
|
|
92
|
+
let cursor = 0;
|
|
93
|
+
let maxAlign = 1;
|
|
94
|
+
let bitfieldWordOffset: number | undefined;
|
|
95
|
+
let bitfieldWordSize = 0;
|
|
96
|
+
let bitfieldUsedBits = 0;
|
|
97
|
+
for (const field of fields) {
|
|
98
|
+
const align = Math.max(1, field.layout.align);
|
|
99
|
+
if (align > maxAlign) maxAlign = align;
|
|
100
|
+
if (field.bits === undefined) {
|
|
101
|
+
bitfieldWordOffset = undefined;
|
|
102
|
+
bitfieldWordSize = 0;
|
|
103
|
+
bitfieldUsedBits = 0;
|
|
104
|
+
cursor = roundUp(cursor, align);
|
|
105
|
+
slots.push({ byteOffset: cursor, bitOffset: undefined, bitWidth: undefined });
|
|
106
|
+
cursor += field.layout.size;
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
const wordSizeBits = field.layout.size * 8;
|
|
110
|
+
const fits =
|
|
111
|
+
bitfieldWordOffset !== undefined &&
|
|
112
|
+
bitfieldWordSize === field.layout.size &&
|
|
113
|
+
bitfieldUsedBits + field.bits <= wordSizeBits;
|
|
114
|
+
if (!fits) {
|
|
115
|
+
cursor = roundUp(cursor, align);
|
|
116
|
+
bitfieldWordOffset = cursor;
|
|
117
|
+
bitfieldWordSize = field.layout.size;
|
|
118
|
+
bitfieldUsedBits = 0;
|
|
119
|
+
cursor += field.layout.size;
|
|
120
|
+
}
|
|
121
|
+
slots.push({
|
|
122
|
+
byteOffset: bitfieldWordOffset ?? 0,
|
|
123
|
+
bitOffset: bitfieldUsedBits,
|
|
124
|
+
bitWidth: field.bits,
|
|
125
|
+
});
|
|
126
|
+
bitfieldUsedBits += field.bits;
|
|
127
|
+
}
|
|
128
|
+
return { slots, size: roundUp(cursor, maxAlign) };
|
|
129
|
+
};
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { attr, attrBool, childOf, childrenOf, type RawNode } from "./parse.js";
|
|
2
|
+
import { type PrimitiveCategory, primitiveCategory } from "./primitives.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Lazily-resolved reference to a GIR type as it appears in a `<type>` or
|
|
6
|
+
* `<array>` slot.
|
|
7
|
+
*
|
|
8
|
+
* The reference captures everything the writers need at emission time
|
|
9
|
+
* without forcing entity resolution to happen at parse time (which would
|
|
10
|
+
* impose a topological-sort order on namespace loading). Resolution into a
|
|
11
|
+
* concrete `GirClass` / `GirBoxed` / `GirEnum` / … is performed on demand
|
|
12
|
+
* by the writers via `GirRepository.resolveNamed`.
|
|
13
|
+
*/
|
|
14
|
+
export type GirTypeRef =
|
|
15
|
+
| PrimitiveTypeRef
|
|
16
|
+
| NamedTypeRef
|
|
17
|
+
| ArrayTypeRef
|
|
18
|
+
| ListTypeRef
|
|
19
|
+
| HashTableTypeRef
|
|
20
|
+
| InlineCallbackTypeRef
|
|
21
|
+
| VarargsTypeRef;
|
|
22
|
+
|
|
23
|
+
/** A GIR scalar primitive: `gint`, `gboolean`, `utf8`, `gpointer`, etc. */
|
|
24
|
+
export type PrimitiveTypeRef = {
|
|
25
|
+
readonly kind: "primitive";
|
|
26
|
+
readonly category: PrimitiveCategory;
|
|
27
|
+
readonly cType: string | undefined;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* A named type that resolves to a class, interface, boxed, enum, alias, or
|
|
32
|
+
* fundamental in some namespace.
|
|
33
|
+
*
|
|
34
|
+
* `namespaceName` is the namespace prefix from the GIR (`"GLib"`, `"Gtk"`,
|
|
35
|
+
* …) or `undefined` for an unqualified reference. The unqualified form
|
|
36
|
+
* implies "look in the namespace the reference appears in".
|
|
37
|
+
*/
|
|
38
|
+
export type NamedTypeRef = {
|
|
39
|
+
readonly kind: "named";
|
|
40
|
+
readonly namespaceName: string | undefined;
|
|
41
|
+
readonly typeName: string;
|
|
42
|
+
readonly cType: string | undefined;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
/** A C array (`<array>`) with optional length, fixed-size, or zero-terminated metadata. */
|
|
46
|
+
export type ArrayTypeRef = {
|
|
47
|
+
readonly kind: "array";
|
|
48
|
+
readonly element: GirTypeRef;
|
|
49
|
+
readonly cType: string | undefined;
|
|
50
|
+
readonly lengthParameterIndex: number | undefined;
|
|
51
|
+
readonly fixedSize: number | undefined;
|
|
52
|
+
readonly zeroTerminated: boolean;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
/** A GLib `GList` / `GSList` / `GPtrArray` / `GArray` / `GByteArray`. */
|
|
56
|
+
export type ListTypeRef = {
|
|
57
|
+
readonly kind: "list";
|
|
58
|
+
readonly flavor: "glist" | "gslist" | "gptrarray" | "garray" | "gbytearray";
|
|
59
|
+
readonly element: GirTypeRef;
|
|
60
|
+
readonly cType: string | undefined;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
/** A GLib `GHashTable` with key and value element types. */
|
|
64
|
+
export type HashTableTypeRef = {
|
|
65
|
+
readonly kind: "hashtable";
|
|
66
|
+
readonly key: GirTypeRef;
|
|
67
|
+
readonly value: GirTypeRef;
|
|
68
|
+
readonly cType: string | undefined;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
/** An inline `<callback>` (used for vtable slots and callback parameters). */
|
|
72
|
+
type InlineCallbackTypeRef = {
|
|
73
|
+
readonly kind: "callback";
|
|
74
|
+
readonly callback: RawNode;
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
/** A `<varargs/>` parameter placeholder; not marshalable. */
|
|
78
|
+
type VarargsTypeRef = { readonly kind: "varargs" };
|
|
79
|
+
|
|
80
|
+
const LIST_KIND_BY_NAME: ReadonlyMap<string, "glist" | "gslist" | "gptrarray" | "garray" | "gbytearray"> = new Map([
|
|
81
|
+
["GLib.List", "glist"],
|
|
82
|
+
["GLib.SList", "gslist"],
|
|
83
|
+
["GLib.PtrArray", "gptrarray"],
|
|
84
|
+
["GLib.Array", "garray"],
|
|
85
|
+
["GLib.ByteArray", "gbytearray"],
|
|
86
|
+
] as const);
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Builds a {@link GirTypeRef} from a parent XML node whose first `<type>`,
|
|
90
|
+
* `<array>`, or `<varargs>` child describes the slot.
|
|
91
|
+
*
|
|
92
|
+
* Pass the parent (`<parameter>`, `<return-value>`, `<field>`, `<property>`,
|
|
93
|
+
* `<constant>`, `<alias>`). The helper extracts the right child and routes
|
|
94
|
+
* to {@link typeRefFromTypeNode}.
|
|
95
|
+
*
|
|
96
|
+
* @param parent - The element whose typed slot we are inspecting
|
|
97
|
+
* @returns The reference, or `undefined` if no type slot exists
|
|
98
|
+
*/
|
|
99
|
+
export const typeRefFromSlot = (parent: RawNode | undefined): GirTypeRef | undefined => {
|
|
100
|
+
if (parent === undefined) return undefined;
|
|
101
|
+
if (childOf(parent, "varargs") !== undefined) return { kind: "varargs" };
|
|
102
|
+
const arrayNode = childOf(parent, "array");
|
|
103
|
+
if (arrayNode !== undefined) return arrayTypeRefFromNode(arrayNode);
|
|
104
|
+
const typeNode = childOf(parent, "type");
|
|
105
|
+
if (typeNode !== undefined) return typeRefFromTypeNode(typeNode);
|
|
106
|
+
const callback = childOf(parent, "callback");
|
|
107
|
+
if (callback !== undefined) return { kind: "callback", callback };
|
|
108
|
+
return undefined;
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Builds a {@link GirTypeRef} from a `<type>` element.
|
|
113
|
+
*
|
|
114
|
+
* Splits a `Namespace.TypeName` form into namespace + type, recognises GLib
|
|
115
|
+
* container types (`GLib.List`, `GLib.HashTable`, …) by name and routes
|
|
116
|
+
* them to the dedicated branches, otherwise produces a primitive or named
|
|
117
|
+
* reference for later resolution.
|
|
118
|
+
*
|
|
119
|
+
* @param typeNode - A `<type>` element
|
|
120
|
+
*/
|
|
121
|
+
const typeRefFromTypeNode = (typeNode: RawNode): GirTypeRef => {
|
|
122
|
+
const name = attr(typeNode, "name") ?? "";
|
|
123
|
+
const cType = attr(typeNode, "c:type");
|
|
124
|
+
|
|
125
|
+
const listFlavor = LIST_KIND_BY_NAME.get(name);
|
|
126
|
+
if (listFlavor !== undefined) {
|
|
127
|
+
const elementNode = childOf(typeNode, "type");
|
|
128
|
+
const element = elementNode === undefined ? pointerFallback() : typeRefFromTypeNode(elementNode);
|
|
129
|
+
return { kind: "list", flavor: listFlavor, element, cType };
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (name === "GLib.HashTable") {
|
|
133
|
+
const elementTypes = childrenOf(typeNode, "type");
|
|
134
|
+
const keyNode = elementTypes[0];
|
|
135
|
+
const valueNode = elementTypes[1];
|
|
136
|
+
return {
|
|
137
|
+
kind: "hashtable",
|
|
138
|
+
key: keyNode === undefined ? pointerFallback() : typeRefFromTypeNode(keyNode),
|
|
139
|
+
value: valueNode === undefined ? pointerFallback() : typeRefFromTypeNode(valueNode),
|
|
140
|
+
cType,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const primitive = primitiveCategory(name);
|
|
145
|
+
if (primitive !== undefined) {
|
|
146
|
+
return { kind: "primitive", category: primitive, cType };
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const [namespaceName, typeName] = splitOptionalNamespace(name);
|
|
150
|
+
return { kind: "named", namespaceName, typeName, cType };
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
const arrayTypeRefFromNode = (arrayNode: RawNode): ArrayTypeRef | ListTypeRef => {
|
|
154
|
+
const elementNode = childOf(arrayNode, "type");
|
|
155
|
+
const element: GirTypeRef = elementNode === undefined ? pointerFallback() : typeRefFromTypeNode(elementNode);
|
|
156
|
+
const cType = attr(arrayNode, "c:type");
|
|
157
|
+
const arrayName = attr(arrayNode, "name");
|
|
158
|
+
const listFlavor = arrayName === undefined ? undefined : LIST_KIND_BY_NAME.get(arrayName);
|
|
159
|
+
if (listFlavor !== undefined) {
|
|
160
|
+
return { kind: "list", flavor: listFlavor, element, cType };
|
|
161
|
+
}
|
|
162
|
+
const lengthAttr = attr(arrayNode, "length");
|
|
163
|
+
const fixedSizeAttr = attr(arrayNode, "fixed-size");
|
|
164
|
+
return {
|
|
165
|
+
kind: "array",
|
|
166
|
+
element,
|
|
167
|
+
cType,
|
|
168
|
+
lengthParameterIndex: lengthAttr === undefined ? undefined : Number.parseInt(lengthAttr, 10),
|
|
169
|
+
fixedSize: fixedSizeAttr === undefined ? undefined : Number.parseInt(fixedSizeAttr, 10),
|
|
170
|
+
zeroTerminated: attrBool(arrayNode, "zero-terminated", false),
|
|
171
|
+
};
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
const pointerFallback = (): PrimitiveTypeRef => ({ kind: "primitive", category: "pointer", cType: undefined });
|
|
175
|
+
|
|
176
|
+
const splitOptionalNamespace = (name: string): [string | undefined, string] => {
|
|
177
|
+
const dot = name.indexOf(".");
|
|
178
|
+
if (dot === -1) return [undefined, name];
|
|
179
|
+
return [name.slice(0, dot), name.slice(dot + 1)];
|
|
180
|
+
};
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public API of `@gtkx/codegen`.
|
|
3
|
+
*
|
|
4
|
+
* The package exposes a single entry point — {@link CodegenRunner} — that
|
|
5
|
+
* orchestrates the GIR-driven code generation for the FFI and React
|
|
6
|
+
* surfaces. Internal modules (`gir/`, `dsl/`, `writers/`, `ffi/`,
|
|
7
|
+
* `react/`) are not part of the supported surface and may change in any
|
|
8
|
+
* release.
|
|
9
|
+
*/
|
|
10
|
+
export {
|
|
11
|
+
CODEGEN_VERSION,
|
|
12
|
+
type CodegenFingerprint,
|
|
13
|
+
computeFingerprint,
|
|
14
|
+
FINGERPRINT_FILENAME,
|
|
15
|
+
} from "./fingerprint.js";
|
|
16
|
+
export { CodegenRunner } from "./runner.js";
|
package/src/jsx-store.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { type StoreOptions, writeStore } from "./store-fs.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Options for assembling the injected `@gtkx/react-jsx` unit.
|
|
5
|
+
*/
|
|
6
|
+
export type JsxStoreOptions = StoreOptions & {
|
|
7
|
+
/** Absolute path to the gi store, for the unit's own `node_modules/@gtkx/gi`. */
|
|
8
|
+
readonly giStoreDir: string;
|
|
9
|
+
/** Real (symlink-resolved) directory of the installed `react` runtime. */
|
|
10
|
+
readonly realReactRuntimeDir: string;
|
|
11
|
+
/** Real (symlink-resolved) directory of the installed `@gtkx/react`. */
|
|
12
|
+
readonly realReactPackageDir: string;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const stem = (relativePath: string): string => relativePath.replace(/\.(tsx|ts)$/, "");
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Assembles the self-contained injected `@gtkx/react-jsx` unit: the generated
|
|
19
|
+
* `jsx`/`internal`/`compounds` modules plus a `package.json` and the unit's own
|
|
20
|
+
* `node_modules` symlinks to `@gtkx/gi` and `react`.
|
|
21
|
+
*
|
|
22
|
+
* @param options - Resolved store/link/dependency paths
|
|
23
|
+
* @param files - React pipeline output keyed by source filename
|
|
24
|
+
*/
|
|
25
|
+
export const writeJsxStore = (options: JsxStoreOptions, files: ReadonlyMap<string, string>): void => {
|
|
26
|
+
writeStore({
|
|
27
|
+
storeDir: options.storeDir,
|
|
28
|
+
linkDir: options.linkDir,
|
|
29
|
+
files: [...files].map(([relativePath, source]) => ({
|
|
30
|
+
stem: stem(relativePath),
|
|
31
|
+
fileName: relativePath,
|
|
32
|
+
source,
|
|
33
|
+
})),
|
|
34
|
+
manifest: {
|
|
35
|
+
name: "@gtkx/react-jsx",
|
|
36
|
+
type: "module",
|
|
37
|
+
version: options.version,
|
|
38
|
+
sideEffects: ["./internal.js"],
|
|
39
|
+
exports: {
|
|
40
|
+
"./package.json": "./package.json",
|
|
41
|
+
".": { types: "./jsx.d.ts", default: "./jsx.js" },
|
|
42
|
+
"./jsx": { types: "./jsx.d.ts", default: "./jsx.js" },
|
|
43
|
+
"./compounds": { types: "./compounds.d.ts", default: "./compounds.js" },
|
|
44
|
+
"./internal": { types: "./internal.d.ts", default: "./internal.js" },
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
symlinks: [
|
|
48
|
+
{ segments: ["node_modules", "@gtkx", "gi"], target: options.giStoreDir },
|
|
49
|
+
{ segments: ["node_modules", "@gtkx", "react"], target: options.realReactPackageDir },
|
|
50
|
+
{ segments: ["node_modules", "react"], target: options.realReactRuntimeDir },
|
|
51
|
+
],
|
|
52
|
+
});
|
|
53
|
+
};
|