@ts-for-gir/cli 4.0.0-rc.5 → 4.0.0-rc.7
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/bin/ts-for-gir +204 -35
- package/dist-templates/types-locally/package.json +1 -1
- package/dist-templates/types-npm/package.json +5 -5
- package/dist-templates/types-workspace/package.json +1 -1
- package/package.json +10 -10
- package/src/commands/run-generation-command.ts +6 -1
- package/src/config/config-loader.ts +50 -3
- package/src/config/defaults.ts +2 -0
- package/src/config/options.ts +23 -0
- package/src/module-loader.ts +46 -14
- package/src/types/command-args.ts +6 -0
package/bin/ts-for-gir
CHANGED
|
@@ -7268,7 +7268,7 @@ import { dirname, join } from "node:path";
|
|
|
7268
7268
|
import { fileURLToPath } from "node:url";
|
|
7269
7269
|
function getPackageVersion() {
|
|
7270
7270
|
if (true) {
|
|
7271
|
-
return "4.0.0-rc.
|
|
7271
|
+
return "4.0.0-rc.7";
|
|
7272
7272
|
}
|
|
7273
7273
|
const currentModulePath = fileURLToPath(import.meta.url);
|
|
7274
7274
|
const currentDir = dirname(currentModulePath);
|
|
@@ -8165,7 +8165,7 @@ import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
|
8165
8165
|
var NEW_LINE_REG_EXP = /[\n\r]+/g;
|
|
8166
8166
|
function getPackageVersion2() {
|
|
8167
8167
|
if (true) {
|
|
8168
|
-
return "4.0.0-rc.
|
|
8168
|
+
return "4.0.0-rc.7";
|
|
8169
8169
|
}
|
|
8170
8170
|
const currentModulePath = fileURLToPath2(import.meta.url);
|
|
8171
8171
|
const currentDir = dirname2(currentModulePath);
|
|
@@ -12726,6 +12726,12 @@ var DependencyManager = class _DependencyManager {
|
|
|
12726
12726
|
};
|
|
12727
12727
|
}
|
|
12728
12728
|
createImportPath(packageName, namespace, version) {
|
|
12729
|
+
if (this.config.externalDeps) {
|
|
12730
|
+
const override3 = this.config.externalPackages?.[namespace];
|
|
12731
|
+
if (override3) return override3;
|
|
12732
|
+
const importName2 = transformImportName(packageName);
|
|
12733
|
+
return `${this.config.npmScope}/${importName2}`;
|
|
12734
|
+
}
|
|
12729
12735
|
if (!this.config.package) {
|
|
12730
12736
|
return `gi://${namespace}?version=${version}`;
|
|
12731
12737
|
}
|
|
@@ -14387,12 +14393,16 @@ var IntrospectedProperty = class _IntrospectedProperty extends IntrospectedBase
|
|
|
14387
14393
|
writable = false;
|
|
14388
14394
|
readable = true;
|
|
14389
14395
|
constructOnly;
|
|
14396
|
+
/** GIR default-value attribute: the default value of the property as a string. */
|
|
14397
|
+
defaultValue;
|
|
14398
|
+
/** GIR getter attribute: name of the getter method for this property (used for nullable inference). */
|
|
14399
|
+
getter;
|
|
14390
14400
|
get namespace() {
|
|
14391
14401
|
return this.parent.namespace;
|
|
14392
14402
|
}
|
|
14393
14403
|
copy(options2) {
|
|
14394
14404
|
const { name, writable, readable, type, constructOnly, parent } = this;
|
|
14395
|
-
|
|
14405
|
+
const prop = new _IntrospectedProperty({
|
|
14396
14406
|
name: options2?.name ?? name,
|
|
14397
14407
|
writable,
|
|
14398
14408
|
readable,
|
|
@@ -14400,6 +14410,9 @@ var IntrospectedProperty = class _IntrospectedProperty extends IntrospectedBase
|
|
|
14400
14410
|
constructOnly,
|
|
14401
14411
|
parent: options2?.parent ?? parent
|
|
14402
14412
|
})._copyBaseProperties(this);
|
|
14413
|
+
prop.defaultValue = this.defaultValue;
|
|
14414
|
+
prop.getter = this.getter;
|
|
14415
|
+
return prop;
|
|
14403
14416
|
}
|
|
14404
14417
|
accept(visitor) {
|
|
14405
14418
|
const node = this.copy({
|
|
@@ -14457,6 +14470,11 @@ var IntrospectedProperty = class _IntrospectedProperty extends IntrospectedBase
|
|
|
14457
14470
|
property.doc = parseDoc(element);
|
|
14458
14471
|
property.metadata = parseMetadata(element);
|
|
14459
14472
|
}
|
|
14473
|
+
property.defaultValue = element.$["default-value"];
|
|
14474
|
+
property.getter = element.$.getter;
|
|
14475
|
+
if (element.$.nullable === "1" || element.$["allow-none"] === "1") {
|
|
14476
|
+
property.type = new NullableType(property.type);
|
|
14477
|
+
}
|
|
14460
14478
|
return property;
|
|
14461
14479
|
}
|
|
14462
14480
|
};
|
|
@@ -14649,6 +14667,28 @@ var IntrospectedSignal = class _IntrospectedSignal extends IntrospectedClassMemb
|
|
|
14649
14667
|
|
|
14650
14668
|
// ../lib/src/gir/introspected-classes.ts
|
|
14651
14669
|
var log = new ConsoleReporter(true, "gir/introspected-classes", true);
|
|
14670
|
+
function hasExtendsShadowOf(cls, prerequisite, name) {
|
|
14671
|
+
let current = cls.resolveParents().extends();
|
|
14672
|
+
while (current) {
|
|
14673
|
+
const node = current.node;
|
|
14674
|
+
if (node !== prerequisite) {
|
|
14675
|
+
const hasOwn = [...node.props, ...node.fields, ...node.members].some((m) => m.name === name);
|
|
14676
|
+
if (hasOwn) return true;
|
|
14677
|
+
}
|
|
14678
|
+
current = current.extends();
|
|
14679
|
+
}
|
|
14680
|
+
return false;
|
|
14681
|
+
}
|
|
14682
|
+
function resolveNullableProperties(cls) {
|
|
14683
|
+
for (const prop of cls.props) {
|
|
14684
|
+
if (prop.type instanceof NullableType) continue;
|
|
14685
|
+
const getterName = prop.getter ?? `get_${prop.name}`;
|
|
14686
|
+
const getter = cls.members.find((m) => m.name === getterName && !(m instanceof IntrospectedStaticClassFunction));
|
|
14687
|
+
if (getter instanceof IntrospectedClassFunction && getter.return() instanceof NullableType) {
|
|
14688
|
+
prop.type = new NullableType(prop.type);
|
|
14689
|
+
}
|
|
14690
|
+
}
|
|
14691
|
+
}
|
|
14652
14692
|
var IntrospectedClassFunction = class _IntrospectedClassFunction extends IntrospectedBase {
|
|
14653
14693
|
parameters;
|
|
14654
14694
|
return_type;
|
|
@@ -14659,6 +14699,8 @@ var IntrospectedClassFunction = class _IntrospectedClassFunction extends Introsp
|
|
|
14659
14699
|
returnTypeDoc;
|
|
14660
14700
|
/** If this function was generated from a signal, stores the signal name. */
|
|
14661
14701
|
signalOrigin;
|
|
14702
|
+
/** GIR glib:finish-func attribute: name of the function that finishes this async operation. */
|
|
14703
|
+
finishFuncName;
|
|
14662
14704
|
generics = [];
|
|
14663
14705
|
constructor({
|
|
14664
14706
|
name,
|
|
@@ -14705,6 +14747,7 @@ var IntrospectedClassFunction = class _IntrospectedClassFunction extends Introsp
|
|
|
14705
14747
|
});
|
|
14706
14748
|
fn.generics = [...this.generics];
|
|
14707
14749
|
fn.returnTypeDoc = this.returnTypeDoc;
|
|
14750
|
+
fn.finishFuncName = this.finishFuncName;
|
|
14708
14751
|
if (interfaceParent) {
|
|
14709
14752
|
fn.interfaceParent = interfaceParent;
|
|
14710
14753
|
}
|
|
@@ -14726,6 +14769,7 @@ var IntrospectedClassFunction = class _IntrospectedClassFunction extends Introsp
|
|
|
14726
14769
|
static fromXML(element, parent, options2) {
|
|
14727
14770
|
const fn = IntrospectedFunction.fromXML(element, parent.namespace, options2);
|
|
14728
14771
|
const { raw_name: name, output_parameters, parameters, return_type, doc: doc2, isIntrospectable: isIntrospectable2 } = fn;
|
|
14772
|
+
const isShadowedBy = element.$["shadowed-by"] != null;
|
|
14729
14773
|
const classFn = new _IntrospectedClassFunction({
|
|
14730
14774
|
parent,
|
|
14731
14775
|
name,
|
|
@@ -14733,10 +14777,11 @@ var IntrospectedClassFunction = class _IntrospectedClassFunction extends Introsp
|
|
|
14733
14777
|
parameters,
|
|
14734
14778
|
return_type,
|
|
14735
14779
|
doc: doc2,
|
|
14736
|
-
isIntrospectable: isIntrospectable2
|
|
14780
|
+
isIntrospectable: isIntrospectable2 && !isShadowedBy
|
|
14737
14781
|
});
|
|
14738
14782
|
classFn.returnTypeDoc = fn.returnTypeDoc;
|
|
14739
14783
|
classFn.generics = [...fn.generics];
|
|
14784
|
+
classFn.finishFuncName = element.$["glib:finish-func"];
|
|
14740
14785
|
return classFn;
|
|
14741
14786
|
}
|
|
14742
14787
|
anyify() {
|
|
@@ -14879,6 +14924,7 @@ var IntrospectedStaticClassFunction = class _IntrospectedStaticClassFunction ext
|
|
|
14879
14924
|
static fromXML(m, parent, options2) {
|
|
14880
14925
|
const fn = IntrospectedFunction.fromXML(m, parent.namespace, options2);
|
|
14881
14926
|
const { raw_name: name, output_parameters, parameters, return_type, doc: doc2, isIntrospectable: isIntrospectable2 } = fn;
|
|
14927
|
+
const isShadowedBy = m.$["shadowed-by"] != null;
|
|
14882
14928
|
return new _IntrospectedStaticClassFunction({
|
|
14883
14929
|
parent,
|
|
14884
14930
|
name,
|
|
@@ -14886,7 +14932,7 @@ var IntrospectedStaticClassFunction = class _IntrospectedStaticClassFunction ext
|
|
|
14886
14932
|
parameters,
|
|
14887
14933
|
return_type,
|
|
14888
14934
|
doc: doc2,
|
|
14889
|
-
isIntrospectable: isIntrospectable2
|
|
14935
|
+
isIntrospectable: isIntrospectable2 && !isShadowedBy
|
|
14890
14936
|
});
|
|
14891
14937
|
}
|
|
14892
14938
|
};
|
|
@@ -15205,6 +15251,7 @@ var IntrospectedClass = class _IntrospectedClass extends IntrospectedBaseClass {
|
|
|
15205
15251
|
if (extended?.node instanceof _IntrospectedClass) {
|
|
15206
15252
|
for (const item of getItems(extended.node)) {
|
|
15207
15253
|
if (items.has(item.name) || !validate3(item)) continue;
|
|
15254
|
+
if (!hasExtendsShadowOf(this, extended.node, item.name)) continue;
|
|
15208
15255
|
items.set(item.name, item);
|
|
15209
15256
|
}
|
|
15210
15257
|
}
|
|
@@ -15342,6 +15389,7 @@ var IntrospectedClass = class _IntrospectedClass extends IntrospectedBaseClass {
|
|
|
15342
15389
|
_IntrospectedClass.parseBasicProperties(element, clazz, ns, options2);
|
|
15343
15390
|
_IntrospectedClass.parseResolveNames(element, clazz, ns, name);
|
|
15344
15391
|
_IntrospectedClass.parseInheritanceAndMembers(element, clazz, ns, options2);
|
|
15392
|
+
resolveNullableProperties(clazz);
|
|
15345
15393
|
return clazz;
|
|
15346
15394
|
}
|
|
15347
15395
|
static parseBasicProperties(element, clazz, ns, options2) {
|
|
@@ -15572,6 +15620,7 @@ var IntrospectedInterface = class _IntrospectedInterface extends IntrospectedBas
|
|
|
15572
15620
|
_IntrospectedInterface.parseInterfaceBasicProperties(element, iface, namespace, options2);
|
|
15573
15621
|
_IntrospectedInterface.parseInterfaceResolveNames(element, iface, namespace, name);
|
|
15574
15622
|
_IntrospectedInterface.parseInterfaceMembers(element, iface, namespace, options2);
|
|
15623
|
+
resolveNullableProperties(iface);
|
|
15575
15624
|
return iface;
|
|
15576
15625
|
}
|
|
15577
15626
|
static parseInterfaceBasicProperties(element, iface, namespace, options2) {
|
|
@@ -15942,9 +15991,7 @@ var IntrospectedFunction = class _IntrospectedFunction extends IntrospectedNames
|
|
|
15942
15991
|
({ allowOptions, params }, p) => {
|
|
15943
15992
|
const { type, isOptional } = p;
|
|
15944
15993
|
if (allowOptions) {
|
|
15945
|
-
if (
|
|
15946
|
-
params.push(p.copy({ isOptional: true }));
|
|
15947
|
-
} else if (!isOptional) {
|
|
15994
|
+
if (!isOptional) {
|
|
15948
15995
|
params.push(p);
|
|
15949
15996
|
return { allowOptions: false, params };
|
|
15950
15997
|
} else {
|
|
@@ -17455,6 +17502,9 @@ function generatePromisifyOverloadedSignatures(node, async_parameters, sync_para
|
|
|
17455
17502
|
}
|
|
17456
17503
|
function findFinishMethodInClass(cls, node) {
|
|
17457
17504
|
const members = node instanceof IntrospectedStaticClassFunction ? [...cls.constructors, ...cls.members.filter((m) => m instanceof IntrospectedStaticClassFunction)] : [...cls.members.filter((m) => !(m instanceof IntrospectedStaticClassFunction))];
|
|
17505
|
+
if (node.finishFuncName) {
|
|
17506
|
+
return members.find((m) => m.name === node.finishFuncName);
|
|
17507
|
+
}
|
|
17458
17508
|
return members.find(
|
|
17459
17509
|
(m) => m.name === `${node.name.replace(/_async$/, "")}_finish` || m.name === `${node.name}_finish`
|
|
17460
17510
|
);
|
|
@@ -20166,6 +20216,14 @@ var fixMissingParent = (node) => {
|
|
|
20166
20216
|
var removeComplexFields = (node) => {
|
|
20167
20217
|
const { namespace } = node;
|
|
20168
20218
|
node.fields = node.fields.filter((f) => {
|
|
20219
|
+
if (f.type instanceof ArrayType) {
|
|
20220
|
+
const elementType = f.type.deepUnwrap();
|
|
20221
|
+
if (elementType instanceof TypeIdentifier) {
|
|
20222
|
+
const classNode = resolveTypeIdentifier(namespace, elementType);
|
|
20223
|
+
return !classNode?.isPrivate;
|
|
20224
|
+
}
|
|
20225
|
+
return true;
|
|
20226
|
+
}
|
|
20169
20227
|
const type = f.type.deepUnwrap();
|
|
20170
20228
|
if (type instanceof NativeType) {
|
|
20171
20229
|
return true;
|
|
@@ -20380,19 +20438,21 @@ var NSRegistry = class {
|
|
|
20380
20438
|
);
|
|
20381
20439
|
}
|
|
20382
20440
|
transform(options2) {
|
|
20383
|
-
const GLib = this.
|
|
20384
|
-
const Gio = this.
|
|
20385
|
-
const GObject = this.
|
|
20386
|
-
Gio.package_version = [...GLib.package_version];
|
|
20387
|
-
GObject.package_version = [...GLib.package_version];
|
|
20441
|
+
const GLib = this.namespace("GLib", "2.0");
|
|
20442
|
+
const Gio = this.namespace("Gio", "2.0");
|
|
20443
|
+
const GObject = this.namespace("GObject", "2.0");
|
|
20444
|
+
if (GLib && Gio) Gio.package_version = [...GLib.package_version];
|
|
20445
|
+
if (GLib && GObject) GObject.package_version = [...GLib.package_version];
|
|
20388
20446
|
const interfaceVisitor = new InterfaceVisitor();
|
|
20389
20447
|
this.registerTransformation(interfaceVisitor);
|
|
20390
20448
|
const classVisitor = new ClassVisitor();
|
|
20391
20449
|
this.registerTransformation(classVisitor);
|
|
20392
|
-
|
|
20393
|
-
|
|
20394
|
-
|
|
20395
|
-
|
|
20450
|
+
if (GLib && Gio) {
|
|
20451
|
+
console.log("Adding generics...");
|
|
20452
|
+
generify(this, options2.inferGenerics);
|
|
20453
|
+
console.log("Injecting types...");
|
|
20454
|
+
inject(this);
|
|
20455
|
+
}
|
|
20396
20456
|
}
|
|
20397
20457
|
defaultVersionOf(name) {
|
|
20398
20458
|
if (name === "GLib" || name === "Gio" || name === "GObject") {
|
|
@@ -20708,7 +20768,7 @@ function checkFunctionConflicts(ns, base, functionElement, conflict_ids, nextTyp
|
|
|
20708
20768
|
return false;
|
|
20709
20769
|
});
|
|
20710
20770
|
});
|
|
20711
|
-
const hasFieldConflicts = checkFieldPropertyConflicts(base, functionElement.name);
|
|
20771
|
+
const hasFieldConflicts = functionElement instanceof IntrospectedStaticClassFunction ? false : checkFieldPropertyConflicts(base, functionElement.name);
|
|
20712
20772
|
const hasGObjectConflicts = checkGObjectConflicts(base, functionElement.name);
|
|
20713
20773
|
const hasConflict = hasParentConflict || hasGObjectConflicts;
|
|
20714
20774
|
return {
|
|
@@ -20942,6 +21002,38 @@ function mergeDescs(descs, comment, indentCount = 1) {
|
|
|
20942
21002
|
return def;
|
|
20943
21003
|
}
|
|
20944
21004
|
|
|
21005
|
+
// ../lib/src/utils/gir-defaults.ts
|
|
21006
|
+
function resolveCEnumConstant(cIdentifier, ns) {
|
|
21007
|
+
const own = ns.enum_constants.get(cIdentifier);
|
|
21008
|
+
if (own) return [ns.namespace, own[0], own[1]];
|
|
21009
|
+
for (const dep of ns.allDependencies) {
|
|
21010
|
+
const depModule = ns.getInstalledImport(dep.namespace);
|
|
21011
|
+
if (!depModule) continue;
|
|
21012
|
+
const entry = depModule.enum_constants.get(cIdentifier);
|
|
21013
|
+
if (entry) return [depModule.namespace, entry[0], entry[1]];
|
|
21014
|
+
}
|
|
21015
|
+
return null;
|
|
21016
|
+
}
|
|
21017
|
+
function convertSingleCValue(value, ns) {
|
|
21018
|
+
const trimmed = value.trim();
|
|
21019
|
+
if (trimmed === "NULL") return "null";
|
|
21020
|
+
if (trimmed === "TRUE") return "true";
|
|
21021
|
+
if (trimmed === "FALSE") return "false";
|
|
21022
|
+
if (/^-?\d+\.\d+$/.test(trimmed)) {
|
|
21023
|
+
const n = parseFloat(trimmed);
|
|
21024
|
+
if (!Number.isNaN(n)) return String(n);
|
|
21025
|
+
}
|
|
21026
|
+
const entry = resolveCEnumConstant(trimmed, ns);
|
|
21027
|
+
if (entry) return `${entry[0]}.${entry[1]}.${entry[2]}`;
|
|
21028
|
+
return trimmed;
|
|
21029
|
+
}
|
|
21030
|
+
function convertCDefaultValue(rawValue, ns) {
|
|
21031
|
+
if (rawValue.includes("|")) {
|
|
21032
|
+
return rawValue.split("|").map((part) => convertSingleCValue(part, ns)).join(" | ");
|
|
21033
|
+
}
|
|
21034
|
+
return convertSingleCValue(rawValue, ns);
|
|
21035
|
+
}
|
|
21036
|
+
|
|
20945
21037
|
// ../lib/src/utils/path.ts
|
|
20946
21038
|
import { dirname as dirname4, resolve as resolve3 } from "node:path";
|
|
20947
21039
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
@@ -20989,6 +21081,8 @@ var defaults = {
|
|
|
20989
21081
|
package: false,
|
|
20990
21082
|
reporter: false,
|
|
20991
21083
|
reporterOutput: "ts-for-gir-report.json",
|
|
21084
|
+
externalDeps: false,
|
|
21085
|
+
allowMissingDeps: false,
|
|
20992
21086
|
combined: true,
|
|
20993
21087
|
/** Default theme for `ts-for-gir doc` (HTML documentation). */
|
|
20994
21088
|
theme: "gi-docgen"
|
|
@@ -21178,6 +21272,23 @@ var options = {
|
|
|
21178
21272
|
description: "Output file path for the reporter (default: ts-for-gir-report.json)",
|
|
21179
21273
|
default: defaults.reporterOutput,
|
|
21180
21274
|
normalize: true
|
|
21275
|
+
},
|
|
21276
|
+
externalDeps: {
|
|
21277
|
+
type: "boolean",
|
|
21278
|
+
description: "Emit imports from installed @girs/* npm packages instead of regenerating dep types. Implies single-file ambient .d.ts output. Designed for project-local Vala/C bridges. Strict by default \u2014 missing transitive dep GIRs abort the run; pass --allow-missing-deps to override.",
|
|
21279
|
+
default: defaults.externalDeps,
|
|
21280
|
+
normalize: true
|
|
21281
|
+
},
|
|
21282
|
+
allowMissingDeps: {
|
|
21283
|
+
type: "boolean",
|
|
21284
|
+
description: "In --external-deps mode, allow generation to proceed when app-specific transitive dep GIRs are missing (e.g. CI without libsoup3-devel). Note: GLib/Gio/GObject GIRs are still architecturally required for class-hierarchy resolution. Default strict behavior prevents silent type-quality drift between environments.",
|
|
21285
|
+
default: defaults.allowMissingDeps,
|
|
21286
|
+
normalize: true
|
|
21287
|
+
},
|
|
21288
|
+
externalPackage: {
|
|
21289
|
+
type: "string",
|
|
21290
|
+
description: "Override the default namespace\u2192npm package mapping for --external-deps mode. Repeatable. Format: 'Namespace=@scope/pkg'. Example: --external-package Soup=@girs/soup-3.0",
|
|
21291
|
+
array: true
|
|
21181
21292
|
}
|
|
21182
21293
|
};
|
|
21183
21294
|
var generateOptions = {
|
|
@@ -21201,7 +21312,10 @@ var generateOptions = {
|
|
|
21201
21312
|
noAdvancedVariants: options.noAdvancedVariants,
|
|
21202
21313
|
package: options.package,
|
|
21203
21314
|
reporter: options.reporter,
|
|
21204
|
-
reporterOutput: options.reporterOutput
|
|
21315
|
+
reporterOutput: options.reporterOutput,
|
|
21316
|
+
externalDeps: options.externalDeps,
|
|
21317
|
+
allowMissingDeps: options.allowMissingDeps,
|
|
21318
|
+
externalPackage: options.externalPackage
|
|
21205
21319
|
};
|
|
21206
21320
|
var listOptions = {
|
|
21207
21321
|
modules: options.modules,
|
|
@@ -21393,6 +21507,18 @@ function getOptionsGeneration(config) {
|
|
|
21393
21507
|
};
|
|
21394
21508
|
return generateConfig;
|
|
21395
21509
|
}
|
|
21510
|
+
function parseExternalPackagePairs(pairs) {
|
|
21511
|
+
if (!pairs || pairs.length === 0) return void 0;
|
|
21512
|
+
const map2 = {};
|
|
21513
|
+
for (const pair of pairs) {
|
|
21514
|
+
const eq = pair.indexOf("=");
|
|
21515
|
+
if (eq < 1) continue;
|
|
21516
|
+
const ns = pair.slice(0, eq).trim();
|
|
21517
|
+
const pkg = pair.slice(eq + 1).trim();
|
|
21518
|
+
if (ns && pkg) map2[ns] = pkg;
|
|
21519
|
+
}
|
|
21520
|
+
return Object.keys(map2).length > 0 ? map2 : void 0;
|
|
21521
|
+
}
|
|
21396
21522
|
function validate2(config) {
|
|
21397
21523
|
return config;
|
|
21398
21524
|
}
|
|
@@ -21410,9 +21536,16 @@ function mergeConfigValue(userConfig, configFileData, key, optionDefault, valida
|
|
|
21410
21536
|
async function load(cliOptions) {
|
|
21411
21537
|
const configFile = await loadConfigFile(cliOptions.configName);
|
|
21412
21538
|
const configFileData = configFile?.config || {};
|
|
21539
|
+
const externalPackagesFromCli = parseExternalPackagePairs(
|
|
21540
|
+
cliOptions.externalPackage
|
|
21541
|
+
);
|
|
21542
|
+
const { externalPackage: _externalPackage, ...cliOptionsClean } = cliOptions;
|
|
21413
21543
|
const userConfig = {
|
|
21414
|
-
...
|
|
21544
|
+
...cliOptionsClean
|
|
21415
21545
|
};
|
|
21546
|
+
if (externalPackagesFromCli) {
|
|
21547
|
+
userConfig.externalPackages = externalPackagesFromCli;
|
|
21548
|
+
}
|
|
21416
21549
|
if (configFileData) {
|
|
21417
21550
|
const booleanKeys = [
|
|
21418
21551
|
["verbose", options.verbose.default],
|
|
@@ -21427,6 +21560,8 @@ async function load(cliOptions) {
|
|
|
21427
21560
|
["noAdvancedVariants", options.noAdvancedVariants.default],
|
|
21428
21561
|
["package", options.package.default],
|
|
21429
21562
|
["reporter", options.reporter.default],
|
|
21563
|
+
["externalDeps", options.externalDeps.default],
|
|
21564
|
+
["allowMissingDeps", options.allowMissingDeps.default],
|
|
21430
21565
|
["combined", docOptions.combined.default],
|
|
21431
21566
|
["merge", docOptions.merge.default]
|
|
21432
21567
|
];
|
|
@@ -21446,13 +21581,19 @@ async function load(cliOptions) {
|
|
|
21446
21581
|
mergeConfigValue(userConfig, configFileData, key, defaultVal);
|
|
21447
21582
|
}
|
|
21448
21583
|
const arrayKeys = [
|
|
21449
|
-
["girDirectories", options.girDirectories.default],
|
|
21450
21584
|
["ignore", options.ignore.default],
|
|
21451
21585
|
["modules", options.modules.default]
|
|
21452
21586
|
];
|
|
21453
21587
|
for (const [key, defaultVal] of arrayKeys) {
|
|
21454
21588
|
mergeConfigValue(userConfig, configFileData, key, defaultVal);
|
|
21455
21589
|
}
|
|
21590
|
+
if (configFileData.girDirectories?.length) {
|
|
21591
|
+
const current = userConfig.girDirectories;
|
|
21592
|
+
const toAdd = configFileData.girDirectories.filter((d) => !current.includes(d));
|
|
21593
|
+
if (toAdd.length > 0) {
|
|
21594
|
+
userConfig.girDirectories = [...toAdd, ...current];
|
|
21595
|
+
}
|
|
21596
|
+
}
|
|
21456
21597
|
if (userConfig.root === options.root.default && (configFileData.root || configFile?.filepath)) {
|
|
21457
21598
|
userConfig.root = configFileData.root || (configFile?.filepath ? dirname5(configFile.filepath) : options.root.default);
|
|
21458
21599
|
}
|
|
@@ -21460,6 +21601,9 @@ async function load(cliOptions) {
|
|
|
21460
21601
|
if (isDefaultOutdir && configFileData.outdir) {
|
|
21461
21602
|
userConfig.outdir = userConfig.print ? null : configFileData.outdir;
|
|
21462
21603
|
}
|
|
21604
|
+
if (!externalPackagesFromCli && configFileData.externalPackages) {
|
|
21605
|
+
userConfig.externalPackages = configFileData.externalPackages;
|
|
21606
|
+
}
|
|
21463
21607
|
}
|
|
21464
21608
|
const resolveToRoot = (path) => path.startsWith("/") ? path : resolve4(userConfig.root, path);
|
|
21465
21609
|
if (userConfig.outdir) {
|
|
@@ -22136,7 +22280,9 @@ var ModuleLoader = class {
|
|
|
22136
22280
|
const girModule = await this.loadAndCreateGirModule(dependency);
|
|
22137
22281
|
if (!girModule) {
|
|
22138
22282
|
if (!failedGirModules.has(dependency.packageName)) {
|
|
22139
|
-
this.
|
|
22283
|
+
if (!this.config.externalDeps) {
|
|
22284
|
+
this.log.warn(WARN_NO_GIR_FILE_FOUND_FOR_PACKAGE(dependency.packageName));
|
|
22285
|
+
}
|
|
22140
22286
|
failedGirModules.add(dependency.packageName);
|
|
22141
22287
|
}
|
|
22142
22288
|
} else if (girModule?.packageName) {
|
|
@@ -22190,18 +22336,33 @@ var ModuleLoader = class {
|
|
|
22190
22336
|
const GObject = await this.dependencyManager.get("GObject", "2.0");
|
|
22191
22337
|
const Cairo = await this.dependencyManager.get("cairo", "1.0");
|
|
22192
22338
|
const dependencies = await this.fileFinder.girFilePathToDependencies(girFiles);
|
|
22339
|
+
const { loaded: forceLoaded, failed: forceFailed } = await this.loadGirModules(
|
|
22340
|
+
[GLib, Gio, GObject, Cairo],
|
|
22341
|
+
ignore,
|
|
22342
|
+
[],
|
|
22343
|
+
0 /* DEPENDENCE */
|
|
22344
|
+
);
|
|
22193
22345
|
const { loaded, failed } = await this.loadGirModules(
|
|
22194
|
-
|
|
22195
|
-
GLib
|
|
22196
|
-
|
|
22197
|
-
|
|
22198
|
-
|
|
22199
|
-
|
|
22200
|
-
|
|
22201
|
-
)
|
|
22202
|
-
],
|
|
22203
|
-
ignore
|
|
22346
|
+
dependencies.filter(
|
|
22347
|
+
(dep) => dep.namespace !== "GLib" && dep.namespace !== "Gio" && dep.namespace !== "GObject" && dep.namespace !== "cairo"
|
|
22348
|
+
),
|
|
22349
|
+
ignore,
|
|
22350
|
+
forceLoaded,
|
|
22351
|
+
1 /* BY_HAND */,
|
|
22352
|
+
forceFailed
|
|
22204
22353
|
);
|
|
22354
|
+
if (this.config.externalDeps && !this.config.allowMissingDeps && failed.size > 0) {
|
|
22355
|
+
const exempt = /* @__PURE__ */ new Set(["GLib-2.0", "Gio-2.0", "GObject-2.0", "cairo-1.0"]);
|
|
22356
|
+
const critical = Array.from(failed).filter((pkg) => !exempt.has(pkg));
|
|
22357
|
+
if (critical.length > 0) {
|
|
22358
|
+
throw new Error(
|
|
22359
|
+
`Missing GIR files for transitive dependencies in --external-deps mode:
|
|
22360
|
+
` + critical.map((pkg) => ` - ${pkg}`).join("\n") + `
|
|
22361
|
+
|
|
22362
|
+
Install the corresponding -devel packages, add their directories to --girDirectories, or pass --allow-missing-deps to generate anyway (warning: degraded type quality).`
|
|
22363
|
+
);
|
|
22364
|
+
}
|
|
22365
|
+
}
|
|
22205
22366
|
let keep = [];
|
|
22206
22367
|
if (doNotAskForVersionOnConflict) {
|
|
22207
22368
|
keep = loaded;
|
|
@@ -23364,6 +23525,12 @@ export const ${node.name}: ${node.name}Namespace & {
|
|
|
23364
23525
|
if (tsProp.constructOnly) propTags.push({ tagName: "construct-only", paramName: "", text: "" });
|
|
23365
23526
|
else if (tsProp.readable && !tsProp.writable) propTags.push({ tagName: "read-only", paramName: "", text: "" });
|
|
23366
23527
|
else if (tsProp.writable && !tsProp.readable) propTags.push({ tagName: "write-only", paramName: "", text: "" });
|
|
23528
|
+
if (tsProp.defaultValue !== void 0)
|
|
23529
|
+
propTags.push({
|
|
23530
|
+
tagName: "default",
|
|
23531
|
+
paramName: "",
|
|
23532
|
+
text: convertCDefaultValue(tsProp.defaultValue, this.namespace)
|
|
23533
|
+
});
|
|
23367
23534
|
desc.push(...this.addGirDocComment(tsProp.doc, propTags, indentCount));
|
|
23368
23535
|
const indent = generateIndent(indentCount);
|
|
23369
23536
|
const name = generateMemberName(tsProp);
|
|
@@ -24548,6 +24715,7 @@ var TypeDefinitionGenerator = class _TypeDefinitionGenerator {
|
|
|
24548
24715
|
}
|
|
24549
24716
|
async exportGjs() {
|
|
24550
24717
|
const { config, dependencyManager } = this;
|
|
24718
|
+
if (config.externalDeps) return;
|
|
24551
24719
|
if (!config.outdir) return;
|
|
24552
24720
|
const gjs2 = dependencyManager.getGjs();
|
|
24553
24721
|
const templateProcessor = new TemplateProcessor(
|
|
@@ -24638,7 +24806,7 @@ ${domContent.append}`, config.outdir, "dom.d.ts");
|
|
|
24638
24806
|
}
|
|
24639
24807
|
async finish(girModules) {
|
|
24640
24808
|
await this.exportGjs();
|
|
24641
|
-
if (!this.config.package) {
|
|
24809
|
+
if (!this.config.package && !this.config.externalDeps) {
|
|
24642
24810
|
await this.exportAllModules(girModules);
|
|
24643
24811
|
}
|
|
24644
24812
|
}
|
|
@@ -27498,7 +27666,7 @@ import { fileURLToPath as fileURLToPath5 } from "node:url";
|
|
|
27498
27666
|
import { i18n, JSX as JSX8, ReflectionKind as ReflectionKind4 } from "typedoc";
|
|
27499
27667
|
function getTsForGirVersion() {
|
|
27500
27668
|
if (true) {
|
|
27501
|
-
return "4.0.0-rc.
|
|
27669
|
+
return "4.0.0-rc.7";
|
|
27502
27670
|
}
|
|
27503
27671
|
const __dirname3 = dirname8(fileURLToPath5(import.meta.url));
|
|
27504
27672
|
return JSON.parse(readFileSync7(join14(__dirname3, "..", "..", "package.json"), "utf8")).version;
|
|
@@ -28204,7 +28372,8 @@ async function runGenerationCommand(args, options2) {
|
|
|
28204
28372
|
}
|
|
28205
28373
|
tsForGir = new GenerationHandler(generateConfig, options2.generatorType, registry);
|
|
28206
28374
|
moduleLoader.parse(keep);
|
|
28207
|
-
const
|
|
28375
|
+
const toGenerate = generateConfig.externalDeps ? keep.filter((m) => m.resolvedBy === 1 /* BY_HAND */) : keep;
|
|
28376
|
+
const girModules = Array.from(toGenerate).map((girModuleResolvedBy) => girModuleResolvedBy.module);
|
|
28208
28377
|
await tsForGir.start(girModules);
|
|
28209
28378
|
} catch (error) {
|
|
28210
28379
|
if (generateConfig.reporter && tsForGir) {
|
|
@@ -14,10 +14,10 @@
|
|
|
14
14
|
"typescript": "^6.0.2"
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@girs/adw-1": "^1.10.0-4.0.0-rc.
|
|
18
|
-
"@girs/gio-2.0": "^2.88.0-4.0.0-rc.
|
|
19
|
-
"@girs/gjs": "^4.0.0-rc.
|
|
20
|
-
"@girs/glib-2.0": "^2.88.0-4.0.0-rc.
|
|
21
|
-
"@girs/gtk-4.0": "^4.23.0-4.0.0-rc.
|
|
17
|
+
"@girs/adw-1": "^1.10.0-4.0.0-rc.6",
|
|
18
|
+
"@girs/gio-2.0": "^2.88.0-4.0.0-rc.6",
|
|
19
|
+
"@girs/gjs": "^4.0.0-rc.6",
|
|
20
|
+
"@girs/glib-2.0": "^2.88.0-4.0.0-rc.6",
|
|
21
|
+
"@girs/gtk-4.0": "^4.23.0-4.0.0-rc.6"
|
|
22
22
|
}
|
|
23
23
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ts-for-gir/cli",
|
|
3
|
-
"version": "4.0.0-rc.
|
|
3
|
+
"version": "4.0.0-rc.7",
|
|
4
4
|
"description": "TypeScript type definition generator for GObject introspection GIR files",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"module": "src/index.ts",
|
|
@@ -55,14 +55,14 @@
|
|
|
55
55
|
".": "./src/index.ts"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
|
-
"@gi.ts/parser": "^4.0.0-rc.
|
|
59
|
-
"@ts-for-gir/generator-base": "^4.0.0-rc.
|
|
60
|
-
"@ts-for-gir/generator-html-doc": "^4.0.0-rc.
|
|
61
|
-
"@ts-for-gir/generator-json": "^4.0.0-rc.
|
|
62
|
-
"@ts-for-gir/generator-typescript": "^4.0.0-rc.
|
|
63
|
-
"@ts-for-gir/lib": "^4.0.0-rc.
|
|
64
|
-
"@ts-for-gir/reporter": "^4.0.0-rc.
|
|
65
|
-
"@ts-for-gir/tsconfig": "^4.0.0-rc.
|
|
58
|
+
"@gi.ts/parser": "^4.0.0-rc.7",
|
|
59
|
+
"@ts-for-gir/generator-base": "^4.0.0-rc.7",
|
|
60
|
+
"@ts-for-gir/generator-html-doc": "^4.0.0-rc.7",
|
|
61
|
+
"@ts-for-gir/generator-json": "^4.0.0-rc.7",
|
|
62
|
+
"@ts-for-gir/generator-typescript": "^4.0.0-rc.7",
|
|
63
|
+
"@ts-for-gir/lib": "^4.0.0-rc.7",
|
|
64
|
+
"@ts-for-gir/reporter": "^4.0.0-rc.7",
|
|
65
|
+
"@ts-for-gir/tsconfig": "^4.0.0-rc.7",
|
|
66
66
|
"@types/ejs": "^3.1.5",
|
|
67
67
|
"@types/inquirer": "^9.0.9",
|
|
68
68
|
"@types/node": "^25.6.0",
|
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
},
|
|
73
73
|
"dependencies": {
|
|
74
74
|
"@inquirer/prompts": "^8.4.2",
|
|
75
|
-
"@ts-for-gir/templates": "^4.0.0-rc.
|
|
75
|
+
"@ts-for-gir/templates": "^4.0.0-rc.7",
|
|
76
76
|
"colorette": "^2.0.20",
|
|
77
77
|
"cosmiconfig": "^9.0.1",
|
|
78
78
|
"ejs": "^5.0.2",
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
Logger,
|
|
7
7
|
NSRegistry,
|
|
8
8
|
ReporterService,
|
|
9
|
+
ResolveType,
|
|
9
10
|
} from "@ts-for-gir/lib";
|
|
10
11
|
import { getOptionsGeneration, load } from "../config.ts";
|
|
11
12
|
import { GenerationHandler } from "../generation-handler.ts";
|
|
@@ -45,7 +46,11 @@ export async function runGenerationCommand(args: ConfigFlags, options: Generatio
|
|
|
45
46
|
|
|
46
47
|
moduleLoader.parse(keep);
|
|
47
48
|
|
|
48
|
-
|
|
49
|
+
// In external-deps mode, only generate the user-requested module(s). Transitively-loaded
|
|
50
|
+
// deps stay in the registry for type resolution but must not produce their own output.
|
|
51
|
+
const toGenerate = generateConfig.externalDeps ? keep.filter((m) => m.resolvedBy === ResolveType.BY_HAND) : keep;
|
|
52
|
+
|
|
53
|
+
const girModules = Array.from(toGenerate).map((girModuleResolvedBy) => girModuleResolvedBy.module as GirModule);
|
|
49
54
|
|
|
50
55
|
await tsForGir.start(girModules);
|
|
51
56
|
} catch (error) {
|
|
@@ -59,6 +59,24 @@ export function getOptionsGeneration(config: UserConfig): OptionsGeneration {
|
|
|
59
59
|
return generateConfig;
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
+
/**
|
|
63
|
+
* Parse `Namespace=npm-package` strings (from repeatable `--external-package` flag) into a
|
|
64
|
+
* map. Silently drops entries that don't contain `=`. Empty input returns undefined so the
|
|
65
|
+
* field stays absent in the merged config (rather than `{}`, which would shadow rc values).
|
|
66
|
+
*/
|
|
67
|
+
function parseExternalPackagePairs(pairs: string[] | undefined): Record<string, string> | undefined {
|
|
68
|
+
if (!pairs || pairs.length === 0) return undefined;
|
|
69
|
+
const map: Record<string, string> = {};
|
|
70
|
+
for (const pair of pairs) {
|
|
71
|
+
const eq = pair.indexOf("=");
|
|
72
|
+
if (eq < 1) continue;
|
|
73
|
+
const ns = pair.slice(0, eq).trim();
|
|
74
|
+
const pkg = pair.slice(eq + 1).trim();
|
|
75
|
+
if (ns && pkg) map[ns] = pkg;
|
|
76
|
+
}
|
|
77
|
+
return Object.keys(map).length > 0 ? map : undefined;
|
|
78
|
+
}
|
|
79
|
+
|
|
62
80
|
/**
|
|
63
81
|
* Validate the configuration
|
|
64
82
|
*/
|
|
@@ -111,9 +129,21 @@ export async function load(cliOptions: ConfigFlags): Promise<UserConfig> {
|
|
|
111
129
|
const configFile = await loadConfigFile(cliOptions.configName);
|
|
112
130
|
const configFileData = configFile?.config || {};
|
|
113
131
|
|
|
132
|
+
// `--external-package GLib=@girs/glib-2.0` arrives as a string[]; collapse to Record.
|
|
133
|
+
// Drop the raw array so it doesn't pollute the merged UserConfig surface.
|
|
134
|
+
const externalPackagesFromCli = parseExternalPackagePairs(
|
|
135
|
+
(cliOptions as { externalPackage?: string[] }).externalPackage,
|
|
136
|
+
);
|
|
137
|
+
const { externalPackage: _externalPackage, ...cliOptionsClean } = cliOptions as ConfigFlags & {
|
|
138
|
+
externalPackage?: string[];
|
|
139
|
+
};
|
|
140
|
+
|
|
114
141
|
const userConfig: UserConfig = {
|
|
115
|
-
...
|
|
142
|
+
...cliOptionsClean,
|
|
116
143
|
};
|
|
144
|
+
if (externalPackagesFromCli) {
|
|
145
|
+
userConfig.externalPackages = externalPackagesFromCli;
|
|
146
|
+
}
|
|
117
147
|
|
|
118
148
|
if (configFileData) {
|
|
119
149
|
// Boolean options — config file overrides CLI defaults
|
|
@@ -130,6 +160,8 @@ export async function load(cliOptions: ConfigFlags): Promise<UserConfig> {
|
|
|
130
160
|
["noAdvancedVariants", options.noAdvancedVariants.default],
|
|
131
161
|
["package", options.package.default],
|
|
132
162
|
["reporter", options.reporter.default],
|
|
163
|
+
["externalDeps", options.externalDeps.default],
|
|
164
|
+
["allowMissingDeps", options.allowMissingDeps.default],
|
|
133
165
|
["combined", docOptions.combined.default],
|
|
134
166
|
["merge", docOptions.merge.default],
|
|
135
167
|
];
|
|
@@ -153,7 +185,6 @@ export async function load(cliOptions: ConfigFlags): Promise<UserConfig> {
|
|
|
153
185
|
|
|
154
186
|
// Array options — config file overrides CLI defaults
|
|
155
187
|
const arrayKeys: Array<[keyof UserConfig, unknown]> = [
|
|
156
|
-
["girDirectories", options.girDirectories.default],
|
|
157
188
|
["ignore", options.ignore.default],
|
|
158
189
|
["modules", options.modules.default],
|
|
159
190
|
];
|
|
@@ -161,6 +192,18 @@ export async function load(cliOptions: ConfigFlags): Promise<UserConfig> {
|
|
|
161
192
|
mergeConfigValue(userConfig, configFileData, key, defaultVal);
|
|
162
193
|
}
|
|
163
194
|
|
|
195
|
+
// girDirectories: rc-file entries are prepended to the current dirs (CLI-provided or
|
|
196
|
+
// system defaults) rather than replacing them. This lets projects add local GIR dirs
|
|
197
|
+
// (e.g. a Vala build output) without having to enumerate all system paths in the rc.
|
|
198
|
+
// To use ONLY the specified dirs (no system fallback), pass --girDirectories on the CLI.
|
|
199
|
+
if (configFileData.girDirectories?.length) {
|
|
200
|
+
const current = userConfig.girDirectories as string[];
|
|
201
|
+
const toAdd = (configFileData.girDirectories as string[]).filter((d) => !current.includes(d));
|
|
202
|
+
if (toAdd.length > 0) {
|
|
203
|
+
userConfig.girDirectories = [...toAdd, ...current];
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
164
207
|
// Special handling for root
|
|
165
208
|
if (userConfig.root === options.root.default && (configFileData.root || configFile?.filepath)) {
|
|
166
209
|
userConfig.root =
|
|
@@ -172,6 +215,11 @@ export async function load(cliOptions: ConfigFlags): Promise<UserConfig> {
|
|
|
172
215
|
if (isDefaultOutdir && configFileData.outdir) {
|
|
173
216
|
userConfig.outdir = userConfig.print ? null : configFileData.outdir;
|
|
174
217
|
}
|
|
218
|
+
|
|
219
|
+
// externalPackages is a Record<string, string> in rc files; CLI overrides take precedence.
|
|
220
|
+
if (!externalPackagesFromCli && configFileData.externalPackages) {
|
|
221
|
+
userConfig.externalPackages = configFileData.externalPackages;
|
|
222
|
+
}
|
|
175
223
|
}
|
|
176
224
|
|
|
177
225
|
// Make paths absolute relative to root
|
|
@@ -186,6 +234,5 @@ export async function load(cliOptions: ConfigFlags): Promise<UserConfig> {
|
|
|
186
234
|
if (userConfig.girDirectories) {
|
|
187
235
|
userConfig.girDirectories = userConfig.girDirectories.map(resolveToRoot);
|
|
188
236
|
}
|
|
189
|
-
|
|
190
237
|
return validate(userConfig);
|
|
191
238
|
}
|
package/src/config/defaults.ts
CHANGED
|
@@ -31,6 +31,8 @@ export const defaults = {
|
|
|
31
31
|
package: false,
|
|
32
32
|
reporter: false,
|
|
33
33
|
reporterOutput: "ts-for-gir-report.json",
|
|
34
|
+
externalDeps: false,
|
|
35
|
+
allowMissingDeps: false,
|
|
34
36
|
combined: true,
|
|
35
37
|
/** Default theme for `ts-for-gir doc` (HTML documentation). */
|
|
36
38
|
theme: "gi-docgen",
|
package/src/config/options.ts
CHANGED
|
@@ -146,6 +146,26 @@ export const options: { [name: string]: Options } = {
|
|
|
146
146
|
default: defaults.reporterOutput,
|
|
147
147
|
normalize: true,
|
|
148
148
|
},
|
|
149
|
+
externalDeps: {
|
|
150
|
+
type: "boolean",
|
|
151
|
+
description:
|
|
152
|
+
"Emit imports from installed @girs/* npm packages instead of regenerating dep types. Implies single-file ambient .d.ts output. Designed for project-local Vala/C bridges. Strict by default — missing transitive dep GIRs abort the run; pass --allow-missing-deps to override.",
|
|
153
|
+
default: defaults.externalDeps,
|
|
154
|
+
normalize: true,
|
|
155
|
+
},
|
|
156
|
+
allowMissingDeps: {
|
|
157
|
+
type: "boolean",
|
|
158
|
+
description:
|
|
159
|
+
"In --external-deps mode, allow generation to proceed when app-specific transitive dep GIRs are missing (e.g. CI without libsoup3-devel). Note: GLib/Gio/GObject GIRs are still architecturally required for class-hierarchy resolution. Default strict behavior prevents silent type-quality drift between environments.",
|
|
160
|
+
default: defaults.allowMissingDeps,
|
|
161
|
+
normalize: true,
|
|
162
|
+
},
|
|
163
|
+
externalPackage: {
|
|
164
|
+
type: "string",
|
|
165
|
+
description:
|
|
166
|
+
"Override the default namespace→npm package mapping for --external-deps mode. Repeatable. Format: 'Namespace=@scope/pkg'. Example: --external-package Soup=@girs/soup-3.0",
|
|
167
|
+
array: true,
|
|
168
|
+
},
|
|
149
169
|
};
|
|
150
170
|
|
|
151
171
|
/**
|
|
@@ -173,6 +193,9 @@ export const generateOptions = {
|
|
|
173
193
|
package: options.package,
|
|
174
194
|
reporter: options.reporter,
|
|
175
195
|
reporterOutput: options.reporterOutput,
|
|
196
|
+
externalDeps: options.externalDeps,
|
|
197
|
+
allowMissingDeps: options.allowMissingDeps,
|
|
198
|
+
externalPackage: options.externalPackage,
|
|
176
199
|
};
|
|
177
200
|
|
|
178
201
|
export const listOptions = {
|
package/src/module-loader.ts
CHANGED
|
@@ -168,7 +168,13 @@ export class ModuleLoader {
|
|
|
168
168
|
const girModule = await this.loadAndCreateGirModule(dependency);
|
|
169
169
|
if (!girModule) {
|
|
170
170
|
if (!failedGirModules.has(dependency.packageName)) {
|
|
171
|
-
|
|
171
|
+
// In external-deps mode the strict check after loading turns missing
|
|
172
|
+
// transitive deps into a hard error; suppress the per-dep warn here so
|
|
173
|
+
// the user sees one consolidated error instead of a wall of warnings.
|
|
174
|
+
// `--allow-missing-deps` opts into the same suppression with a soft fail.
|
|
175
|
+
if (!this.config.externalDeps) {
|
|
176
|
+
this.log.warn(WARN_NO_GIR_FILE_FOUND_FOR_PACKAGE(dependency.packageName));
|
|
177
|
+
}
|
|
172
178
|
failedGirModules.add(dependency.packageName);
|
|
173
179
|
}
|
|
174
180
|
} else if (girModule?.packageName) {
|
|
@@ -239,23 +245,49 @@ export class ModuleLoader {
|
|
|
239
245
|
|
|
240
246
|
const dependencies = await this.fileFinder.girFilePathToDependencies(girFiles);
|
|
241
247
|
|
|
248
|
+
// Load GJS force-loads as DEPENDENCE so they are never treated as user-requested
|
|
249
|
+
// modules. This ensures --external-deps mode doesn't emit output files for them.
|
|
250
|
+
const { loaded: forceLoaded, failed: forceFailed } = await this.loadGirModules(
|
|
251
|
+
[GLib, Gio, GObject, Cairo],
|
|
252
|
+
ignore,
|
|
253
|
+
[],
|
|
254
|
+
ResolveType.DEPENDENCE,
|
|
255
|
+
);
|
|
256
|
+
|
|
257
|
+
// Load user-requested modules (and their transitive deps) starting from the
|
|
258
|
+
// already-loaded force-load registry so they are not double-loaded.
|
|
242
259
|
const { loaded, failed } = await this.loadGirModules(
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
dep.namespace !== "GLib" &&
|
|
251
|
-
dep.namespace !== "Gio" &&
|
|
252
|
-
dep.namespace !== "GObject" &&
|
|
253
|
-
dep.namespace !== "cairo",
|
|
254
|
-
),
|
|
255
|
-
],
|
|
260
|
+
dependencies.filter(
|
|
261
|
+
(dep) =>
|
|
262
|
+
dep.namespace !== "GLib" &&
|
|
263
|
+
dep.namespace !== "Gio" &&
|
|
264
|
+
dep.namespace !== "GObject" &&
|
|
265
|
+
dep.namespace !== "cairo",
|
|
266
|
+
),
|
|
256
267
|
ignore,
|
|
268
|
+
forceLoaded,
|
|
269
|
+
ResolveType.BY_HAND,
|
|
270
|
+
forceFailed,
|
|
257
271
|
);
|
|
258
272
|
|
|
273
|
+
// External-deps mode is strict by default: any transitive dep GIR that couldn't be
|
|
274
|
+
// loaded would silently degrade type quality. The hardcoded GLib/Gio/GObject/cairo
|
|
275
|
+
// force-loads above are exempt (they exist for runtime convenience, not because the
|
|
276
|
+
// input GIR references them).
|
|
277
|
+
if (this.config.externalDeps && !this.config.allowMissingDeps && failed.size > 0) {
|
|
278
|
+
const exempt = new Set(["GLib-2.0", "Gio-2.0", "GObject-2.0", "cairo-1.0"]);
|
|
279
|
+
const critical = Array.from(failed).filter((pkg) => !exempt.has(pkg));
|
|
280
|
+
if (critical.length > 0) {
|
|
281
|
+
throw new Error(
|
|
282
|
+
`Missing GIR files for transitive dependencies in --external-deps mode:\n` +
|
|
283
|
+
critical.map((pkg) => ` - ${pkg}`).join("\n") +
|
|
284
|
+
`\n\nInstall the corresponding -devel packages, add their directories to ` +
|
|
285
|
+
`--girDirectories, or pass --allow-missing-deps to generate anyway ` +
|
|
286
|
+
`(warning: degraded type quality).`,
|
|
287
|
+
);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
259
291
|
let keep: GirModuleResolvedBy[] = [];
|
|
260
292
|
if (doNotAskForVersionOnConflict) {
|
|
261
293
|
keep = loaded;
|
|
@@ -50,6 +50,12 @@ export interface GenerateCommandArgs extends BaseCommandArgs {
|
|
|
50
50
|
reporter: boolean;
|
|
51
51
|
/** Output file path for the reporter */
|
|
52
52
|
reporterOutput: string;
|
|
53
|
+
/** Emit imports from installed @girs/* npm packages instead of regenerating dep types */
|
|
54
|
+
externalDeps: boolean;
|
|
55
|
+
/** Allow externalDeps generation when transitive dep GIRs are missing (degraded type quality) */
|
|
56
|
+
allowMissingDeps: boolean;
|
|
57
|
+
/** Override default namespace→npm package mapping. Repeatable. Format: `Namespace=@girs/pkg` */
|
|
58
|
+
externalPackage?: string[];
|
|
53
59
|
}
|
|
54
60
|
|
|
55
61
|
/**
|