|
10 | 10 | import { expect } from 'chai';
|
11 | 11 | import { describe, it } from 'mocha';
|
12 | 12 | import { parse } from '../parser';
|
| 13 | +import { print } from '../printer'; |
13 | 14 | import { readFileSync } from 'fs';
|
14 |
| -import { visit, visitInParallel, BREAK } from '../visitor'; |
| 15 | +import { visit, visitInParallel, visitWithTypeInfo, BREAK } from '../visitor'; |
15 | 16 | import { join } from 'path';
|
| 17 | +import { TypeInfo } from '../../utilities/TypeInfo'; |
| 18 | +import { testSchema } from '../../validation/__tests__/harness'; |
| 19 | +import { getNamedType, isCompositeType } from '../../type'; |
16 | 20 |
|
17 | 21 |
|
18 | 22 | describe('Visitor', () => {
|
@@ -975,4 +979,197 @@ describe('Visitor', () => {
|
975 | 979 |
|
976 | 980 | });
|
977 | 981 |
|
| 982 | + describe('visitWithTypeInfo', () => { |
| 983 | + |
| 984 | + it('maintains type info during visit', () => { |
| 985 | + const visited = []; |
| 986 | + |
| 987 | + const typeInfo = new TypeInfo(testSchema); |
| 988 | + |
| 989 | + const ast = parse('{ human(id: 4) { name, pets { name }, unknown } }'); |
| 990 | + visit(ast, visitWithTypeInfo(typeInfo, { |
| 991 | + enter(node) { |
| 992 | + let parentType = typeInfo.getParentType(); |
| 993 | + let type = typeInfo.getType(); |
| 994 | + let inputType = typeInfo.getInputType(); |
| 995 | + visited.push([ |
| 996 | + 'enter', |
| 997 | + node.kind, |
| 998 | + node.kind === 'Name' ? node.value : null, |
| 999 | + parentType ? String(parentType) : null, |
| 1000 | + type ? String(type) : null, |
| 1001 | + inputType ? String(inputType) : null |
| 1002 | + ]); |
| 1003 | + }, |
| 1004 | + leave(node) { |
| 1005 | + let parentType = typeInfo.getParentType(); |
| 1006 | + let type = typeInfo.getType(); |
| 1007 | + let inputType = typeInfo.getInputType(); |
| 1008 | + visited.push([ |
| 1009 | + 'leave', |
| 1010 | + node.kind, |
| 1011 | + node.kind === 'Name' ? node.value : null, |
| 1012 | + parentType ? String(parentType) : null, |
| 1013 | + type ? String(type) : null, |
| 1014 | + inputType ? String(inputType) : null |
| 1015 | + ]); |
| 1016 | + } |
| 1017 | + })); |
| 1018 | + |
| 1019 | + expect(visited).to.deep.equal([ |
| 1020 | + [ 'enter', 'Document', null, null, null, null ], |
| 1021 | + [ 'enter', 'OperationDefinition', null, null, 'QueryRoot', null ], |
| 1022 | + [ 'enter', 'SelectionSet', null, 'QueryRoot', 'QueryRoot', null ], |
| 1023 | + [ 'enter', 'Field', null, 'QueryRoot', 'Human', null ], |
| 1024 | + [ 'enter', 'Name', 'human', 'QueryRoot', 'Human', null ], |
| 1025 | + [ 'leave', 'Name', 'human', 'QueryRoot', 'Human', null ], |
| 1026 | + [ 'enter', 'Argument', null, 'QueryRoot', 'Human', 'ID' ], |
| 1027 | + [ 'enter', 'Name', 'id', 'QueryRoot', 'Human', 'ID' ], |
| 1028 | + [ 'leave', 'Name', 'id', 'QueryRoot', 'Human', 'ID' ], |
| 1029 | + [ 'enter', 'IntValue', null, 'QueryRoot', 'Human', 'ID' ], |
| 1030 | + [ 'leave', 'IntValue', null, 'QueryRoot', 'Human', 'ID' ], |
| 1031 | + [ 'leave', 'Argument', null, 'QueryRoot', 'Human', 'ID' ], |
| 1032 | + [ 'enter', 'SelectionSet', null, 'Human', 'Human', null ], |
| 1033 | + [ 'enter', 'Field', null, 'Human', 'String', null ], |
| 1034 | + [ 'enter', 'Name', 'name', 'Human', 'String', null ], |
| 1035 | + [ 'leave', 'Name', 'name', 'Human', 'String', null ], |
| 1036 | + [ 'leave', 'Field', null, 'Human', 'String', null ], |
| 1037 | + [ 'enter', 'Field', null, 'Human', '[Pet]', null ], |
| 1038 | + [ 'enter', 'Name', 'pets', 'Human', '[Pet]', null ], |
| 1039 | + [ 'leave', 'Name', 'pets', 'Human', '[Pet]', null ], |
| 1040 | + [ 'enter', 'SelectionSet', null, 'Pet', '[Pet]', null ], |
| 1041 | + [ 'enter', 'Field', null, 'Pet', 'String', null ], |
| 1042 | + [ 'enter', 'Name', 'name', 'Pet', 'String', null ], |
| 1043 | + [ 'leave', 'Name', 'name', 'Pet', 'String', null ], |
| 1044 | + [ 'leave', 'Field', null, 'Pet', 'String', null ], |
| 1045 | + [ 'leave', 'SelectionSet', null, 'Pet', '[Pet]', null ], |
| 1046 | + [ 'leave', 'Field', null, 'Human', '[Pet]', null ], |
| 1047 | + [ 'enter', 'Field', null, 'Human', null, null ], |
| 1048 | + [ 'enter', 'Name', 'unknown', 'Human', null, null ], |
| 1049 | + [ 'leave', 'Name', 'unknown', 'Human', null, null ], |
| 1050 | + [ 'leave', 'Field', null, 'Human', null, null ], |
| 1051 | + [ 'leave', 'SelectionSet', null, 'Human', 'Human', null ], |
| 1052 | + [ 'leave', 'Field', null, 'QueryRoot', 'Human', null ], |
| 1053 | + [ 'leave', 'SelectionSet', null, 'QueryRoot', 'QueryRoot', null ], |
| 1054 | + [ 'leave', 'OperationDefinition', null, null, 'QueryRoot', null ], |
| 1055 | + [ 'leave', 'Document', null, null, null, null ] |
| 1056 | + ]); |
| 1057 | + }); |
| 1058 | + |
| 1059 | + it('maintains type info during edit', () => { |
| 1060 | + const visited = []; |
| 1061 | + const typeInfo = new TypeInfo(testSchema); |
| 1062 | + |
| 1063 | + const ast = parse( |
| 1064 | + '{ human(id: 4) { name, pets }, alien }' |
| 1065 | + ); |
| 1066 | + const editedAst = visit(ast, visitWithTypeInfo(typeInfo, { |
| 1067 | + enter(node) { |
| 1068 | + let parentType = typeInfo.getParentType(); |
| 1069 | + let type = typeInfo.getType(); |
| 1070 | + let inputType = typeInfo.getInputType(); |
| 1071 | + visited.push([ |
| 1072 | + 'enter', |
| 1073 | + node.kind, |
| 1074 | + node.kind === 'Name' ? node.value : null, |
| 1075 | + parentType ? String(parentType) : null, |
| 1076 | + type ? String(type) : null, |
| 1077 | + inputType ? String(inputType) : null |
| 1078 | + ]); |
| 1079 | + |
| 1080 | + // Make a query valid by adding missing selection sets. |
| 1081 | + if ( |
| 1082 | + node.kind === 'Field' && |
| 1083 | + !node.selectionSet && |
| 1084 | + isCompositeType(getNamedType(type)) |
| 1085 | + ) { |
| 1086 | + return { |
| 1087 | + kind: 'Field', |
| 1088 | + alias: node.alias, |
| 1089 | + name: node.name, |
| 1090 | + arguments: node.arguments, |
| 1091 | + directives: node.directives, |
| 1092 | + selectionSet: { |
| 1093 | + kind: 'SelectionSet', |
| 1094 | + selections: [ |
| 1095 | + { |
| 1096 | + kind: 'Field', |
| 1097 | + name: { kind: 'Name', value: '__typename' } |
| 1098 | + } |
| 1099 | + ] |
| 1100 | + } |
| 1101 | + }; |
| 1102 | + } |
| 1103 | + }, |
| 1104 | + leave(node) { |
| 1105 | + let parentType = typeInfo.getParentType(); |
| 1106 | + let type = typeInfo.getType(); |
| 1107 | + let inputType = typeInfo.getInputType(); |
| 1108 | + visited.push([ |
| 1109 | + 'leave', |
| 1110 | + node.kind, |
| 1111 | + node.kind === 'Name' ? node.value : null, |
| 1112 | + parentType ? String(parentType) : null, |
| 1113 | + type ? String(type) : null, |
| 1114 | + inputType ? String(inputType) : null |
| 1115 | + ]); |
| 1116 | + } |
| 1117 | + })); |
| 1118 | + |
| 1119 | + expect(print(ast)).to.deep.equal(print(parse( |
| 1120 | + '{ human(id: 4) { name, pets }, alien }' |
| 1121 | + ))); |
| 1122 | + |
| 1123 | + expect(print(editedAst)).to.deep.equal(print(parse( |
| 1124 | + '{ human(id: 4) { name, pets { __typename } }, alien { __typename } }' |
| 1125 | + ))); |
| 1126 | + |
| 1127 | + expect(visited).to.deep.equal([ |
| 1128 | + [ 'enter', 'Document', null, null, null, null ], |
| 1129 | + [ 'enter', 'OperationDefinition', null, null, 'QueryRoot', null ], |
| 1130 | + [ 'enter', 'SelectionSet', null, 'QueryRoot', 'QueryRoot', null ], |
| 1131 | + [ 'enter', 'Field', null, 'QueryRoot', 'Human', null ], |
| 1132 | + [ 'enter', 'Name', 'human', 'QueryRoot', 'Human', null ], |
| 1133 | + [ 'leave', 'Name', 'human', 'QueryRoot', 'Human', null ], |
| 1134 | + [ 'enter', 'Argument', null, 'QueryRoot', 'Human', 'ID' ], |
| 1135 | + [ 'enter', 'Name', 'id', 'QueryRoot', 'Human', 'ID' ], |
| 1136 | + [ 'leave', 'Name', 'id', 'QueryRoot', 'Human', 'ID' ], |
| 1137 | + [ 'enter', 'IntValue', null, 'QueryRoot', 'Human', 'ID' ], |
| 1138 | + [ 'leave', 'IntValue', null, 'QueryRoot', 'Human', 'ID' ], |
| 1139 | + [ 'leave', 'Argument', null, 'QueryRoot', 'Human', 'ID' ], |
| 1140 | + [ 'enter', 'SelectionSet', null, 'Human', 'Human', null ], |
| 1141 | + [ 'enter', 'Field', null, 'Human', 'String', null ], |
| 1142 | + [ 'enter', 'Name', 'name', 'Human', 'String', null ], |
| 1143 | + [ 'leave', 'Name', 'name', 'Human', 'String', null ], |
| 1144 | + [ 'leave', 'Field', null, 'Human', 'String', null ], |
| 1145 | + [ 'enter', 'Field', null, 'Human', '[Pet]', null ], |
| 1146 | + [ 'enter', 'Name', 'pets', 'Human', '[Pet]', null ], |
| 1147 | + [ 'leave', 'Name', 'pets', 'Human', '[Pet]', null ], |
| 1148 | + [ 'enter', 'SelectionSet', null, 'Pet', '[Pet]', null ], |
| 1149 | + [ 'enter', 'Field', null, 'Pet', 'String!', null ], |
| 1150 | + [ 'enter', 'Name', '__typename', 'Pet', 'String!', null ], |
| 1151 | + [ 'leave', 'Name', '__typename', 'Pet', 'String!', null ], |
| 1152 | + [ 'leave', 'Field', null, 'Pet', 'String!', null ], |
| 1153 | + [ 'leave', 'SelectionSet', null, 'Pet', '[Pet]', null ], |
| 1154 | + [ 'leave', 'Field', null, 'Human', '[Pet]', null ], |
| 1155 | + [ 'leave', 'SelectionSet', null, 'Human', 'Human', null ], |
| 1156 | + [ 'leave', 'Field', null, 'QueryRoot', 'Human', null ], |
| 1157 | + [ 'enter', 'Field', null, 'QueryRoot', 'Alien', null ], |
| 1158 | + [ 'enter', 'Name', 'alien', 'QueryRoot', 'Alien', null ], |
| 1159 | + [ 'leave', 'Name', 'alien', 'QueryRoot', 'Alien', null ], |
| 1160 | + [ 'enter', 'SelectionSet', null, 'Alien', 'Alien', null ], |
| 1161 | + [ 'enter', 'Field', null, 'Alien', 'String!', null ], |
| 1162 | + [ 'enter', 'Name', '__typename', 'Alien', 'String!', null ], |
| 1163 | + [ 'leave', 'Name', '__typename', 'Alien', 'String!', null ], |
| 1164 | + [ 'leave', 'Field', null, 'Alien', 'String!', null ], |
| 1165 | + [ 'leave', 'SelectionSet', null, 'Alien', 'Alien', null ], |
| 1166 | + [ 'leave', 'Field', null, 'QueryRoot', 'Alien', null ], |
| 1167 | + [ 'leave', 'SelectionSet', null, 'QueryRoot', 'QueryRoot', null ], |
| 1168 | + [ 'leave', 'OperationDefinition', null, null, 'QueryRoot', null ], |
| 1169 | + [ 'leave', 'Document', null, null, null, null ] |
| 1170 | + ]); |
| 1171 | + }); |
| 1172 | + |
| 1173 | + }); |
| 1174 | + |
978 | 1175 | });
|
0 commit comments