@gjsify/node-gi 0.40.0 → 0.42.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 -2
- package/gtk-runtime.js +16 -8
- package/load-diagnostics.js +59 -1
- package/native-paths.js +14 -2
- package/package.json +1 -1
- package/prebuilds/darwin-arm64/node_gi.node +0 -0
- package/prebuilds/darwin-x64/node_gi.node +0 -0
- package/prebuilds/linux-arm64/node_gi.node +0 -0
- package/prebuilds/linux-x64/node_gi.node +0 -0
- package/prebuilds/win32-x64/node_gi.node +0 -0
- package/src/class.cc +0 -2
- package/src/marshal.cc +128 -8
- package/system-gi.js +8 -2
package/README.md
CHANGED
|
@@ -609,8 +609,7 @@ shared per-instance JS object yet), so use GObject **properties** for any state
|
|
|
609
609
|
that must be visible both inside a vfunc and on the instance (those live in C and
|
|
610
610
|
are consistent; the unified instance identity arrives with the toggle-ref work);
|
|
611
611
|
a JS↔GObject reference cycle on a custom instance leaks (the same cycle-leak
|
|
612
|
-
caveat the signal/vfunc layer carries)
|
|
613
|
-
chains (registering a subclass of a registered subclass) are not yet supported.
|
|
612
|
+
caveat the signal/vfunc layer carries).
|
|
614
613
|
|
|
615
614
|
#### `GObject` conveniences (signals, `GObject.Value`, `Object.new`)
|
|
616
615
|
|
package/gtk-runtime.js
CHANGED
|
@@ -399,14 +399,22 @@ export function maybeWireGtkWindowingEnv() {
|
|
|
399
399
|
setIfUnset('GSETTINGS_SCHEMA_DIR', schemaDir);
|
|
400
400
|
|
|
401
401
|
// MODULE_FILE is the load-bearing one on BOTH platforms — it is the cache, and the
|
|
402
|
-
// cache is what names the modules.
|
|
403
|
-
//
|
|
404
|
-
//
|
|
405
|
-
//
|
|
406
|
-
//
|
|
407
|
-
//
|
|
408
|
-
//
|
|
409
|
-
//
|
|
402
|
+
// cache is what names the modules. It is also the ONLY variable gdk-pixbuf's runtime
|
|
403
|
+
// reads: `GDK_PIXBUF_MODULEDIR` is read by queryloaders.c, the GENERATOR, where it
|
|
404
|
+
// merely picks the directory to scan. This comment used to claim the opposite — that
|
|
405
|
+
// MODULEDIR is "what its bare-leaf cache needs" on win32 — and the win32 builder wrote
|
|
406
|
+
// a bare-leaf cache on the strength of it. gdk-pixbuf 2.44.6's `build_module_path()`
|
|
407
|
+
// joins a relative cache entry with the bundle TOPLEVEL instead, so every leaf resolved
|
|
408
|
+
// to `<bundle>\<leaf>` and no SVG icon has ever decoded from a win32 bundle (#996).
|
|
409
|
+
// The cache is written toplevel-relative now; see scripts/pixbuf-loader-cache.mjs.
|
|
410
|
+
//
|
|
411
|
+
// darwin needs neither: Homebrew's gdk-pixbuf 2.44.7 has no `GDK_PIXBUF_MODULEDIR`
|
|
412
|
+
// string in the dylib at all, so that cache names each module `@loader_path/…`
|
|
413
|
+
// (relative to the image that dlopens it, i.e. the bundle's lib/) and dyld resolves it
|
|
414
|
+
// with no env beyond this file.
|
|
415
|
+
//
|
|
416
|
+
// MODULEDIR is still set, and still only if unset: it costs nothing, and it is what a
|
|
417
|
+
// consumer regenerating the cache in-process would need. Nothing here depends on it.
|
|
410
418
|
const loaderCache = join(bundle.dir, 'lib', 'gdk-pixbuf-2.0', '2.10.0', 'loaders.cache');
|
|
411
419
|
if (existsSync(loaderCache)) {
|
|
412
420
|
setIfUnset('GDK_PIXBUF_MODULEDIR', join(bundle.dir, 'lib', 'gdk-pixbuf-2.0', '2.10.0', 'loaders'));
|
package/load-diagnostics.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
2
|
// @gjsify/node-gi/load-diagnostics — what a user is told when the addon FILE is
|
|
3
|
-
// present and still will not load.
|
|
3
|
+
// present and still will not load. TWO causes reach the same catch and they get
|
|
4
|
+
// DIFFERENT answers: the loader could not resolve the specifier, or it resolved
|
|
5
|
+
// it and the OS refused the binary. Only the second is about GTK.
|
|
4
6
|
//
|
|
5
7
|
// A MODULE OF ITS OWN, and that is the point: `index.js` loads the native addon
|
|
6
8
|
// at evaluation time, so anything living there can only be imported by a process
|
|
@@ -13,6 +15,41 @@
|
|
|
13
15
|
import { hostTarget } from './native-paths.js';
|
|
14
16
|
import { gtkSource } from './gtk-runtime.js';
|
|
15
17
|
|
|
18
|
+
/**
|
|
19
|
+
* Did the loader fail to RESOLVE the specifier, rather than to load the binary?
|
|
20
|
+
*
|
|
21
|
+
* Two entirely different failures arrive at the same `catch`, and only one of
|
|
22
|
+
* them is about GTK:
|
|
23
|
+
*
|
|
24
|
+
* • dlopen/LoadLibrary said no — the file was found, and its dependency
|
|
25
|
+
* closure (or its ABI) is the problem. That is the case the long GTK
|
|
26
|
+
* explanation below describes.
|
|
27
|
+
* • `require()` never got as far as the file. The specifier was neither
|
|
28
|
+
* absolute nor `./`-led, so it was looked up as a MODULE — against this
|
|
29
|
+
* package's directory and node_modules, never against the process's cwd that
|
|
30
|
+
* the `existsSync()` one line earlier had just resolved it against.
|
|
31
|
+
*
|
|
32
|
+
* THE INCIDENT (#996 / PR #1239), and why this discriminator exists at all:
|
|
33
|
+
* node-gi.yml hands the GTK bundle builder a repo-relative `--stage`, the builder
|
|
34
|
+
* passed that straight through as `NODE_GI_NATIVE`, and all four darwin bundle
|
|
35
|
+
* legs failed with `Cannot find module 'packages/node-gi/…'` underneath a
|
|
36
|
+
* confident five-line account of the Homebrew dependency closure ending in
|
|
37
|
+
* "Reinstall @gjsify/gtk-runtime-darwin-arm64". Every word of that advice was
|
|
38
|
+
* wrong for the cause, and it is the advice a stranger would have followed. The
|
|
39
|
+
* path bug itself is fixed in `native-paths.js#nativeCandidates()`; this stays
|
|
40
|
+
* because the next relative path to reach a `require()` will not come from there.
|
|
41
|
+
* @param {unknown} err
|
|
42
|
+
* @returns {boolean}
|
|
43
|
+
*/
|
|
44
|
+
function isResolutionFailure(err) {
|
|
45
|
+
if (!err || typeof err !== 'object') return false;
|
|
46
|
+
const { code, message } = /** @type {{ code?: unknown, message?: unknown }} */ (err);
|
|
47
|
+
if (code === 'MODULE_NOT_FOUND' || code === 'ERR_MODULE_NOT_FOUND') return true;
|
|
48
|
+
// Bun, Deno and the GJS napi shim raise the same condition without Node's
|
|
49
|
+
// code, so the message is a fallback rather than the primary test.
|
|
50
|
+
return typeof message === 'string' && /cannot find module|module not found/i.test(message);
|
|
51
|
+
}
|
|
52
|
+
|
|
16
53
|
/**
|
|
17
54
|
* Turn a failed addon load into something the reader can act on.
|
|
18
55
|
*
|
|
@@ -34,6 +71,27 @@ export function describeAddonLoadFailure(addonPath, err, ctx = {}) {
|
|
|
34
71
|
const target = ctx.target ?? hostTarget();
|
|
35
72
|
const reason = err instanceof Error ? err.message : String(err);
|
|
36
73
|
|
|
74
|
+
// A resolution failure gets no GTK answer. Returning early is what keeps the
|
|
75
|
+
// dependency-closure explanation for the case it actually describes — see
|
|
76
|
+
// isResolutionFailure() for what it cost when the two shared one message.
|
|
77
|
+
if (isResolutionFailure(err)) {
|
|
78
|
+
return [
|
|
79
|
+
`@gjsify/node-gi: the native addon path could not be RESOLVED.`,
|
|
80
|
+
` addon: ${addonPath}`,
|
|
81
|
+
` cause: ${reason}`,
|
|
82
|
+
'',
|
|
83
|
+
`This is a module-RESOLUTION failure, NOT a missing GTK dependency: the`,
|
|
84
|
+
`loader never reached the file, so nothing here is evidence about glib,`,
|
|
85
|
+
`gobject, girepository or a runtime bundle. A path that is neither absolute`,
|
|
86
|
+
`nor written with a leading ./ is resolved by require() as a MODULE`,
|
|
87
|
+
`specifier — against @gjsify/node-gi's own directory and node_modules,`,
|
|
88
|
+
`never against the working directory of the process that set it.`,
|
|
89
|
+
'',
|
|
90
|
+
`Pass an ABSOLUTE path:`,
|
|
91
|
+
` NODE_GI_NATIVE=/absolute/path/to/node_gi.node`,
|
|
92
|
+
].join('\n');
|
|
93
|
+
}
|
|
94
|
+
|
|
37
95
|
const lines = [
|
|
38
96
|
`@gjsify/node-gi: the native addon exists but could not be loaded.`,
|
|
39
97
|
` addon: ${addonPath}`,
|
package/native-paths.js
CHANGED
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
// definitions; this file is the authority for node-gi's own binary, and the third
|
|
27
27
|
// copy is the one that must never be written.
|
|
28
28
|
import { fileURLToPath } from 'node:url';
|
|
29
|
-
import { dirname, join } from 'node:path';
|
|
29
|
+
import { dirname, join, resolve } from 'node:path';
|
|
30
30
|
|
|
31
31
|
/**
|
|
32
32
|
* The package root. This module sits beside `index.js`, so its own directory IS
|
|
@@ -89,6 +89,15 @@ export function buildAddonPath(flavor = 'Release') {
|
|
|
89
89
|
* Default order: prefer a shipped prebuild so a consumer needs no C toolchain and
|
|
90
90
|
* no node-gyp — the only install path Deno supports (it runs no postinstall build
|
|
91
91
|
* script). Fall back to a locally built addon (Release, then Debug).
|
|
92
|
+
*
|
|
93
|
+
* Every candidate is ABSOLUTE, including a pinned one, and that is load-bearing
|
|
94
|
+
* rather than tidiness: `loadNative()` tests a candidate with `existsSync()` (which
|
|
95
|
+
* reads a relative path against the CWD) and hands the SAME string to `require()`
|
|
96
|
+
* (which reads a bare one as a MODULE specifier, against this package's directory).
|
|
97
|
+
* A relative pin therefore passed the check and failed the load. Resolving HERE,
|
|
98
|
+
* where the string enters the package, is what makes the two ask about one file.
|
|
99
|
+
* The incident it cost, and the misdiagnosis it wore: load-diagnostics.js
|
|
100
|
+
* `isResolutionFailure`.
|
|
92
101
|
* @param {Record<string, string | undefined>} [env] defaults to `process.env`
|
|
93
102
|
* @returns {string[]}
|
|
94
103
|
*/
|
|
@@ -99,6 +108,9 @@ export function nativeCandidates(env = process.env) {
|
|
|
99
108
|
const prefer = env.NODE_GI_NATIVE;
|
|
100
109
|
if (prefer === 'build') return [release, debug, prebuild];
|
|
101
110
|
if (prefer === 'prebuild') return [prebuild];
|
|
102
|
-
|
|
111
|
+
// An explicit path to a node_gi.node. `resolve()` keeps an absolute path
|
|
112
|
+
// byte-identical and gives a relative one the cwd meaning `existsSync` would
|
|
113
|
+
// have read into it anyway — so the check and the load name the same file.
|
|
114
|
+
if (prefer) return [resolve(prefer)];
|
|
103
115
|
return [prebuild, release, debug];
|
|
104
116
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gjsify/node-gi",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.42.0",
|
|
4
4
|
"description": "GObject-Introspection runtime for Node.js — load gi:// namespaces (GLib/GObject/Gio/…) with GJS-compatible semantics. Vendored + rewritten from node-gtk under MIT.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/src/class.cc
CHANGED
|
@@ -669,8 +669,6 @@ static void NodeGiClassInit(gpointer g_class, gpointer class_data) {
|
|
|
669
669
|
// return-tuple convention `[returnValue?, ...outArgs]` — one value bare, several as
|
|
670
670
|
// an Array, matching exactly what a JS override of that vfunc receives as its call
|
|
671
671
|
// args. Read-back reuses ReadOutOrReturn (array-length slots, containers, boxed).
|
|
672
|
-
// INOUT containers stay deferred (the same rare, ownership-tricky case the function
|
|
673
|
-
// path defers) with a clear, catchable throw BEFORE the ffi_call.
|
|
674
672
|
//
|
|
675
673
|
// MULTI-LEVEL chain-up (registered chains, G2): chains to the DEEPEST registered
|
|
676
674
|
// override's captured parent (the C-side default below the whole registered chain),
|
package/src/marshal.cc
CHANGED
|
@@ -1736,14 +1736,134 @@ static bool ReadFieldArg(GIFieldInfo* field, gpointer base, GITypeInfo* ftype,
|
|
|
1736
1736
|
return false;
|
|
1737
1737
|
}
|
|
1738
1738
|
|
|
1739
|
-
//
|
|
1740
|
-
//
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1739
|
+
// Field #`index` of a struct/union, or nullptr. The by-NAME lookup is
|
|
1740
|
+
// `FindBoxedField`; this is the by-POSITION one an `array length=` annotation needs.
|
|
1741
|
+
static GIFieldInfo* BoxedFieldAt(GIBaseInfo* owner, unsigned index) {
|
|
1742
|
+
if (GI_IS_STRUCT_INFO(owner)) {
|
|
1743
|
+
GIStructInfo* s = reinterpret_cast<GIStructInfo*>(owner);
|
|
1744
|
+
return index < gi_struct_info_get_n_fields(s) ? gi_struct_info_get_field(s, index) : nullptr;
|
|
1745
|
+
}
|
|
1746
|
+
if (GI_IS_UNION_INFO(owner)) {
|
|
1747
|
+
GIUnionInfo* u = reinterpret_cast<GIUnionInfo*>(owner);
|
|
1748
|
+
return index < gi_union_info_get_n_fields(u) ? gi_union_info_get_field(u, index) : nullptr;
|
|
1749
|
+
}
|
|
1750
|
+
return nullptr;
|
|
1751
|
+
}
|
|
1752
|
+
|
|
1753
|
+
// Can `ReadCElement` actually read this array's elements?
|
|
1754
|
+
//
|
|
1755
|
+
// Resolving a length is only ever an improvement where the reader can then walk that
|
|
1756
|
+
// many elements. Two shapes it cannot: an element tag it answers with `Undefined()`
|
|
1757
|
+
// (its `default:`), and an INLINE (by-value) interface element — for those it
|
|
1758
|
+
// dereferences `src` as a pointer while `CElementSize` reports `sizeof(gpointer)`
|
|
1759
|
+
// rather than the record's real size, so a resolved length walks garbage. Measured:
|
|
1760
|
+
// `new Pango.GlyphString(); gs.set_size(3); gs.glyphs[0].glyph` SIGSEGVs with a
|
|
1761
|
+
// length and returns an empty array without one.
|
|
1762
|
+
//
|
|
1763
|
+
// `calls.cc` draws exactly this line at its own CALLER_ALLOCATES site, with the same
|
|
1764
|
+
// reason recorded there — a by-value element array needs `gi_struct_info_get_size`
|
|
1765
|
+
// per element plus a field-access read-back. That is ONE deferred piece of work, and
|
|
1766
|
+
// this predicate keeps the field path on the same side of it rather than opening a
|
|
1767
|
+
// second, crashing entrance to it.
|
|
1768
|
+
static bool ElementsAreReadable(GITypeInfo* type) {
|
|
1769
|
+
GITypeInfo* elem = gi_type_info_get_param_type(type, 0);
|
|
1770
|
+
if (elem == nullptr) return false;
|
|
1771
|
+
bool readable;
|
|
1772
|
+
switch (gi_type_info_get_tag(elem)) {
|
|
1773
|
+
case GI_TYPE_TAG_BOOLEAN:
|
|
1774
|
+
case GI_TYPE_TAG_INT8:
|
|
1775
|
+
case GI_TYPE_TAG_UINT8:
|
|
1776
|
+
case GI_TYPE_TAG_INT16:
|
|
1777
|
+
case GI_TYPE_TAG_UINT16:
|
|
1778
|
+
case GI_TYPE_TAG_INT32:
|
|
1779
|
+
case GI_TYPE_TAG_UINT32:
|
|
1780
|
+
case GI_TYPE_TAG_INT64:
|
|
1781
|
+
case GI_TYPE_TAG_UINT64:
|
|
1782
|
+
case GI_TYPE_TAG_FLOAT:
|
|
1783
|
+
case GI_TYPE_TAG_DOUBLE:
|
|
1784
|
+
case GI_TYPE_TAG_UTF8:
|
|
1785
|
+
case GI_TYPE_TAG_FILENAME:
|
|
1786
|
+
readable = true;
|
|
1787
|
+
break;
|
|
1788
|
+
// A pointer array of interfaces is a `gpointer` per slot, which is what
|
|
1789
|
+
// `ReadCElement` reads. By value it is the record itself, which is not.
|
|
1790
|
+
case GI_TYPE_TAG_INTERFACE:
|
|
1791
|
+
readable = gi_type_info_is_pointer(elem);
|
|
1792
|
+
break;
|
|
1793
|
+
default:
|
|
1794
|
+
readable = false;
|
|
1795
|
+
break;
|
|
1796
|
+
}
|
|
1797
|
+
gi_base_info_unref(elem);
|
|
1798
|
+
return readable;
|
|
1799
|
+
}
|
|
1800
|
+
|
|
1801
|
+
// The element count for an array FIELD whose GIR carries `array length=<n>`,
|
|
1802
|
+
// meaning "sibling field <n> of this same struct holds it".
|
|
1803
|
+
//
|
|
1804
|
+
// This is the one GIArrayToJs call site that used to pass a hard `-1`, and the cost
|
|
1805
|
+
// was silence: `GstMapInfo.data` is `<array length="3" c:type="guint8*">` with field 3
|
|
1806
|
+
// being `size`, so a mapped 32-byte buffer marshalled as `size=32, data.length=0` — no
|
|
1807
|
+
// error, no warning, an empty array indistinguishable from a genuinely empty one. That
|
|
1808
|
+
// made audio inaudible on node for an entire investigation because every layer above
|
|
1809
|
+
// reported success. gjs reads 32 for the identical struct.
|
|
1810
|
+
//
|
|
1811
|
+
// The ledger entry that recorded this said the dependency was one "GI cannot express
|
|
1812
|
+
// for a struct-field READ". It can, and does: the annotation is in the GIR and survives
|
|
1813
|
+
// into the typelib, which is why the CALL-argument path (`calls.cc`) has resolved it for
|
|
1814
|
+
// as long as it has existed. Only the field reader ignored it.
|
|
1815
|
+
//
|
|
1816
|
+
// Returns false when there is no annotation, when the index is out of range, or when
|
|
1817
|
+
// the sibling is not integer-typed — all of which leave the caller on its previous
|
|
1818
|
+
// zero-terminated/fixed-size derivation rather than inventing a length.
|
|
1819
|
+
static bool FieldArrayLength(GITypeInfo* ftype, GIBaseInfo* owner, gpointer base, long* out) {
|
|
1820
|
+
unsigned int index = 0;
|
|
1821
|
+
if (!gi_type_info_get_array_length_index(ftype, &index)) return false;
|
|
1822
|
+
if (!ElementsAreReadable(ftype)) return false;
|
|
1823
|
+
GIFieldInfo* lengthField = BoxedFieldAt(owner, index);
|
|
1824
|
+
if (lengthField == nullptr) return false;
|
|
1825
|
+
|
|
1826
|
+
bool resolved = false;
|
|
1827
|
+
GITypeInfo* ltype = gi_field_info_get_type_info(lengthField);
|
|
1828
|
+
if (ltype != nullptr) {
|
|
1829
|
+
GIArgument larg;
|
|
1830
|
+
if (ReadFieldArg(lengthField, base, ltype, &larg)) {
|
|
1831
|
+
switch (gi_type_info_get_tag(ltype)) {
|
|
1832
|
+
case GI_TYPE_TAG_INT8: *out = larg.v_int8; resolved = true; break;
|
|
1833
|
+
case GI_TYPE_TAG_UINT8: *out = larg.v_uint8; resolved = true; break;
|
|
1834
|
+
case GI_TYPE_TAG_INT16: *out = larg.v_int16; resolved = true; break;
|
|
1835
|
+
case GI_TYPE_TAG_UINT16: *out = larg.v_uint16; resolved = true; break;
|
|
1836
|
+
case GI_TYPE_TAG_INT32: *out = larg.v_int32; resolved = true; break;
|
|
1837
|
+
case GI_TYPE_TAG_UINT32: *out = static_cast<long>(larg.v_uint32); resolved = true; break;
|
|
1838
|
+
case GI_TYPE_TAG_INT64: *out = static_cast<long>(larg.v_int64); resolved = true; break;
|
|
1839
|
+
case GI_TYPE_TAG_UINT64: *out = static_cast<long>(larg.v_uint64); resolved = true; break;
|
|
1840
|
+
default: break; // non-integer sibling: not a length, leave it alone
|
|
1841
|
+
}
|
|
1842
|
+
}
|
|
1843
|
+
gi_base_info_unref(ltype);
|
|
1844
|
+
}
|
|
1845
|
+
gi_base_info_unref(lengthField);
|
|
1846
|
+
// A signed length field holding a negative value is a broken typelib, not a count.
|
|
1847
|
+
// Declining sends it down the zero-terminated/fixed-size derivation the caller would
|
|
1848
|
+
// have used anyway — which is also what a negative reaching `GIArrayToJs` does, so this
|
|
1849
|
+
// changes no observable behaviour today. It is here to keep the CONTRACT of this
|
|
1850
|
+
// function honest: it returns a resolved element count or nothing.
|
|
1851
|
+
if (resolved && *out < 0) resolved = false;
|
|
1852
|
+
return resolved;
|
|
1853
|
+
}
|
|
1854
|
+
|
|
1855
|
+
// Marshal a field GIArgument to JS. ARRAY tags dispatch to GIArrayToJs with the
|
|
1856
|
+
// length resolved from an `array length=` sibling field where the GIR declares one,
|
|
1857
|
+
// and otherwise derived from zero-terminated / fixed-size (the common GStrv field
|
|
1858
|
+
// case). Everything else goes through GIArgumentToJs. TRANSFER NOTHING throughout —
|
|
1859
|
+
// a field read is a borrow (the container keeps ownership), so the JS value is a copy
|
|
1860
|
+
// and no container/element memory is freed.
|
|
1861
|
+
static Napi::Value FieldArgToJs(Napi::Env env, GITypeInfo* ftype, GIArgument* arg,
|
|
1862
|
+
GIBaseInfo* owner, gpointer base) {
|
|
1745
1863
|
if (gi_type_info_get_tag(ftype) == GI_TYPE_TAG_ARRAY) {
|
|
1746
|
-
|
|
1864
|
+
long length = -1;
|
|
1865
|
+
if (!FieldArrayLength(ftype, owner, base, &length)) length = -1;
|
|
1866
|
+
return GIArrayToJs(env, ftype, arg, GI_TRANSFER_NOTHING, length);
|
|
1747
1867
|
}
|
|
1748
1868
|
return GIArgumentToJs(env, ftype, arg, GI_TRANSFER_NOTHING);
|
|
1749
1869
|
}
|
|
@@ -1854,7 +1974,7 @@ Napi::Value GetBoxedField(const Napi::CallbackInfo& info) {
|
|
|
1854
1974
|
}
|
|
1855
1975
|
GIArgument arg;
|
|
1856
1976
|
if (ReadFieldArg(field, bh->ptr, ftype, &arg)) {
|
|
1857
|
-
result = FieldArgToJs(env, ftype, &arg);
|
|
1977
|
+
result = FieldArgToJs(env, ftype, &arg, ti, bh->ptr);
|
|
1858
1978
|
} else {
|
|
1859
1979
|
Napi::Error::New(env, std::string("Reading field ") + typeName + "." + name + " is not supported")
|
|
1860
1980
|
.ThrowAsJavaScriptException();
|
package/system-gi.js
CHANGED
|
@@ -84,8 +84,14 @@ const PROBED_GI_LIBDIRS = {
|
|
|
84
84
|
darwin: ['/opt/homebrew/lib', '/usr/local/lib', '/opt/local/lib'],
|
|
85
85
|
};
|
|
86
86
|
|
|
87
|
-
/**
|
|
88
|
-
|
|
87
|
+
/**
|
|
88
|
+
* The subdir GI installs typelibs into — historically `1.0` even for the girepository-2.0 API.
|
|
89
|
+
*
|
|
90
|
+
* Exported so `gi-typelib.ts` shares it rather than keeping a third copy of the
|
|
91
|
+
* one string this whole layout rule turns on. Both mirrors export it, so the
|
|
92
|
+
* agreement suite still compares two files that differ only in language.
|
|
93
|
+
*/
|
|
94
|
+
export const TYPELIB_SUBDIR = 'girepository-1.0';
|
|
89
95
|
|
|
90
96
|
/** Memoized `pkg-config` answer: the spawn happens at most once per process. */
|
|
91
97
|
let pkgConfigDirsCache = null;
|