1
- import { ParserField , ParserTree , TypeSystemDefinition } from '@/Models' ;
1
+ import { ParserField , ParserTree , TypeDefinition , TypeSystemDefinition } from '@/Models' ;
2
2
import { Parser } from '@/Parser' ;
3
+ import { mergeArguments } from '@/TreeOperations/merge/arguments' ;
4
+ import { MergeError , ErrorConflict } from '@/TreeOperations/merge/common' ;
3
5
import { isExtensionNode } from '@/TreeOperations/shared' ;
4
6
import { TreeToGraphQL } from '@/TreeToGraphQL' ;
5
- import { generateNodeId } from '@/shared' ;
7
+ import { generateNodeId , getTypeName } from '@/shared' ;
6
8
9
+ const detectConflictOnBaseNode = ( n1 : ParserField , n2 : ParserField ) => {
10
+ if ( n1 . data . type !== n2 . data . type )
11
+ throw new MergeError ( {
12
+ conflictingNode : n1 . name ,
13
+ message : `Data type conflict of nodes ${ n1 . name } and ${ n2 . name } ` ,
14
+ } ) ;
15
+ if ( JSON . stringify ( n1 . interfaces ) !== JSON . stringify ( n2 . interfaces ) )
16
+ throw new MergeError ( {
17
+ conflictingNode : n1 . name ,
18
+ message : `Data type conflict of nodes ${ n1 . name } and ${ n2 . name } ` ,
19
+ } ) ;
20
+ } ;
21
+
22
+ const detectConflictOnFieldNode = ( parentName : string , f1 : ParserField , f2 : ParserField ) => {
23
+ const [ f1Type , f2Type ] = [ getTypeName ( f1 . type . fieldType ) , getTypeName ( f2 . type . fieldType ) ] ;
24
+ if ( f1Type !== f2Type )
25
+ throw new MergeError ( {
26
+ conflictingNode : parentName ,
27
+ conflictingField : f1 . name ,
28
+ message : `Data type conflict of node ${ parentName } field ${ f1 . name } ` ,
29
+ } ) ;
30
+ } ;
7
31
const addFromLibrary = ( n : ParserField ) : ParserField => ( { ...n , fromLibrary : true } ) ;
8
32
33
+ const mergeFields = ( parentName : string , fields1 : ParserField [ ] , fields2 : ParserField [ ] ) => {
34
+ const mergedCommonFieldsAndF1Fields = fields1
35
+ . map ( ( f1 ) => {
36
+ const commonField = fields2 . find ( ( f2 ) => f2 . name === f1 . name ) ;
37
+ if ( ! commonField ) return f1 ;
38
+ detectConflictOnFieldNode ( parentName , f1 , commonField ) ;
39
+ const mergedField : ParserField = {
40
+ ...f1 ,
41
+ args : mergeArguments ( f1 . name , f1 . args , commonField . args ) ,
42
+ } ;
43
+ return mergedField ;
44
+ } )
45
+ . filter ( < T > ( f : T | undefined ) : f is T => ! ! f ) ;
46
+ const otherF2Fields = fields2 . filter ( ( f2 ) => ! fields1 . find ( ( f1 ) => f1 . name === f2 . name ) ) ;
47
+ return [ ...mergedCommonFieldsAndF1Fields , ...otherF2Fields ] ;
48
+ } ;
49
+
9
50
const mergeNode = ( n1 : ParserField , n2 : ParserField ) => {
10
- const args = [ ...n1 . args , ...n2 . args . map ( addFromLibrary ) ] ;
51
+ detectConflictOnBaseNode ( n1 , n2 ) ;
52
+ const args =
53
+ n1 . data . type === TypeDefinition . InputObjectTypeDefinition
54
+ ? mergeArguments ( n1 . name , n1 . args , n2 . args )
55
+ : mergeFields ( n1 . name , n1 . args , n2 . args . map ( addFromLibrary ) ) ;
56
+
11
57
const mergedNode = {
12
58
...n1 ,
13
59
id : generateNodeId ( n1 . name , n1 . data . type , args ) ,
14
60
args,
15
61
directives : [ ...n1 . directives , ...n2 . directives . map ( addFromLibrary ) ] ,
16
62
interfaces : [ ...n1 . interfaces , ...n2 . interfaces ] ,
17
63
} as ParserField ;
18
- //dedupe
19
- mergedNode . args = mergedNode . args . filter ( ( a , i ) => mergedNode . args . findIndex ( ( aa ) => aa . name === a . name ) === i ) ;
64
+
20
65
mergedNode . directives = mergedNode . directives . filter (
21
66
( a , i ) => mergedNode . directives . findIndex ( ( aa ) => aa . name === a . name ) === i ,
22
67
) ;
@@ -30,7 +75,7 @@ export const mergeTrees = (tree1: ParserTree, tree2: ParserTree) => {
30
75
const mergedNodesT1 : ParserField [ ] = [ ] ;
31
76
const mergedNodesT2 : ParserField [ ] = [ ] ;
32
77
const mergeResultNodes : ParserField [ ] = [ ] ;
33
- const errors : Array < { conflictingNode : string ; conflictingField : string } > = [ ] ;
78
+ const errors : Array < ErrorConflict > = [ ] ;
34
79
const filteredTree2Nodes = tree2 . nodes . filter ( ( t ) => t . data . type !== TypeSystemDefinition . SchemaDefinition ) ;
35
80
// merge nodes
36
81
tree1 . nodes . forEach ( ( t1n ) => {
@@ -48,23 +93,19 @@ export const mergeTrees = (tree1: ParserTree, tree2: ParserTree) => {
48
93
}
49
94
}
50
95
} ) ;
51
- } else {
52
- // Check if arg named same and different typings -> throw
53
- mergedNodesT1 . push ( t1n ) ;
54
- mergedNodesT2 . push ( matchingNode ) ;
55
- t1n . args . forEach ( ( t1nA ) => {
56
- const matchingArg = matchingNode . args . find ( ( mNA ) => mNA . name === t1nA . name ) ;
57
- if ( matchingArg ) {
58
- if ( JSON . stringify ( matchingArg ) !== JSON . stringify ( t1nA ) ) {
59
- errors . push ( {
60
- conflictingField : t1nA . name ,
61
- conflictingNode : t1n . name ,
62
- } ) ;
63
- }
64
- }
65
- } ) ;
66
- if ( ! errors . length ) {
67
- mergeResultNodes . push ( mergeNode ( t1n , matchingNode ) ) ;
96
+ return ;
97
+ }
98
+ mergedNodesT1 . push ( t1n ) ;
99
+ mergedNodesT2 . push ( matchingNode ) ;
100
+ try {
101
+ const mergeNodeResult = mergeNode ( t1n , matchingNode ) ;
102
+ mergeResultNodes . push ( mergeNodeResult ) ;
103
+ } catch ( error ) {
104
+ if ( error instanceof MergeError ) {
105
+ errors . push ( {
106
+ conflictingNode : error . errorParams . conflictingNode ,
107
+ conflictingField : error . errorParams . conflictingField ,
108
+ } ) ;
68
109
}
69
110
}
70
111
}
0 commit comments