11using System ;
2+ using System . Collections . Concurrent ;
23using System . Collections . Generic ;
4+ using System . Diagnostics ;
35using System . Linq ;
46
57namespace Kiota . Builder
@@ -11,20 +13,27 @@ namespace Kiota.Builder
1113 public class CodeBlock : CodeElement
1214 {
1315 public BlockDeclaration StartBlock { get ; set ; }
14- public List < CodeElement > InnerChildElements { get ; set ; } = new List < CodeElement > ( ) ;
16+ protected IDictionary < string , CodeElement > InnerChildElements { get ; private set ; } = new ConcurrentDictionary < string , CodeElement > ( StringComparer . OrdinalIgnoreCase ) ;
1517 public BlockEnd EndBlock { get ; set ; }
1618 public CodeBlock ( CodeElement parent ) : base ( parent )
1719 {
1820 StartBlock = new BlockDeclaration ( this ) ;
1921 EndBlock = new BlockEnd ( this ) ;
2022 }
2123
22- public override IList < CodeElement > GetChildElements ( )
24+ public override IEnumerable < CodeElement > GetChildElements ( bool innerOnly = false )
2325 {
24- var elements = new List < CodeElement > ( InnerChildElements ) ;
25- elements . Insert ( 0 , StartBlock ) ;
26- elements . Add ( EndBlock ) ;
27- return elements ;
26+ if ( innerOnly )
27+ return InnerChildElements . Values ;
28+ else
29+ return new CodeElement [ ] { StartBlock , EndBlock } . Union ( InnerChildElements . Values ) ;
30+ }
31+ public void RemoveChildElement < T > ( params T [ ] elements ) where T : CodeElement {
32+ if ( elements == null ) return ;
33+
34+ foreach ( var element in elements ) {
35+ InnerChildElements . Remove ( element . Name ) ;
36+ }
2837 }
2938 public void AddUsing ( params CodeUsing [ ] codeUsings )
3039 {
@@ -33,24 +42,72 @@ public void AddUsing(params CodeUsing[] codeUsings)
3342 AddMissingParent ( codeUsings ) ;
3443 StartBlock . Usings . AddRange ( codeUsings ) ;
3544 }
36- public T GetChildElementOfType < T > ( Func < T , bool > predicate ) where T : CodeElement {
37- if ( predicate == null )
38- throw new ArgumentNullException ( nameof ( predicate ) ) ;
39- else if ( this is T thisT && predicate ( thisT ) )
40- return thisT ;
41- else if ( this is CodeBlock currentBlock ) {
42- if ( currentBlock . InnerChildElements . OfType < T > ( ) . Any ( predicate ) )
43- return currentBlock . InnerChildElements . OfType < T > ( ) . First ( predicate ) ;
44- else if ( currentBlock . InnerChildElements . OfType < CodeBlock > ( ) . Any ( ) )
45- return currentBlock . InnerChildElements . OfType < CodeBlock > ( )
46- . Select ( x => x . GetChildElementOfType < T > ( predicate ) )
47- . OfType < T > ( )
48- . FirstOrDefault ( ) ;
49- else
50- return null ;
45+ protected IEnumerable < T > AddRange < T > ( params T [ ] elements ) where T : CodeElement {
46+ if ( elements == null ) return Enumerable . Empty < T > ( ) ;
47+ AddMissingParent ( elements ) ;
48+ var innerChildElements = InnerChildElements as ConcurrentDictionary < string , CodeElement > ; // to avoid calling the non thread-safe extension method
49+ var result = new T [ elements . Length ] ; // not using yield return as they'll only get called if the result is assigned
50+
51+ for ( var i = 0 ; i < elements . Length ; i ++ ) {
52+ var element = elements [ i ] ;
53+ var returnedValue = innerChildElements . GetOrAdd ( element . Name , element ) ;
54+ result [ i ] = ( T ) HandleDuplicatedExceptions ( innerChildElements , element , returnedValue ) ;
5155 }
52- else
53- return null ;
56+ return result ;
57+ }
58+ private static CodeElement HandleDuplicatedExceptions ( ConcurrentDictionary < string , CodeElement > innerChildElements , CodeElement element , CodeElement returnedValue ) {
59+ var added = returnedValue == element ;
60+ if ( ! added && element is CodeMethod currentMethod )
61+ if ( currentMethod . MethodKind == CodeMethodKind . IndexerBackwardCompatibility &&
62+ returnedValue is CodeProperty cProp &&
63+ cProp . PropertyKind == CodePropertyKind . RequestBuilder ) {
64+ // indexer retrofited to method in the parent request builder on the path and conflicting with the collection request builder propeerty
65+ returnedValue = innerChildElements . GetOrAdd ( $ "{ element . Name } -indexerbackcompat", element ) ;
66+ added = true ;
67+ } else if ( currentMethod . MethodKind == CodeMethodKind . RequestExecutor ||
68+ currentMethod . MethodKind == CodeMethodKind . RequestGenerator ) {
69+ // allows for methods overload
70+ var methodOverloadNameSuffix = currentMethod . Parameters . Any ( ) ? currentMethod . Parameters . Select ( x => x . Name ) . OrderBy ( x => x ) . Aggregate ( ( x , y ) => x + y ) : "1" ;
71+ returnedValue = innerChildElements . GetOrAdd ( $ "{ element . Name } -{ methodOverloadNameSuffix } ", element ) ;
72+ added = true ;
73+ }
74+
75+ if ( ! added && returnedValue . GetType ( ) != element . GetType ( ) )
76+ throw new InvalidOperationException ( $ "the current dom node already contains a child with name { returnedValue . Name } and of type { returnedValue . GetType ( ) . Name } ") ;
77+
78+ return returnedValue ;
79+ }
80+ public IEnumerable < T > FindChildrenByName < T > ( string childName ) where T : ICodeElement {
81+ if ( string . IsNullOrEmpty ( childName ) )
82+ throw new ArgumentNullException ( nameof ( childName ) ) ;
83+
84+ if ( InnerChildElements . Any ( ) ) {
85+ var result = new List < T > ( ) ;
86+ var immediateResult = this . FindChildByName < T > ( childName , false ) ;
87+ if ( immediateResult != null )
88+ result . Add ( immediateResult ) ;
89+ foreach ( var childElement in InnerChildElements . Values . OfType < CodeBlock > ( ) )
90+ result . AddRange ( childElement . FindChildrenByName < T > ( childName ) ) ;
91+ return result ;
92+ } else
93+ return Enumerable . Empty < T > ( ) ;
94+ }
95+ public T FindChildByName < T > ( string childName , bool findInChildElements = true ) where T : ICodeElement {
96+ if ( string . IsNullOrEmpty ( childName ) )
97+ throw new ArgumentNullException ( nameof ( childName ) ) ;
98+
99+ if ( ! InnerChildElements . Any ( ) )
100+ return default ( T ) ;
101+
102+ if ( InnerChildElements . TryGetValue ( childName , out var result ) && result is T )
103+ return ( T ) ( object ) result ;
104+ else if ( findInChildElements )
105+ foreach ( var childElement in InnerChildElements . Values . OfType < CodeBlock > ( ) ) {
106+ var childResult = childElement . FindChildByName < T > ( childName , true ) ;
107+ if ( childResult != null )
108+ return childResult ;
109+ }
110+ return default ( T ) ;
54111 }
55112 public class BlockDeclaration : CodeTerminal
56113 {
0 commit comments