@ts-for-gir/lib 4.0.0-beta.34 → 4.0.0-beta.35
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/package.json +4 -4
- package/src/gir-module.ts +26 -5
- package/src/gir.ts +1 -0
- package/src/injections/inject.ts +1 -0
- package/src/utils/conflicts.ts +137 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ts-for-gir/lib",
|
|
3
|
-
"version": "4.0.0-beta.
|
|
3
|
+
"version": "4.0.0-beta.35",
|
|
4
4
|
"description": "Typescript .d.ts generator from GIR for gjs",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"module": "src/index.ts",
|
|
@@ -48,9 +48,9 @@
|
|
|
48
48
|
"typescript": "^5.9.2"
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
|
-
"@gi.ts/parser": "^4.0.0-beta.
|
|
52
|
-
"@ts-for-gir/reporter": "^4.0.0-beta.
|
|
53
|
-
"@ts-for-gir/templates": "^4.0.0-beta.
|
|
51
|
+
"@gi.ts/parser": "^4.0.0-beta.35",
|
|
52
|
+
"@ts-for-gir/reporter": "^4.0.0-beta.35",
|
|
53
|
+
"@ts-for-gir/templates": "^4.0.0-beta.35",
|
|
54
54
|
"colorette": "^2.0.20",
|
|
55
55
|
"ejs": "^3.1.10",
|
|
56
56
|
"glob": "^11.0.3",
|
package/src/gir-module.ts
CHANGED
|
@@ -469,18 +469,39 @@ export class GirModule implements IGirModule {
|
|
|
469
469
|
const clazzes = Array.from(this.members.values()).filter(
|
|
470
470
|
(m): m is IntrospectedBaseClass => m instanceof IntrospectedBaseClass,
|
|
471
471
|
);
|
|
472
|
-
|
|
472
|
+
|
|
473
|
+
// First, try to handle compound names like "ResultFlatMapFunc" -> "Result.FlatMapFunc"
|
|
474
|
+
// This is the main fix for the Gpseq namespace collision issue
|
|
475
|
+
for (const clazz of clazzes) {
|
|
476
|
+
// Check if the name starts with the class name (compound name pattern)
|
|
477
|
+
if (name.startsWith(clazz.name)) {
|
|
478
|
+
const potentialCallbackName = name.slice(clazz.name.length);
|
|
479
|
+
const callback = clazz.callbacks.find((c) => c.name === potentialCallbackName);
|
|
480
|
+
if (callback) {
|
|
481
|
+
return [clazz.name, callback.name];
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
// Find all matches using the original logic
|
|
487
|
+
const allMatches = clazzes
|
|
473
488
|
.map<[IntrospectedBaseClass, IntrospectedClassCallback | undefined]>((m) => [
|
|
474
489
|
m,
|
|
475
490
|
m.callbacks.find((c) => c.name === name || c.resolve_names.includes(name)),
|
|
476
491
|
])
|
|
477
|
-
.
|
|
492
|
+
.filter((r): r is [IntrospectedBaseClass, IntrospectedClassCallback] => r[1] != null);
|
|
478
493
|
|
|
479
|
-
if (
|
|
480
|
-
return [res[0].name, res[1].name];
|
|
481
|
-
} else {
|
|
494
|
+
if (allMatches.length === 0) {
|
|
482
495
|
return [null, name];
|
|
483
496
|
}
|
|
497
|
+
|
|
498
|
+
// If there are multiple matches, prefer more specific ones
|
|
499
|
+
if (allMatches.length > 1) {
|
|
500
|
+
this.log.warn(`Found multiple matches for ${name}: ${allMatches.map((m) => m[0].name).join(", ")}`);
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
const res = allMatches[0];
|
|
504
|
+
return [res[0].name, res[1].name];
|
|
484
505
|
}
|
|
485
506
|
|
|
486
507
|
/**
|
package/src/gir.ts
CHANGED
package/src/injections/inject.ts
CHANGED
package/src/utils/conflicts.ts
CHANGED
|
@@ -8,6 +8,7 @@ import type { IntrospectedBaseClass } from "../gir/introspected-classes.ts";
|
|
|
8
8
|
import {
|
|
9
9
|
IntrospectedClass,
|
|
10
10
|
IntrospectedClassFunction,
|
|
11
|
+
IntrospectedInterface,
|
|
11
12
|
IntrospectedStaticClassFunction,
|
|
12
13
|
IntrospectedVirtualClassFunction,
|
|
13
14
|
} from "../gir/introspected-classes.ts";
|
|
@@ -391,6 +392,12 @@ function detectConflictType<T extends IntrospectedClassMember | IntrospectedClas
|
|
|
391
392
|
const propertyConflict = checkPropertyConflicts(ns, c, element, thisType);
|
|
392
393
|
if (propertyConflict) return propertyConflict;
|
|
393
394
|
|
|
395
|
+
// Check virtual function signature conflicts (for interfaces)
|
|
396
|
+
if (element instanceof IntrospectedVirtualClassFunction) {
|
|
397
|
+
const vfuncConflict = checkVfuncSignatureConflicts(ns, c, element, thisType);
|
|
398
|
+
if (vfuncConflict) return vfuncConflict;
|
|
399
|
+
}
|
|
400
|
+
|
|
394
401
|
// Check function conflicts
|
|
395
402
|
return checkFunctionNameConflicts(ns, c, element, thisType);
|
|
396
403
|
}
|
|
@@ -476,6 +483,51 @@ function checkFunctionNameConflicts<
|
|
|
476
483
|
);
|
|
477
484
|
}
|
|
478
485
|
|
|
486
|
+
function checkVfuncSignatureConflicts(
|
|
487
|
+
ns: IntrospectedNamespace,
|
|
488
|
+
c: IntrospectedBaseClass,
|
|
489
|
+
element: IntrospectedVirtualClassFunction,
|
|
490
|
+
thisType: TypeIdentifier,
|
|
491
|
+
): ConflictType | undefined {
|
|
492
|
+
// Only check for vfunc conflicts on interfaces
|
|
493
|
+
if (!(c instanceof IntrospectedInterface)) {
|
|
494
|
+
return undefined;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
// Check if this virtual method conflicts with parent class or interface methods
|
|
498
|
+
return c.findParentMap((resolved_parent) => {
|
|
499
|
+
// Look for virtual methods with the same name in parent classes/interfaces
|
|
500
|
+
const parentVirtualMethods = resolved_parent.members.filter(
|
|
501
|
+
(m) => m instanceof IntrospectedVirtualClassFunction && m.name === element.name,
|
|
502
|
+
);
|
|
503
|
+
|
|
504
|
+
for (const parentMethod of parentVirtualMethods) {
|
|
505
|
+
// Check if signatures conflict
|
|
506
|
+
if (isConflictingFunction(ns, thisType, element, resolved_parent.getType(), parentMethod)) {
|
|
507
|
+
return ConflictType.VFUNC_SIGNATURE_CONFLICT;
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
// Also check if the parent is an interface that might have virtual methods from its Interface namespace
|
|
512
|
+
// This is important for cases like List extends Collection where both have vfunc_get_read_only_view
|
|
513
|
+
if (resolved_parent instanceof IntrospectedInterface) {
|
|
514
|
+
// Get the virtual methods from the parent interface
|
|
515
|
+
const parentInterfaceVirtualMethods = resolved_parent.members.filter(
|
|
516
|
+
(m) => m instanceof IntrospectedVirtualClassFunction && m.name === element.name,
|
|
517
|
+
);
|
|
518
|
+
|
|
519
|
+
for (const parentMethod of parentInterfaceVirtualMethods) {
|
|
520
|
+
// Check if signatures conflict between the interfaces
|
|
521
|
+
if (isConflictingFunction(ns, thisType, element, resolved_parent.getType(), parentMethod)) {
|
|
522
|
+
return ConflictType.VFUNC_SIGNATURE_CONFLICT;
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
return undefined;
|
|
528
|
+
});
|
|
529
|
+
}
|
|
530
|
+
|
|
479
531
|
function createConflictElement<T extends IntrospectedClassMember | IntrospectedClassFunction | IntrospectedProperty>(
|
|
480
532
|
element: T,
|
|
481
533
|
conflictType: ConflictType,
|
|
@@ -486,5 +538,90 @@ function createConflictElement<T extends IntrospectedClassMember | IntrospectedC
|
|
|
486
538
|
}) as T;
|
|
487
539
|
}
|
|
488
540
|
|
|
541
|
+
// For VFUNC_SIGNATURE_CONFLICT, we'll handle it differently in the generator
|
|
542
|
+
// Just mark the element so the generator knows to create overloads
|
|
543
|
+
if (conflictType === ConflictType.VFUNC_SIGNATURE_CONFLICT && element instanceof IntrospectedVirtualClassFunction) {
|
|
544
|
+
// Return the element with a marker that will be handled in the generator
|
|
545
|
+
// We don't use TypeConflict here as that causes resolution errors
|
|
546
|
+
return element;
|
|
547
|
+
}
|
|
548
|
+
|
|
489
549
|
return null;
|
|
490
550
|
}
|
|
551
|
+
|
|
552
|
+
/**
|
|
553
|
+
* Check if an interface has virtual methods that conflict with parent class or interface methods.
|
|
554
|
+
* This is used to determine whether to inherit from Interface namespace or generate method overloads.
|
|
555
|
+
*/
|
|
556
|
+
export function hasVfuncSignatureConflicts(ns: IntrospectedNamespace, interfaceClass: IntrospectedInterface): boolean {
|
|
557
|
+
const thisType = interfaceClass.getType();
|
|
558
|
+
const virtualMethods = interfaceClass.members.filter(
|
|
559
|
+
(m) => m instanceof IntrospectedVirtualClassFunction,
|
|
560
|
+
) as IntrospectedVirtualClassFunction[];
|
|
561
|
+
|
|
562
|
+
// If we don't have any virtual methods, no conflicts possible
|
|
563
|
+
if (virtualMethods.length === 0) {
|
|
564
|
+
return false;
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
// Check each virtual method for conflicts with parent classes/interfaces
|
|
568
|
+
for (const vmethod of virtualMethods) {
|
|
569
|
+
const conflictType = checkVfuncSignatureConflicts(ns, interfaceClass, vmethod, thisType);
|
|
570
|
+
if (conflictType === ConflictType.VFUNC_SIGNATURE_CONFLICT) {
|
|
571
|
+
return true;
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
// Check if any parent interface already inherits from its own .Interface namespace
|
|
576
|
+
// If it does, and we have virtual methods with the same name but different signatures,
|
|
577
|
+
// we have a conflict (e.g., List extends Collection, List.Interface and BidirList extends List, BidirList.Interface)
|
|
578
|
+
const hasParentWithVirtualMethods = interfaceClass.someParent((parent) => {
|
|
579
|
+
// Only check parent interfaces (not classes)
|
|
580
|
+
if (!(parent instanceof IntrospectedInterface)) {
|
|
581
|
+
return false;
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
// Check if the parent interface has virtual methods (which means it probably inherits from its .Interface namespace)
|
|
585
|
+
const parentHasVirtualMethods = parent.members.some((m) => m instanceof IntrospectedVirtualClassFunction);
|
|
586
|
+
|
|
587
|
+
if (!parentHasVirtualMethods) {
|
|
588
|
+
return false; // Parent has no virtual methods, no conflict
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
// Check if any of our virtual methods have the same name as parent's virtual methods
|
|
592
|
+
// but with different signatures (especially return types)
|
|
593
|
+
for (const vmethod of virtualMethods) {
|
|
594
|
+
// Find virtual methods with the same name in the parent
|
|
595
|
+
const parentVirtualMethods = parent.members.filter(
|
|
596
|
+
(m) => m instanceof IntrospectedVirtualClassFunction && m.name === vmethod.name,
|
|
597
|
+
) as IntrospectedVirtualClassFunction[];
|
|
598
|
+
|
|
599
|
+
for (const parentMethod of parentVirtualMethods) {
|
|
600
|
+
// For interfaces, even if the return type is a subtype, TypeScript won't allow
|
|
601
|
+
// multiple inheritance from interfaces with the same method but different return types
|
|
602
|
+
// So we need to check if there's any difference in signatures
|
|
603
|
+
// Note: We can't just use isConflictingFunction because it allows subtype relationships
|
|
604
|
+
// but TypeScript doesn't allow that for interface multiple inheritance
|
|
605
|
+
|
|
606
|
+
// Check if return types are different (even if one is a subtype of the other)
|
|
607
|
+
const ourReturn = vmethod.return();
|
|
608
|
+
const parentReturn = parentMethod.return();
|
|
609
|
+
|
|
610
|
+
// Check if return types are not exactly the same
|
|
611
|
+
// For interface inheritance, even subtype relationships cause conflicts
|
|
612
|
+
if (!ourReturn.equals(parentReturn)) {
|
|
613
|
+
return true; // Different return types = conflict
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
// Also check parameters using the existing conflict detection
|
|
617
|
+
if (isConflictingFunction(ns, thisType, vmethod, parent.getType(), parentMethod)) {
|
|
618
|
+
return true;
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
return false;
|
|
624
|
+
});
|
|
625
|
+
|
|
626
|
+
return hasParentWithVirtualMethods;
|
|
627
|
+
}
|