@gtkx/codegen 1.0.0 → 1.2.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 +12 -15
- package/dist/analysis/descriptor-render.d.ts.map +1 -1
- package/dist/analysis/descriptor-render.js +59 -38
- package/dist/analysis/descriptor-render.js.map +1 -1
- package/dist/analysis/descriptor.d.ts +25 -10
- package/dist/analysis/descriptor.d.ts.map +1 -1
- package/dist/analysis/descriptor.js +37 -9
- package/dist/analysis/descriptor.js.map +1 -1
- package/dist/analysis/inheritance.d.ts +4 -2
- package/dist/analysis/inheritance.d.ts.map +1 -1
- package/dist/analysis/inheritance.js +80 -38
- package/dist/analysis/inheritance.js.map +1 -1
- package/dist/analysis/interface-conflicts.d.ts +25 -0
- package/dist/analysis/interface-conflicts.d.ts.map +1 -0
- package/dist/analysis/interface-conflicts.js +139 -0
- package/dist/analysis/interface-conflicts.js.map +1 -0
- package/dist/analysis/param-capability.d.ts.map +1 -1
- package/dist/analysis/param-capability.js +3 -4
- package/dist/analysis/param-capability.js.map +1 -1
- package/dist/analysis/param-structure.js +2 -2
- package/dist/analysis/param-structure.js.map +1 -1
- package/dist/analysis/ts-type.d.ts +3 -2
- package/dist/analysis/ts-type.d.ts.map +1 -1
- package/dist/analysis/ts-type.js +26 -26
- package/dist/analysis/ts-type.js.map +1 -1
- package/dist/analysis/type-key.d.ts +5 -0
- package/dist/analysis/type-key.d.ts.map +1 -0
- package/dist/analysis/type-key.js +9 -0
- package/dist/analysis/type-key.js.map +1 -0
- package/dist/analysis/type-shape.d.ts +3 -2
- package/dist/analysis/type-shape.d.ts.map +1 -1
- package/dist/analysis/type-shape.js +2 -1
- package/dist/analysis/type-shape.js.map +1 -1
- package/dist/compile.d.ts +14 -6
- package/dist/compile.d.ts.map +1 -1
- package/dist/compile.js +125 -24
- 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 +11 -10
- package/dist/docs/api-reference.js.map +1 -1
- package/dist/docs/element-page.d.ts.map +1 -1
- package/dist/docs/element-page.js +5 -3
- package/dist/docs/element-page.js.map +1 -1
- package/dist/docs/pipeline.d.ts +1 -0
- package/dist/docs/pipeline.d.ts.map +1 -1
- package/dist/docs/pipeline.js +93 -19
- package/dist/docs/pipeline.js.map +1 -1
- package/dist/docs/render.d.ts +2 -1
- package/dist/docs/render.d.ts.map +1 -1
- package/dist/docs/render.js +5 -4
- package/dist/docs/render.js.map +1 -1
- package/dist/docs/symbol-page.d.ts.map +1 -1
- package/dist/docs/symbol-page.js +10 -9
- package/dist/docs/symbol-page.js.map +1 -1
- package/dist/fingerprint.d.ts +20 -3
- package/dist/fingerprint.d.ts.map +1 -1
- package/dist/fingerprint.js +56 -37
- 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 +8 -2
- package/dist/gi.js.map +1 -1
- package/dist/gir/ancestry.d.ts +7 -1
- package/dist/gir/ancestry.d.ts.map +1 -1
- package/dist/gir/ancestry.js +9 -1
- package/dist/gir/ancestry.js.map +1 -1
- package/dist/gir/annotations.d.ts +1 -2
- package/dist/gir/annotations.d.ts.map +1 -1
- package/dist/gir/annotations.js +1 -1
- package/dist/gir/annotations.js.map +1 -1
- package/dist/gir/cursor-overrides.d.ts +8 -0
- package/dist/gir/cursor-overrides.d.ts.map +1 -0
- package/dist/gir/cursor-overrides.js +6 -0
- package/dist/gir/cursor-overrides.js.map +1 -0
- package/dist/gir/emittable.d.ts +7 -0
- package/dist/gir/emittable.d.ts.map +1 -0
- package/dist/gir/emittable.js +3 -0
- package/dist/gir/emittable.js.map +1 -0
- package/dist/gir/function.d.ts.map +1 -1
- package/dist/gir/function.js +28 -2
- package/dist/gir/function.js.map +1 -1
- package/dist/gir/gir-path.d.ts +1 -1
- package/dist/gir/gir-path.js +1 -1
- package/dist/gir/gir-path.js.map +1 -1
- package/dist/gir/library.d.ts +5 -1
- package/dist/gir/library.d.ts.map +1 -1
- package/dist/gir/library.js +9 -2
- package/dist/gir/library.js.map +1 -1
- package/dist/gir/namespace.d.ts +5 -1
- package/dist/gir/namespace.d.ts.map +1 -1
- package/dist/gir/namespace.js +4 -2
- package/dist/gir/namespace.js.map +1 -1
- package/dist/gir/parameter.d.ts +13 -1
- package/dist/gir/parameter.d.ts.map +1 -1
- package/dist/gir/parameter.js +1 -0
- package/dist/gir/parameter.js.map +1 -1
- package/dist/gir/parse.d.ts.map +1 -1
- package/dist/gir/parse.js +6 -6
- package/dist/gir/parse.js.map +1 -1
- package/dist/gir/primitives.js +1 -1
- package/dist/gir/primitives.js.map +1 -1
- package/dist/guards.d.ts +16 -0
- package/dist/guards.d.ts.map +1 -0
- package/dist/guards.js +11 -0
- package/dist/guards.js.map +1 -0
- package/dist/internal.d.ts +2 -0
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +2 -0
- package/dist/internal.js.map +1 -1
- package/dist/json.d.ts +3 -0
- package/dist/json.d.ts.map +1 -0
- package/dist/json.js +11 -0
- package/dist/json.js.map +1 -0
- package/dist/khronos/args.d.ts.map +1 -1
- package/dist/khronos/args.js +8 -6
- package/dist/khronos/args.js.map +1 -1
- package/dist/khronos/modules.d.ts.map +1 -1
- package/dist/khronos/modules.js +22 -7
- package/dist/khronos/modules.js.map +1 -1
- package/dist/khronos/parse.d.ts.map +1 -1
- package/dist/khronos/parse.js +3 -4
- package/dist/khronos/parse.js.map +1 -1
- package/dist/khronos/pipeline.d.ts +1 -1
- package/dist/khronos/pipeline.d.ts.map +1 -1
- package/dist/khronos/pipeline.js.map +1 -1
- package/dist/khronos/plan.d.ts +1 -7
- package/dist/khronos/plan.d.ts.map +1 -1
- package/dist/khronos/plan.js +1 -1
- package/dist/khronos/plan.js.map +1 -1
- package/dist/khronos/render.d.ts.map +1 -1
- package/dist/khronos/render.js +8 -4
- package/dist/khronos/render.js.map +1 -1
- package/dist/runner.d.ts +7 -1
- package/dist/runner.d.ts.map +1 -1
- package/dist/runner.js +21 -3
- package/dist/runner.js.map +1 -1
- package/dist/staging.d.ts +5 -0
- package/dist/staging.d.ts.map +1 -0
- package/dist/staging.js +57 -0
- package/dist/staging.js.map +1 -0
- package/dist/store/compile-store.d.ts +0 -1
- package/dist/store/compile-store.d.ts.map +1 -1
- package/dist/store/compile-store.js +7 -32
- package/dist/store/compile-store.js.map +1 -1
- package/dist/store/gi/callables.d.ts +6 -3
- package/dist/store/gi/callables.d.ts.map +1 -1
- package/dist/store/gi/callables.js +40 -30
- package/dist/store/gi/callables.js.map +1 -1
- package/dist/store/gi/callback.d.ts.map +1 -1
- package/dist/store/gi/callback.js +9 -5
- package/dist/store/gi/callback.js.map +1 -1
- package/dist/store/gi/class.d.ts.map +1 -1
- package/dist/store/gi/class.js +104 -44
- package/dist/store/gi/class.js.map +1 -1
- package/dist/store/gi/companion.d.ts.map +1 -1
- package/dist/store/gi/companion.js +6 -6
- package/dist/store/gi/companion.js.map +1 -1
- package/dist/store/gi/constant.d.ts.map +1 -1
- package/dist/store/gi/constant.js +11 -3
- package/dist/store/gi/constant.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/enum.d.ts.map +1 -1
- package/dist/store/gi/enum.js +29 -12
- package/dist/store/gi/enum.js.map +1 -1
- package/dist/store/gi/function.d.ts +1 -3
- package/dist/store/gi/function.d.ts.map +1 -1
- package/dist/store/gi/function.js +24 -18
- 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 +4 -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 +34 -19
- package/dist/store/gi/interface.js.map +1 -1
- package/dist/store/gi/method.d.ts +7 -6
- package/dist/store/gi/method.d.ts.map +1 -1
- package/dist/store/gi/method.js +13 -24
- package/dist/store/gi/method.js.map +1 -1
- package/dist/store/gi/param-marshal.d.ts +3 -2
- package/dist/store/gi/param-marshal.d.ts.map +1 -1
- package/dist/store/gi/param-marshal.js +50 -5
- package/dist/store/gi/param-marshal.js.map +1 -1
- package/dist/store/gi/pipeline.d.ts.map +1 -1
- package/dist/store/gi/pipeline.js +21 -10
- package/dist/store/gi/pipeline.js.map +1 -1
- package/dist/store/gi/properties.d.ts +2 -1
- package/dist/store/gi/properties.d.ts.map +1 -1
- package/dist/store/gi/properties.js +6 -3
- package/dist/store/gi/properties.js.map +1 -1
- package/dist/store/gi/property-accessor.d.ts +10 -8
- package/dist/store/gi/property-accessor.d.ts.map +1 -1
- package/dist/store/gi/property-accessor.js +49 -91
- package/dist/store/gi/property-accessor.js.map +1 -1
- package/dist/store/gi/record-constructor.d.ts +8 -1
- package/dist/store/gi/record-constructor.d.ts.map +1 -1
- package/dist/store/gi/record-constructor.js +34 -13
- package/dist/store/gi/record-constructor.js.map +1 -1
- package/dist/store/gi/record-field-accessor.d.ts.map +1 -1
- package/dist/store/gi/record-field-accessor.js +20 -4
- package/dist/store/gi/record-field-accessor.js.map +1 -1
- package/dist/store/gi/record-layout.d.ts +6 -1
- package/dist/store/gi/record-layout.d.ts.map +1 -1
- package/dist/store/gi/record-layout.js +8 -1
- package/dist/store/gi/record-layout.js.map +1 -1
- package/dist/store/gi/record.d.ts.map +1 -1
- package/dist/store/gi/record.js +19 -8
- 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 +2 -1
- package/dist/store/gi/signal.d.ts.map +1 -1
- package/dist/store/gi/signal.js +55 -28
- package/dist/store/gi/signal.js.map +1 -1
- package/dist/store/gi/value-marshalable.d.ts.map +1 -1
- package/dist/store/gi/value-marshalable.js +2 -1
- package/dist/store/gi/value-marshalable.js.map +1 -1
- package/dist/store/gi/vtable.d.ts +4 -1
- package/dist/store/gi/vtable.d.ts.map +1 -1
- package/dist/store/gi/vtable.js +60 -17
- 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 +15 -20
- package/dist/store/gi-store.js.map +1 -1
- package/dist/store/jsx/generated-elements.d.ts +2 -1
- package/dist/store/jsx/generated-elements.d.ts.map +1 -1
- package/dist/store/jsx/generated-elements.js +13 -7
- package/dist/store/jsx/generated-elements.js.map +1 -1
- package/dist/store/jsx/jsx.js +3 -3
- 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 +3 -1
- package/dist/store/jsx/metadata.js.map +1 -1
- package/dist/store/jsx-store.d.ts.map +1 -1
- package/dist/store/jsx-store.js +3 -4
- package/dist/store/jsx-store.js.map +1 -1
- package/dist/store/resolve-store.d.ts +14 -3
- package/dist/store/resolve-store.d.ts.map +1 -1
- package/dist/store/resolve-store.js +98 -15
- package/dist/store/resolve-store.js.map +1 -1
- package/dist/store/store-fs.d.ts +9 -7
- package/dist/store/store-fs.d.ts.map +1 -1
- package/dist/store/store-fs.js +54 -25
- package/dist/store/store-fs.js.map +1 -1
- package/dist/store/store-links.d.ts +3 -0
- package/dist/store/store-links.d.ts.map +1 -0
- package/dist/store/store-links.js +39 -0
- package/dist/store/store-links.js.map +1 -0
- package/dist/writer/comparison-context.d.ts +4 -0
- package/dist/writer/comparison-context.d.ts.map +1 -0
- package/dist/writer/comparison-context.js +13 -0
- package/dist/writer/comparison-context.js.map +1 -0
- package/dist/writer/context.d.ts +3 -3
- package/dist/writer/context.d.ts.map +1 -1
- package/dist/writer/context.js +11 -6
- package/dist/writer/context.js.map +1 -1
- package/dist/writer/module.d.ts +13 -5
- package/dist/writer/module.d.ts.map +1 -1
- package/dist/writer/module.js +68 -11
- package/dist/writer/module.js.map +1 -1
- package/dist/xml.d.ts +8 -1
- package/dist/xml.d.ts.map +1 -1
- package/dist/xml.js +70 -1
- package/dist/xml.js.map +1 -1
- package/overrides/gobject/object.ts.ejs +2 -0
- package/package.json +14 -3
- package/src/analysis/descriptor-render.ts +106 -52
- package/src/analysis/descriptor.ts +76 -15
- package/src/analysis/inheritance.ts +134 -44
- package/src/analysis/interface-conflicts.ts +235 -0
- package/src/analysis/param-capability.ts +3 -6
- package/src/analysis/param-structure.ts +2 -2
- package/src/analysis/ts-type.ts +43 -28
- package/src/analysis/type-key.ts +14 -0
- package/src/analysis/type-shape.ts +5 -2
- package/src/compile.ts +192 -27
- package/src/docs/api-reference.ts +13 -10
- package/src/docs/element-page.ts +5 -2
- package/src/docs/pipeline.ts +140 -24
- package/src/docs/render.ts +7 -3
- package/src/docs/symbol-page.ts +12 -11
- package/src/fingerprint.ts +95 -47
- package/src/gi.ts +10 -2
- package/src/gir/ancestry.ts +17 -1
- package/src/gir/annotations.ts +1 -1
- package/src/gir/cursor-overrides.ts +12 -0
- package/src/gir/emittable.ts +8 -0
- package/src/gir/function.ts +45 -9
- package/src/gir/gir-path.ts +1 -1
- package/src/gir/library.ts +10 -2
- package/src/gir/namespace.ts +8 -2
- package/src/gir/parameter.ts +15 -0
- package/src/gir/parse.ts +10 -7
- package/src/gir/primitives.ts +1 -1
- package/src/guards.ts +23 -0
- package/src/internal.ts +2 -0
- package/src/json.ts +11 -0
- package/src/khronos/args.ts +9 -6
- package/src/khronos/modules.ts +25 -9
- package/src/khronos/parse.ts +3 -4
- package/src/khronos/pipeline.ts +1 -1
- package/src/khronos/plan.ts +0 -1
- package/src/khronos/render.ts +8 -6
- package/src/runner.ts +26 -4
- package/src/staging.ts +67 -0
- package/src/store/compile-store.ts +7 -38
- package/src/store/gi/callables.ts +60 -33
- package/src/store/gi/callback.ts +9 -9
- package/src/store/gi/class.ts +140 -53
- package/src/store/gi/companion.ts +7 -6
- package/src/store/gi/constant.ts +13 -3
- package/src/store/gi/constructor-props.ts +1 -1
- package/src/store/gi/enum.ts +36 -26
- package/src/store/gi/function.ts +30 -24
- package/src/store/gi/gtype-binding.ts +7 -2
- package/src/store/gi/interface.ts +39 -20
- package/src/store/gi/method.ts +26 -32
- package/src/store/gi/param-marshal.ts +77 -6
- package/src/store/gi/pipeline.ts +25 -15
- package/src/store/gi/properties.ts +8 -4
- package/src/store/gi/property-accessor.ts +73 -161
- package/src/store/gi/record-constructor.ts +53 -21
- package/src/store/gi/record-field-accessor.ts +26 -4
- package/src/store/gi/record-layout.ts +11 -1
- package/src/store/gi/record.ts +20 -12
- package/src/store/gi/registration.ts +2 -2
- package/src/store/gi/return-wrap.ts +1 -1
- package/src/store/gi/signal.ts +66 -42
- package/src/store/gi/value-marshalable.ts +3 -1
- package/src/store/gi/vtable.ts +97 -20
- package/src/store/gi-store.ts +26 -31
- package/src/store/jsx/generated-elements.ts +17 -8
- package/src/store/jsx/jsx.ts +3 -3
- package/src/store/jsx/metadata.ts +4 -1
- package/src/store/jsx-store.ts +3 -4
- package/src/store/resolve-store.ts +133 -18
- package/src/store/store-fs.ts +82 -35
- package/src/store/store-links.ts +49 -0
- package/src/writer/comparison-context.ts +18 -0
- package/src/writer/context.ts +12 -6
- package/src/writer/module.ts +101 -14
- package/src/xml.ts +103 -1
package/src/gir/function.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { GirAnnotations } from "./annotations.js";
|
|
2
2
|
import type { ParseContext } from "./type-id.js";
|
|
3
|
+
import { type CursorParameterNames, PARAMETERS_MISSING_ARRAY_EXTENT } from "./cursor-overrides.js";
|
|
3
4
|
import { PARAMETERS_MISSING_NULLABLE_ANNOTATION } from "./nullable-overrides.js";
|
|
4
5
|
import { type GirParameter, type GirReturnValue, parameterFromNode, parseCallable } from "./parameter.js";
|
|
5
6
|
import { attr, getChild, type RawNode } from "./parse.js";
|
|
@@ -50,18 +51,53 @@ const relaxMissingNullable = (fn: GirFunction): GirFunction => {
|
|
|
50
51
|
return fn;
|
|
51
52
|
};
|
|
52
53
|
|
|
54
|
+
const parameterIndexFor = (parameters: GirParameter[], name: string): number => {
|
|
55
|
+
const index = parameters.findIndex((parameter) => parameter.name === name);
|
|
56
|
+
|
|
57
|
+
if (index === -1) {
|
|
58
|
+
throw new Error(`A cursor correction names a parameter the GIR does not declare: ${name}`);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return index;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const bindCursorParameters = (parameters: GirParameter[], corrections: CursorParameterNames[]): void => {
|
|
65
|
+
for (const names of corrections) {
|
|
66
|
+
const parameter = parameters[parameterIndexFor(parameters, names.cursor)];
|
|
67
|
+
|
|
68
|
+
if (parameter !== undefined) {
|
|
69
|
+
parameter.cursor = {
|
|
70
|
+
baseIndex: parameterIndexFor(parameters, names.base),
|
|
71
|
+
lengthIndex: parameterIndexFor(parameters, names.length),
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const bindMissingArrayExtent = (fn: GirFunction): GirFunction => {
|
|
78
|
+
const corrections = fn.cIdentifier === undefined ? undefined : PARAMETERS_MISSING_ARRAY_EXTENT.get(fn.cIdentifier);
|
|
79
|
+
|
|
80
|
+
if (corrections !== undefined) {
|
|
81
|
+
bindCursorParameters(fn.parameters, corrections);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return fn;
|
|
85
|
+
};
|
|
86
|
+
|
|
53
87
|
const functionFromNode = (node: RawNode, context: ParseContext): GirFunction => {
|
|
54
88
|
const instanceNode = getChild(getChild(node, "parameters"), "instance-parameter");
|
|
55
89
|
|
|
56
|
-
return
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
90
|
+
return bindMissingArrayExtent(
|
|
91
|
+
relaxMissingNullable({
|
|
92
|
+
...parseCallable(node, context),
|
|
93
|
+
name: attr(node, "shadows") ?? attr(node, "name") ?? "",
|
|
94
|
+
cIdentifier: attr(node, "c:identifier"),
|
|
95
|
+
movedTo: attr(node, "moved-to"),
|
|
96
|
+
shadowedBy: attr(node, "shadowed-by"),
|
|
97
|
+
finishFunc: attr(node, "glib:finish-func"),
|
|
98
|
+
instance: instanceNode === undefined ? undefined : parameterFromNode(instanceNode, context),
|
|
99
|
+
}),
|
|
100
|
+
);
|
|
65
101
|
};
|
|
66
102
|
|
|
67
103
|
export { functionFromNode, type GirFunction };
|
package/src/gir/gir-path.ts
CHANGED
|
@@ -7,7 +7,7 @@ const SYSTEM_GIR_PATH = "/usr/share/gir-1.0";
|
|
|
7
7
|
/**
|
|
8
8
|
* The directories to search for `.gir` files, in precedence order: the config's own `girPath`, then
|
|
9
9
|
* `GTKX_GIR_PATH`, then `/usr/share/gir-1.0`, then the girdir pkg-config reports for
|
|
10
|
-
* gobject-introspection-1.0. Duplicates are dropped, and the
|
|
10
|
+
* gobject-introspection-1.0. Duplicates are dropped, and the system directories are included only when they exist.
|
|
11
11
|
*
|
|
12
12
|
* @throws If pkg-config is installed but fails while being queried.
|
|
13
13
|
*/
|
package/src/gir/library.ts
CHANGED
|
@@ -84,10 +84,12 @@ class Library {
|
|
|
84
84
|
*
|
|
85
85
|
* @param libraries GIR identifiers to load, such as `Gtk-4.0`.
|
|
86
86
|
* @param girPath Directories searched, in order, for each `.gir` file.
|
|
87
|
+
* @param isByteArrayTyped Whether byte sequences render as `Uint8Array` rather than `number[]`.
|
|
87
88
|
* @returns A library holding every namespace that was parsed.
|
|
88
89
|
*/
|
|
89
|
-
static load(libraries: string[], girPath: string[]): Library {
|
|
90
|
+
static load(libraries: string[], girPath: string[], isByteArrayTyped = false): Library {
|
|
90
91
|
const library = new Library();
|
|
92
|
+
library.isByteArrayTypedValue = isByteArrayTyped;
|
|
91
93
|
this.drive(library, libraries, girPath);
|
|
92
94
|
|
|
93
95
|
return library;
|
|
@@ -99,6 +101,7 @@ class Library {
|
|
|
99
101
|
private nsIdByName: Map<string, number> = new Map();
|
|
100
102
|
private typeTables: TypeTable[] = [];
|
|
101
103
|
private girFilesValue: string[] = [];
|
|
104
|
+
private isByteArrayTypedValue = false;
|
|
102
105
|
|
|
103
106
|
/** Creates a library with no namespaces loaded; {@link Library.load} builds a populated one. */
|
|
104
107
|
constructor() {
|
|
@@ -294,7 +297,7 @@ class Library {
|
|
|
294
297
|
seen.add(namespaceName);
|
|
295
298
|
const path = locateGirFile(identifier, girPath);
|
|
296
299
|
girFiles.push(path);
|
|
297
|
-
const header = parseNamespaceHeader(readRepositoryNode(path));
|
|
300
|
+
const header = parseNamespaceHeader(readRepositoryNode(path), path);
|
|
298
301
|
const shell = this.registerNamespace(header);
|
|
299
302
|
discovered.push({ header, shell });
|
|
300
303
|
|
|
@@ -328,6 +331,11 @@ class Library {
|
|
|
328
331
|
return this.namespacesByName;
|
|
329
332
|
}
|
|
330
333
|
|
|
334
|
+
/** Whether byte sequences render as `Uint8Array` rather than `number[]`. */
|
|
335
|
+
public get isByteArrayTyped(): boolean {
|
|
336
|
+
return this.isByteArrayTypedValue;
|
|
337
|
+
}
|
|
338
|
+
|
|
331
339
|
/** Paths of the `.gir` files that were read, in the order they were discovered. */
|
|
332
340
|
public get girFiles(): string[] {
|
|
333
341
|
return this.girFilesValue;
|
package/src/gir/namespace.ts
CHANGED
|
@@ -44,6 +44,8 @@ type GirNamespace = {
|
|
|
44
44
|
id: number;
|
|
45
45
|
/** Namespace name as it appears in the GIR, such as `Gtk`. */
|
|
46
46
|
name: string;
|
|
47
|
+
/** Path of the `.gir` file the namespace was parsed from, named by every diagnostic the namespace causes. */
|
|
48
|
+
girFile: string;
|
|
47
49
|
/** The `shared-library` attribute verbatim: the objects to load symbols from, separated by commas. */
|
|
48
50
|
sharedLibrary: string | undefined;
|
|
49
51
|
/** Prefixes stripped off C identifiers to derive export names, such as `gtk`. */
|
|
@@ -78,6 +80,8 @@ type NamespaceInclude = {
|
|
|
78
80
|
type NamespaceHeader = {
|
|
79
81
|
/** Namespace name as it appears in the GIR, such as `Gtk`. */
|
|
80
82
|
name: string;
|
|
83
|
+
/** Path of the `.gir` file the header was read from. */
|
|
84
|
+
girFile: string;
|
|
81
85
|
/** The `shared-library` attribute verbatim: the objects to load symbols from, separated by commas. */
|
|
82
86
|
sharedLibrary: string | undefined;
|
|
83
87
|
/** Prefixes stripped off C identifiers to derive export names, such as `gtk`. */
|
|
@@ -90,7 +94,7 @@ type NamespaceHeader = {
|
|
|
90
94
|
|
|
91
95
|
const namespaceDirectory = (namespace: Pick<GirNamespace, "name">): string => namespace.name.toLowerCase();
|
|
92
96
|
|
|
93
|
-
const parseNamespaceHeader = (repositoryNode: RawNode): NamespaceHeader => {
|
|
97
|
+
const parseNamespaceHeader = (repositoryNode: RawNode, path: string): NamespaceHeader => {
|
|
94
98
|
const includes = getChildren(repositoryNode, "include").map<NamespaceInclude>((include) => ({
|
|
95
99
|
name: nameAttr(include),
|
|
96
100
|
version: attr(include, "version") ?? "",
|
|
@@ -99,11 +103,12 @@ const parseNamespaceHeader = (repositoryNode: RawNode): NamespaceHeader => {
|
|
|
99
103
|
const namespaceNode = getChildren(repositoryNode, "namespace")[0];
|
|
100
104
|
|
|
101
105
|
if (namespaceNode === undefined) {
|
|
102
|
-
throw new Error(
|
|
106
|
+
throw new Error(`GIR file at ${path} has no <namespace> child in its <repository>`);
|
|
103
107
|
}
|
|
104
108
|
|
|
105
109
|
return {
|
|
106
110
|
name: nameAttr(namespaceNode),
|
|
111
|
+
girFile: path,
|
|
107
112
|
sharedLibrary: attr(namespaceNode, "shared-library"),
|
|
108
113
|
cSymbolPrefixes: splitPrefixes(attr(namespaceNode, "c:symbol-prefixes")),
|
|
109
114
|
includes,
|
|
@@ -114,6 +119,7 @@ const parseNamespaceHeader = (repositoryNode: RawNode): NamespaceHeader => {
|
|
|
114
119
|
const createNamespaceShell = (header: NamespaceHeader, id: number): GirNamespace => ({
|
|
115
120
|
id,
|
|
116
121
|
name: header.name,
|
|
122
|
+
girFile: header.girFile,
|
|
117
123
|
sharedLibrary: header.sharedLibrary,
|
|
118
124
|
cSymbolPrefixes: header.cSymbolPrefixes,
|
|
119
125
|
classes: [],
|
package/src/gir/parameter.ts
CHANGED
|
@@ -23,6 +23,17 @@ type ParameterTransfer = "none" | "full" | "container";
|
|
|
23
23
|
*/
|
|
24
24
|
type CallbackScope = "call" | "notified" | "async" | "forever";
|
|
25
25
|
|
|
26
|
+
/**
|
|
27
|
+
* Bounds of an out parameter that points into the buffer of a sibling parameter instead of to an
|
|
28
|
+
* array of its own, which GIR describes as an array with no extent of any kind.
|
|
29
|
+
*/
|
|
30
|
+
type GirCursorBounds = {
|
|
31
|
+
/** Position of the parameter holding the buffer the pointer points into. */
|
|
32
|
+
baseIndex: number;
|
|
33
|
+
/** Position of the parameter carrying that buffer's element count. */
|
|
34
|
+
lengthIndex: number;
|
|
35
|
+
};
|
|
36
|
+
|
|
26
37
|
/** A parameter of a {@link GirCallable}, with the annotations that decide how it is marshalled. */
|
|
27
38
|
type GirParameter = {
|
|
28
39
|
/** The name GIR gives the parameter. */
|
|
@@ -51,6 +62,8 @@ type GirParameter = {
|
|
|
51
62
|
destroyIndex: number | undefined;
|
|
52
63
|
/** Whether the parameter is the `...` varargs marker. */
|
|
53
64
|
isVarargs: boolean;
|
|
65
|
+
/** Where the buffer is that the parameter points into, when it carries a cursor rather than an array. */
|
|
66
|
+
cursor: GirCursorBounds | undefined;
|
|
54
67
|
};
|
|
55
68
|
|
|
56
69
|
/** What a {@link GirCallable} hands back, with the annotations that decide how it is marshalled. */
|
|
@@ -118,6 +131,7 @@ const parameterFromNode = (node: RawNode, context: ParseContext): GirParameter =
|
|
|
118
131
|
closureIndex: intAttr(node, "closure"),
|
|
119
132
|
destroyIndex: intAttr(node, "destroy"),
|
|
120
133
|
isVarargs: getChild(node, "varargs") !== undefined,
|
|
134
|
+
cursor: undefined,
|
|
121
135
|
});
|
|
122
136
|
|
|
123
137
|
const isOutParameter = (parameter: GirParameter): boolean =>
|
|
@@ -163,6 +177,7 @@ export {
|
|
|
163
177
|
isInoutParameter,
|
|
164
178
|
parseCallable,
|
|
165
179
|
type ParameterTransfer,
|
|
180
|
+
type GirCursorBounds,
|
|
166
181
|
type GirParameter,
|
|
167
182
|
type GirReturnValue,
|
|
168
183
|
type GirCallable,
|
package/src/gir/parse.ts
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { createXmlParser } from "../xml.js";
|
|
1
|
+
import { createXmlParser, parseXmlFile } from "../xml.js";
|
|
3
2
|
|
|
4
3
|
/** An element of the parsed GIR XML: attributes under `@_`-prefixed keys, children under their tag names. */
|
|
5
4
|
type RawNode = Record<string, unknown>;
|
|
6
5
|
|
|
6
|
+
const GIR_LABEL = "GIR file";
|
|
7
|
+
|
|
8
|
+
const GIR_MALFORMED_REMEDY =
|
|
9
|
+
"No XML parser can read this file, so report it to whoever ships it. To get past it now, name the " +
|
|
10
|
+
"libraries you need explicitly in `libraries` and leave this one out, or put a corrected copy of the " +
|
|
11
|
+
"file in a directory listed in `girPath`, which is searched ahead of the system location.";
|
|
12
|
+
|
|
7
13
|
const MULTI_TAGS: Set<string> = new Set([
|
|
8
14
|
"include",
|
|
9
15
|
"class",
|
|
@@ -42,11 +48,8 @@ function renameReservedTag(tag: string): string {
|
|
|
42
48
|
return RESERVED_TAG_RENAMES.get(tag) ?? tag;
|
|
43
49
|
}
|
|
44
50
|
|
|
45
|
-
const parseGirFile = (path: string): RawNode =>
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
return PARSER.parse(xml) as RawNode;
|
|
49
|
-
};
|
|
51
|
+
const parseGirFile = (path: string): RawNode =>
|
|
52
|
+
parseXmlFile({ parser: PARSER, label: GIR_LABEL, path, malformedRemedy: GIR_MALFORMED_REMEDY }) as RawNode;
|
|
50
53
|
|
|
51
54
|
const attr = (node: RawNode | undefined, name: string): string | undefined => {
|
|
52
55
|
if (node === undefined) {
|
package/src/gir/primitives.ts
CHANGED
|
@@ -110,7 +110,7 @@ const PRIMITIVE_TS_TYPE: Record<PrimitiveCategory, string> = {
|
|
|
110
110
|
float64: "number",
|
|
111
111
|
string: "string",
|
|
112
112
|
unichar: "string",
|
|
113
|
-
pointer: "
|
|
113
|
+
pointer: "bigint",
|
|
114
114
|
};
|
|
115
115
|
|
|
116
116
|
const primitiveCategory = (name: string): PrimitiveCategory | undefined => PRIMITIVE_BY_NAME.get(name);
|
package/src/guards.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { isRecord } from "@gtkx/utils";
|
|
2
|
+
|
|
3
|
+
type Guard<T> = (value: unknown) => value is T;
|
|
4
|
+
type OptionalGuard<T> = Guard<T | undefined> & { __optional__: true };
|
|
5
|
+
type FieldGuard<T> = [undefined] extends [T] ? OptionalGuard<NonNullable<T>> : Guard<T>;
|
|
6
|
+
type FieldGuards<T> = { [K in keyof Required<T>]: FieldGuard<T[K]> };
|
|
7
|
+
|
|
8
|
+
const isBoolean = (value: unknown): value is boolean => typeof value === "boolean";
|
|
9
|
+
const isNumber = (value: unknown): value is number => typeof value === "number";
|
|
10
|
+
const isString = (value: unknown): value is string => typeof value === "string";
|
|
11
|
+
|
|
12
|
+
const arrayGuard = <T>(isEntry: Guard<T>): Guard<T[]> =>
|
|
13
|
+
(value: unknown): value is T[] => Array.isArray(value) && value.every((entry: unknown) => isEntry(entry));
|
|
14
|
+
|
|
15
|
+
const optionalGuard = <T>(isPresent: Guard<T>): OptionalGuard<T> =>
|
|
16
|
+
Object.assign((value: unknown): value is T | undefined => value === undefined || isPresent(value), {
|
|
17
|
+
__optional__: true as const,
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const hasFields = <T extends object>(value: unknown, guards: FieldGuards<T>): value is T =>
|
|
21
|
+
isRecord(value) && Object.entries(guards).every(([name, guard]) => (guard as Guard<unknown>)(value[name]));
|
|
22
|
+
|
|
23
|
+
export { arrayGuard, hasFields, isBoolean, isNumber, isString, optionalGuard };
|
package/src/internal.ts
CHANGED
package/src/json.ts
ADDED
package/src/khronos/args.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { toCamelIdentifier } from "@gtkx/utils";
|
|
|
2
2
|
import type { GlCommand, GlParam } from "./model.js";
|
|
3
3
|
import type { CommandPlan, GlScalar, ParamPlan, ReturnPlan } from "./plan.js";
|
|
4
4
|
import {
|
|
5
|
+
type ArrayLayout,
|
|
5
6
|
tArray,
|
|
6
7
|
tBoolean,
|
|
7
8
|
tBuffer,
|
|
@@ -50,6 +51,7 @@ type BuildArgOptions = {
|
|
|
50
51
|
};
|
|
51
52
|
|
|
52
53
|
const OUT_PLAN_KINDS: Set<string> = new Set(["ref-out", "ref-array-out", "ref-fixed-out", "string-out"]);
|
|
54
|
+
const NUMERIC_LAYOUT: ArrayLayout = { isBytes: false };
|
|
53
55
|
|
|
54
56
|
const scalarAliasOrGroup = (scalar: GlScalar, group: string | undefined): string =>
|
|
55
57
|
group !== undefined && scalar.isGroupBearing === true ? group : scalar.tsAlias;
|
|
@@ -122,12 +124,13 @@ const buildInArg = (options: BuildArgOptions, name: string, track: (alias: strin
|
|
|
122
124
|
return inArg(name, "string", tString("borrowed"));
|
|
123
125
|
}
|
|
124
126
|
case "string-array-in": {
|
|
125
|
-
return inArg(name, "string[]", tArray(tString("borrowed")));
|
|
127
|
+
return inArg(name, "string[]", tArray(tString("borrowed"), undefined, NUMERIC_LAYOUT));
|
|
126
128
|
}
|
|
127
129
|
case "array-in": {
|
|
128
130
|
track(scalarAliasOrGroup(plan.scalar, param.group));
|
|
131
|
+
const descriptor = tArray(plan.scalar.descriptor, undefined, NUMERIC_LAYOUT);
|
|
129
132
|
|
|
130
|
-
return inArg(name, arrayInTsType(plan.scalar, param.group),
|
|
133
|
+
return inArg(name, arrayInTsType(plan.scalar, param.group), descriptor);
|
|
131
134
|
}
|
|
132
135
|
case "buffer": {
|
|
133
136
|
return inArg(name, `ArrayBufferView | ${track("GLintptr")} | null`, tBuffer);
|
|
@@ -136,7 +139,7 @@ const buildInArg = (options: BuildArgOptions, name: string, track: (alias: strin
|
|
|
136
139
|
return inArg(name, track("GLintptr"), tUint64);
|
|
137
140
|
}
|
|
138
141
|
case "byte-offset-array": {
|
|
139
|
-
return inArg(name, `${track("GLintptr")}[]`, tArray(tUint64));
|
|
142
|
+
return inArg(name, `${track("GLintptr")}[]`, tArray(tUint64, undefined, NUMERIC_LAYOUT));
|
|
140
143
|
}
|
|
141
144
|
case "ref-array-out":
|
|
142
145
|
case "ref-fixed-out":
|
|
@@ -165,14 +168,14 @@ const outArgFields = (options: OutArgFieldsOptions): OutArgFields => {
|
|
|
165
168
|
return {
|
|
166
169
|
seed: `const ${cellName} = { value: new Array<number>(${lenIdentifier}).fill(0) };`,
|
|
167
170
|
tsType: `${track(scalarAliasOrGroup(plan.scalar, param.group))}[]`,
|
|
168
|
-
descriptor: tRef(tSizedArray(plan.scalar.descriptor, sizeIndex)),
|
|
171
|
+
descriptor: tRef(tSizedArray(plan.scalar.descriptor, sizeIndex, undefined, NUMERIC_LAYOUT)),
|
|
169
172
|
};
|
|
170
173
|
}
|
|
171
174
|
case "ref-fixed-out": {
|
|
172
175
|
return {
|
|
173
176
|
seed: `const ${cellName} = { value: new Array<number>(${String(plan.length)}).fill(0) };`,
|
|
174
177
|
tsType: `${track(plan.scalar.tsAlias)}[]`,
|
|
175
|
-
descriptor: tRef(tFixedArray(plan.scalar.descriptor, plan.length)),
|
|
178
|
+
descriptor: tRef(tFixedArray(plan.scalar.descriptor, plan.length, undefined, NUMERIC_LAYOUT)),
|
|
176
179
|
};
|
|
177
180
|
}
|
|
178
181
|
case "string-out": {
|
|
@@ -204,7 +207,7 @@ const buildOutArg = (options: BuildArgOptions, track: (alias: string) => string)
|
|
|
204
207
|
throw new Error(`Parameter index ${String(index)} out of range on ${command.name}`);
|
|
205
208
|
}
|
|
206
209
|
|
|
207
|
-
const cellName = `
|
|
210
|
+
const cellName = `__out${String(outIndex)}`;
|
|
208
211
|
const cell: OutArgCell = { isOut: true, cellName, paramIndex: index };
|
|
209
212
|
|
|
210
213
|
return { ...cell, ...outArgFields({ command, plan, param, cellName, track }) };
|
package/src/khronos/modules.ts
CHANGED
|
@@ -76,7 +76,10 @@ const renderEnumsModule = (tokens: EnumRow[], docs: GlDocContext): string => {
|
|
|
76
76
|
const builder = new ModuleBuilder();
|
|
77
77
|
|
|
78
78
|
for (const row of tokens) {
|
|
79
|
-
builder.appendDeclaration(
|
|
79
|
+
builder.appendDeclaration({
|
|
80
|
+
name: row.exportName,
|
|
81
|
+
code: `${enumJsDoc(row, docs)}\nexport const ${row.exportName} = ${row.literal};`,
|
|
82
|
+
});
|
|
80
83
|
}
|
|
81
84
|
|
|
82
85
|
return `${generatedHeader(docs)}\n\n${builder.toSource()}`;
|
|
@@ -135,7 +138,11 @@ const appendScalarAliases = (builder: ModuleBuilder, docs: GlDocContext): void =
|
|
|
135
138
|
}
|
|
136
139
|
|
|
137
140
|
seen.add(scalar.tsAlias);
|
|
138
|
-
|
|
141
|
+
|
|
142
|
+
builder.appendDeclaration({
|
|
143
|
+
name: scalar.tsAlias,
|
|
144
|
+
code: `${scalarJsDoc(scalar.tsAlias, docs)}\nexport type ${scalar.tsAlias} = number;`,
|
|
145
|
+
});
|
|
139
146
|
}
|
|
140
147
|
};
|
|
141
148
|
|
|
@@ -143,7 +150,10 @@ const appendGroupAliases = (builder: ModuleBuilder, groupAliases: Map<string, st
|
|
|
143
150
|
const sorted = sortStringsBy(groupAliases.entries(), ([key]) => key);
|
|
144
151
|
|
|
145
152
|
for (const [group, base] of sorted) {
|
|
146
|
-
builder.appendDeclaration(
|
|
153
|
+
builder.appendDeclaration({
|
|
154
|
+
name: group,
|
|
155
|
+
code: `${groupAliasJsDoc(group, base, docs)}\nexport type ${group} = ${base};`,
|
|
156
|
+
});
|
|
147
157
|
}
|
|
148
158
|
};
|
|
149
159
|
|
|
@@ -151,12 +161,18 @@ const renderTypesModule = (groupAliases: Map<string, string>, docs: GlDocContext
|
|
|
151
161
|
const builder = new ModuleBuilder();
|
|
152
162
|
builder.imports.addNamed("@gtkx/native", "ExternalObject", true);
|
|
153
163
|
builder.imports.addNamed("@gtkx/native", "Handle", true);
|
|
154
|
-
builder.appendDeclaration(`${syncJsDoc(docs)}\nexport type GLsync = ExternalObject<Handle>;`);
|
|
155
164
|
|
|
156
|
-
builder.appendDeclaration(
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
);
|
|
165
|
+
builder.appendDeclaration({
|
|
166
|
+
name: "GLsync",
|
|
167
|
+
code: `${syncJsDoc(docs)}\nexport type GLsync = ExternalObject<Handle>;`,
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
builder.appendDeclaration({
|
|
171
|
+
name: "GLpointer",
|
|
172
|
+
code:
|
|
173
|
+
"/** An opaque native pointer handle (e.g. a `glMapBufferRange` mapping). */\n" +
|
|
174
|
+
"export type GLpointer = ExternalObject<Handle>;",
|
|
175
|
+
});
|
|
160
176
|
|
|
161
177
|
appendScalarAliases(builder, docs);
|
|
162
178
|
appendGroupAliases(builder, groupAliases, docs);
|
|
@@ -184,7 +200,7 @@ const appendCommandBindings = (builder: ModuleBuilder, commands: RenderedCommand
|
|
|
184
200
|
|
|
185
201
|
const appendCommandDeclarations = (builder: ModuleBuilder, commands: RenderedCommand[]): void => {
|
|
186
202
|
for (const command of commands) {
|
|
187
|
-
builder.appendDeclaration(command.declaration);
|
|
203
|
+
builder.appendDeclaration({ name: command.exportName, code: command.declaration });
|
|
188
204
|
}
|
|
189
205
|
};
|
|
190
206
|
|
package/src/khronos/parse.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { createXmlParser } from "../xml.js";
|
|
1
|
+
import { createXmlParser, parseXmlFile } from "../xml.js";
|
|
3
2
|
|
|
4
3
|
type OrderedNode = Record<string, unknown>;
|
|
5
4
|
|
|
6
5
|
const ATTRIBUTES_KEY = ":@";
|
|
7
6
|
const TEXT_KEY = "#text";
|
|
7
|
+
const REGISTRY_LABEL = "OpenGL registry";
|
|
8
8
|
|
|
9
9
|
const PARSER = createXmlParser({
|
|
10
10
|
trimValues: false,
|
|
@@ -12,8 +12,7 @@ const PARSER = createXmlParser({
|
|
|
12
12
|
});
|
|
13
13
|
|
|
14
14
|
const parseRegistryFile = (path: string): OrderedNode[] => {
|
|
15
|
-
const
|
|
16
|
-
const documentNodes = PARSER.parse(xml) as OrderedNode[];
|
|
15
|
+
const documentNodes = parseXmlFile({ parser: PARSER, label: REGISTRY_LABEL, path }) as OrderedNode[];
|
|
17
16
|
|
|
18
17
|
for (const node of documentNodes) {
|
|
19
18
|
if (nodeTag(node) === "registry") {
|
package/src/khronos/pipeline.ts
CHANGED
package/src/khronos/plan.ts
CHANGED
package/src/khronos/render.ts
CHANGED
|
@@ -114,7 +114,7 @@ const returnStatements = (call: string, returned: EmittedReturn, outs: OutArg[])
|
|
|
114
114
|
return [`${call};`, tail];
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
-
return [`const
|
|
117
|
+
return [`const __result = ${call};`, `return [${returned.expr("__result")}, ${outValues.join(", ")}];`];
|
|
118
118
|
};
|
|
119
119
|
|
|
120
120
|
const renderCommand = (
|
|
@@ -135,7 +135,7 @@ const renderCommand = (
|
|
|
135
135
|
const seeds = outs.map((out) => out.seed);
|
|
136
136
|
const bindExpression = glBind(command.name, descriptors, returned.descriptor);
|
|
137
137
|
const isInline = plan.params.some((paramPlan) => paramPlan.kind === "string-out");
|
|
138
|
-
const bindingName = isInline ? "
|
|
138
|
+
const bindingName = isInline ? "__binding" : toCamelIdentifier(command.name);
|
|
139
139
|
|
|
140
140
|
const body = [
|
|
141
141
|
...seeds,
|
|
@@ -252,12 +252,14 @@ const deriveGenSingular = (
|
|
|
252
252
|
const descriptors = [...prefix.map((arg) => arg.descriptor), countScalar.descriptor, tRef(outScalar.descriptor)];
|
|
253
253
|
usedTypes.add(outScalar.tsAlias);
|
|
254
254
|
const signature = prefix.map((arg) => `${arg.name}: ${arg.tsType}`).join(", ");
|
|
255
|
-
const callArgs = [...prefix.map((arg) => arg.name), "1", "
|
|
255
|
+
const callArgs = [...prefix.map((arg) => arg.name), "1", "__out"].join(", ");
|
|
256
256
|
const jsDoc = genSingularJsDoc({ plan, provenance, docs }, prefix, shape);
|
|
257
257
|
|
|
258
|
-
const body = [
|
|
259
|
-
"
|
|
260
|
-
)
|
|
258
|
+
const body = [
|
|
259
|
+
" const __out = { value: 0 };",
|
|
260
|
+
` ${bindingName}(${callArgs});`,
|
|
261
|
+
" return __out.value;",
|
|
262
|
+
].join("\n");
|
|
261
263
|
|
|
262
264
|
const binding = glBind(plan.command.name, renderDescriptorList(descriptors), tVoid);
|
|
263
265
|
|
package/src/runner.ts
CHANGED
|
@@ -2,12 +2,13 @@ import { mkdirSync, writeFileSync } from "node:fs";
|
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import type { ModuleExport } from "./react/element-config.js";
|
|
4
4
|
import type { OmittedProps } from "./store/jsx/omitted-props.js";
|
|
5
|
-
import type { StoreOptions } from "./store/store-fs.js";
|
|
6
5
|
import { checkModules } from "./compile.js";
|
|
7
6
|
import { isGiStoreFresh } from "./fingerprint.js";
|
|
8
7
|
import { runGiCodegen } from "./gi.js";
|
|
9
8
|
import { Library } from "./gir/library.js";
|
|
10
9
|
import { generateGlModules, type GlGenerationReport } from "./khronos/pipeline.js";
|
|
10
|
+
import { sweepStagingDirs } from "./staging.js";
|
|
11
|
+
import { ensureStoreLink, type StoreOptions } from "./store/store-fs.js";
|
|
11
12
|
|
|
12
13
|
type GlCodegenOptions = {
|
|
13
14
|
registryPath: string;
|
|
@@ -38,6 +39,8 @@ type CodegenRunnerOptions = {
|
|
|
38
39
|
userOmittedProps?: OmittedProps;
|
|
39
40
|
/** Regenerates both stores even when their fingerprints are fresh. */
|
|
40
41
|
isForced?: boolean;
|
|
42
|
+
/** Emits GIR byte sequences as `Uint8Array` rather than `number[]`; defaults to false. */
|
|
43
|
+
isByteArrayTyped?: boolean;
|
|
41
44
|
};
|
|
42
45
|
|
|
43
46
|
/** What a `runCodegen` run produced. */
|
|
@@ -64,6 +67,10 @@ type StoreResult = {
|
|
|
64
67
|
* store or the React element config changed, unless `options.isForced` is set. Pass the spread of
|
|
65
68
|
* `resolveStore(projectRoot)` for everything but `libraries` and `girPath`.
|
|
66
69
|
*
|
|
70
|
+
* Every store already on disk is linked at its `linkDir` before anything is generated, so a link an install
|
|
71
|
+
* pruned out of `node_modules` is restored without regenerating the store, and the gi store is reachable
|
|
72
|
+
* under its own specifier while the jsx store is type checked.
|
|
73
|
+
*
|
|
67
74
|
* @param options What to generate and where to write it.
|
|
68
75
|
* @returns A summary of what was regenerated and how long the run took.
|
|
69
76
|
* @throws If `girPath` is empty, which would otherwise generate nothing and report success.
|
|
@@ -152,12 +159,14 @@ const emitStoresWithConfig = async (config: {
|
|
|
152
159
|
girPath: string[];
|
|
153
160
|
}): Promise<StoreResult> => {
|
|
154
161
|
const { options, gi, jsx, libraries, girPath } = config;
|
|
162
|
+
const isByteArrayTyped = options.isByteArrayTyped === true;
|
|
155
163
|
let library: Library | undefined;
|
|
156
|
-
const loadLibrary = (): Library => (library ??= Library.load(libraries, girPath));
|
|
157
|
-
const
|
|
164
|
+
const loadLibrary = (): Library => (library ??= Library.load(libraries, girPath, isByteArrayTyped));
|
|
165
|
+
const giInputs = { girFiles: [] as string[], libraries, girPath, isByteArrayTyped };
|
|
166
|
+
const isGiRegenerated = options.isForced === true || !isGiStoreFresh(gi.storeDir, giInputs);
|
|
158
167
|
|
|
159
168
|
const namespaces = isGiRegenerated
|
|
160
|
-
? runGiCodegen(loadLibrary(), { gi, libraries, girPath })
|
|
169
|
+
? runGiCodegen(loadLibrary(), { gi, libraries, girPath, isByteArrayTyped })
|
|
161
170
|
: 0;
|
|
162
171
|
|
|
163
172
|
if (jsx === undefined) {
|
|
@@ -167,6 +176,17 @@ const emitStoresWithConfig = async (config: {
|
|
|
167
176
|
return emitJsxStore({ options, jsx, gi, loadLibrary, isGiRegenerated, namespaces });
|
|
168
177
|
};
|
|
169
178
|
|
|
179
|
+
const prepareStores = (stores: (StoreOptions | undefined)[]): void => {
|
|
180
|
+
for (const store of stores) {
|
|
181
|
+
if (store === undefined) {
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
sweepStagingDirs(store.storeDir);
|
|
186
|
+
ensureStoreLink(store);
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
|
|
170
190
|
const emitStores = async (options: CodegenRunnerOptions): Promise<StoreResult> => {
|
|
171
191
|
const { gi, jsx, libraries, girPath } = options;
|
|
172
192
|
|
|
@@ -174,6 +194,8 @@ const emitStores = async (options: CodegenRunnerOptions): Promise<StoreResult> =
|
|
|
174
194
|
throw new Error("codegen needs at least one GIR search path; pass the result of resolveGirPath");
|
|
175
195
|
}
|
|
176
196
|
|
|
197
|
+
prepareStores([gi, jsx]);
|
|
198
|
+
|
|
177
199
|
return emitStoresWithConfig({ options, gi, jsx, libraries, girPath });
|
|
178
200
|
};
|
|
179
201
|
|
package/src/staging.ts
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { errorCode } from "@gtkx/utils";
|
|
2
|
+
import { mkdirSync, mkdtempSync, readdirSync, rmSync } from "node:fs";
|
|
3
|
+
import { basename, dirname, join } from "node:path";
|
|
4
|
+
|
|
5
|
+
const STAGING_SUFFIX = ".tmp-";
|
|
6
|
+
const OWNER_PATTERN = /^(?<pid>\d+)-/;
|
|
7
|
+
|
|
8
|
+
const isOwnerRunning = (pid: number): boolean => {
|
|
9
|
+
if (!Number.isSafeInteger(pid) || pid <= 0) {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
try {
|
|
14
|
+
process.kill(pid, 0);
|
|
15
|
+
|
|
16
|
+
return true;
|
|
17
|
+
} catch (error) {
|
|
18
|
+
return errorCode(error) === "EPERM";
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const isStranded = (entry: string, prefix: string): boolean => {
|
|
23
|
+
if (!entry.startsWith(prefix)) {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const owner = OWNER_PATTERN.exec(entry.slice(prefix.length))?.groups?.pid;
|
|
28
|
+
|
|
29
|
+
return owner === undefined || !isOwnerRunning(Number(owner));
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const readEntries = (parentDir: string): string[] => {
|
|
33
|
+
try {
|
|
34
|
+
return readdirSync(parentDir);
|
|
35
|
+
} catch {
|
|
36
|
+
return [];
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const removeStrandedDir = (path: string): void => {
|
|
41
|
+
try {
|
|
42
|
+
rmSync(path, { recursive: true, force: true });
|
|
43
|
+
} catch {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const sweepStrandedDirs = (parentDir: string, prefix: string): void => {
|
|
49
|
+
for (const entry of readEntries(parentDir)) {
|
|
50
|
+
if (isStranded(entry, prefix)) {
|
|
51
|
+
removeStrandedDir(join(parentDir, entry));
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const sweepStagingDirs = (target: string): void => {
|
|
57
|
+
sweepStrandedDirs(dirname(target), `${basename(target)}${STAGING_SUFFIX}`);
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const createStagingDir = (target: string): string => {
|
|
61
|
+
mkdirSync(dirname(target), { recursive: true });
|
|
62
|
+
sweepStagingDirs(target);
|
|
63
|
+
|
|
64
|
+
return mkdtempSync(`${target}${STAGING_SUFFIX}${String(process.pid)}-`);
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export { createStagingDir, sweepStagingDirs, sweepStrandedDirs };
|