@@ -2549,8 +2549,8 @@ export function createChecker(program: Program, resolver: NameResolver): Checker
2549
2549
case IdentifierKind . ModelExpressionProperty :
2550
2550
case IdentifierKind . ObjectLiteralProperty :
2551
2551
const model = getReferencedModel ( node as ModelPropertyNode | ObjectLiteralPropertyNode ) ;
2552
- if ( model && ! Array . isArray ( model ) ) {
2553
- sym = getMemberSymbol ( model . node ! . symbol , id . sv ) ;
2552
+ if ( model . length === 1 ) {
2553
+ sym = getMemberSymbol ( model [ 0 ] . node ! . symbol , id . sv ) ;
2554
2554
} else {
2555
2555
return undefined ;
2556
2556
}
@@ -2617,7 +2617,7 @@ export function createChecker(program: Program, resolver: NameResolver): Checker
2617
2617
2618
2618
function getReferencedModel (
2619
2619
propertyNode : ObjectLiteralPropertyNode | ModelPropertyNode ,
2620
- ) : Model | Model [ ] | undefined {
2620
+ ) : Model [ ] {
2621
2621
type ModelOrArrayValueNode = ArrayLiteralNode | ObjectLiteralNode ;
2622
2622
type ModelOrArrayTypeNode = ModelExpressionNode | TupleExpressionNode ;
2623
2623
type ModelOrArrayNode = ModelOrArrayValueNode | ModelOrArrayTypeNode ;
@@ -2661,9 +2661,7 @@ export function createChecker(program: Program, resolver: NameResolver): Checker
2661
2661
break ;
2662
2662
}
2663
2663
2664
- return refType ?. kind === "Model" || refType ?. kind === "Tuple" || refType ?. kind === "Union"
2665
- ? getNestedModel ( refType , path )
2666
- : undefined ;
2664
+ return getNestedModel ( refType , path ) ;
2667
2665
2668
2666
function pushToModelPath ( node : Node , preNode : Node | undefined , path : PathSeg [ ] ) {
2669
2667
if ( node . kind === SyntaxKind . ArrayLiteral || node . kind === SyntaxKind . TupleExpression ) {
@@ -2680,91 +2678,77 @@ export function createChecker(program: Program, resolver: NameResolver): Checker
2680
2678
) {
2681
2679
path . unshift ( { propertyName : node . id . sv } ) ;
2682
2680
}
2683
- if ( node . kind === SyntaxKind . ObjectLiteral ) {
2684
- // define tupleIndex as -1 to indicate that we are looking for union type
2685
- const curResult = path . find ( ( i ) => i . tupleIndex === - 1 ) ;
2686
- if ( curResult === undefined ) {
2687
- path . unshift ( { tupleIndex : - 1 } ) ;
2688
- } else {
2689
- if ( path . length > 1 ) {
2690
- // If it is a specific type in the union type, the previous -1 needs to be deleted
2691
- const removeIdx = path . findIndex ( ( i ) => i . tupleIndex === - 1 ) ;
2692
- if ( removeIdx !== - 1 ) {
2693
- path . splice ( removeIdx , 1 ) ;
2694
- }
2695
- }
2696
- }
2697
- }
2698
2681
}
2699
2682
2700
- function getNestedModel (
2701
- modelOrTuple : Model | Tuple | Union | undefined ,
2702
- path : PathSeg [ ] ,
2703
- ) : Model [ ] | undefined {
2704
- let cur : Type | undefined = modelOrTuple ;
2683
+ function getNestedModel ( modelOrTupleOrUnion : Type | undefined , path : PathSeg [ ] ) : Model [ ] {
2684
+ let cur = modelOrTupleOrUnion ;
2705
2685
const models : Model [ ] = [ ] ;
2706
- for ( const seg of path ) {
2707
- switch ( cur ?. kind ) {
2708
- case "Tuple" :
2709
- if (
2710
- seg . tupleIndex !== undefined &&
2711
- seg . tupleIndex >= 0 &&
2712
- seg . tupleIndex < cur . values . length
2713
- ) {
2714
- cur = cur . values [ seg . tupleIndex ] ;
2715
- } else {
2716
- return undefined ;
2717
- }
2718
- break ;
2719
- case "Model" :
2720
- if ( cur . name === "Array" && seg . tupleIndex !== undefined ) {
2721
- cur = cur . templateMapper ?. args [ 0 ] as Model ;
2722
- } else if ( cur . name !== "Array" && seg . propertyName ) {
2723
- cur = cur . properties . get ( seg . propertyName ) ?. type ;
2724
- if ( cur ?. kind === "Model" ) {
2725
- const result = getNestedModel ( cur , path ) ;
2726
- if ( result ) {
2727
- models . push ( ...result ) ;
2728
- }
2729
- }
2730
- } else if ( seg . tupleIndex === - 1 ) {
2686
+ if ( cur ?. kind === "Model" || cur ?. kind === "Tuple" || cur ?. kind === "Union" ) {
2687
+ if ( path . length <= 0 ) {
2688
+ // Handle union type nesting when path is empty
2689
+ switch ( cur ?. kind ) {
2690
+ case "Model" :
2691
+ models . push ( cur ) ;
2731
2692
for ( const child of cur . properties . values ( ) ) {
2732
2693
if ( child . type . kind === "Model" ) {
2733
- const result = getNestedModel ( child . type , path ) ;
2734
- if ( result ) {
2735
- models . push ( ...result ) ;
2736
- }
2694
+ models . push ( ...( getNestedModel ( child . type , path ) ?? [ ] ) ) ;
2737
2695
}
2738
2696
}
2739
- } else {
2740
- return undefined ;
2741
- }
2742
-
2743
- break ;
2744
- case "Union" :
2745
- if ( seg . tupleIndex === - 1 || seg . propertyName ) {
2746
- // seg.propertyName is empty and contains all,
2747
- // otherwise the value contains the model property corresponding to seg.propertyName
2697
+ return models ;
2698
+ case "Union" :
2748
2699
for ( const variant of cur . variants . values ( ) ) {
2749
- if ( variant . type . kind === "Model" ) {
2750
- const result = getNestedModel ( variant . type , path ) ;
2751
- if ( result ) {
2752
- models . push ( ...result ) ;
2753
- }
2700
+ if ( variant . type . kind === "Model" || variant . type . kind === "Tuple" ) {
2701
+ models . push ( ...( getNestedModel ( variant . type , path ) ?? [ ] ) ) ;
2754
2702
}
2755
2703
}
2704
+ return models ;
2705
+ default :
2706
+ return models ;
2707
+ }
2708
+ } else {
2709
+ for ( const seg of path ) {
2710
+ switch ( cur ?. kind ) {
2711
+ case "Tuple" :
2712
+ if (
2713
+ seg . tupleIndex !== undefined &&
2714
+ seg . tupleIndex >= 0 &&
2715
+ seg . tupleIndex < cur . values . length
2716
+ ) {
2717
+ cur = cur . values [ seg . tupleIndex ] ;
2718
+ } else {
2719
+ return models ;
2720
+ }
2721
+ break ;
2722
+ case "Model" :
2723
+ if ( cur . name === "Array" && seg . tupleIndex !== undefined ) {
2724
+ cur = cur . templateMapper ?. args [ 0 ] as Model ;
2725
+ } else if ( cur . name !== "Array" && seg . propertyName ) {
2726
+ cur = cur . properties . get ( seg . propertyName ) ?. type ;
2727
+ } else {
2728
+ return models ;
2729
+ }
2730
+ break ;
2731
+ case "Union" :
2732
+ // When seg.property name exists, it means that it is in the union model or tuple,
2733
+ // and the corresponding model or tuple needs to be found recursively.
2734
+ for ( const variant of cur . variants . values ( ) ) {
2735
+ if ( variant . type . kind === "Model" || variant . type . kind === "Tuple" ) {
2736
+ models . push ( ...( getNestedModel ( variant . type , path ) ?? [ ] ) ) ;
2737
+ }
2738
+ }
2739
+ break ;
2740
+ default :
2741
+ return models ;
2756
2742
}
2757
- break ;
2758
- default :
2759
- return undefined ;
2760
- }
2761
- }
2743
+ }
2762
2744
2763
- if ( cur ?. kind === "Model" ) {
2764
- models . push ( cur ) ;
2745
+ if ( cur ?. kind === "Model" ) {
2746
+ models . push ( cur ) ;
2747
+ }
2748
+ }
2765
2749
}
2766
2750
2767
- return models . length > 0 ? models : undefined ;
2751
+ return models ;
2768
2752
}
2769
2753
2770
2754
function getReferencedTypeFromTemplateDeclaration ( node : ModelOrArrayNode ) : Type | undefined {
@@ -2957,16 +2941,12 @@ export function createChecker(program: Program, resolver: NameResolver): Checker
2957
2941
kind === IdentifierKind . ObjectLiteralProperty
2958
2942
) {
2959
2943
const model = getReferencedModel ( ancestor as ModelPropertyNode | ObjectLiteralPropertyNode ) ;
2960
- if ( ! model ) {
2944
+ if ( model . length <= 0 ) {
2961
2945
return completions ;
2962
2946
}
2963
2947
const curModelNode = ancestor . parent as ModelExpressionNode | ObjectLiteralNode ;
2964
- if ( Array . isArray ( model ) ) {
2965
- for ( const curModel of model ) {
2966
- addInheritedPropertyCompletions ( curModel , curModelNode ) ;
2967
- }
2968
- } else {
2969
- addInheritedPropertyCompletions ( model , curModelNode ) ;
2948
+ for ( const curModel of model ) {
2949
+ addInheritedPropertyCompletions ( curModel , curModelNode ) ;
2970
2950
}
2971
2951
} else if ( identifier . parent && identifier . parent . kind === SyntaxKind . MemberExpression ) {
2972
2952
let base = resolver . getNodeLinks ( identifier . parent . base ) . resolvedSymbol ;
0 commit comments