houdini 0.15.1 → 0.15.2

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/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # houdini
2
2
 
3
+ ## 0.15.2
4
+
5
+ ### Patch Changes
6
+
7
+ - [#370](https://github.com/HoudiniGraphql/houdini/pull/370) [`1ce03ec`](https://github.com/HoudiniGraphql/houdini/commit/1ce03ece112bf2688dcc066bdd844fa8b431fe4a) Thanks [@AlecAivazis](https://github.com/AlecAivazis)! - fixed bug when generating type definitions for interfaces mixed on interfaces
8
+
3
9
  ## 0.15.1
4
10
 
5
11
  ### Patch Changes
@@ -60,16 +60,64 @@ function inlineType({ config, filepath, rootType, selections, root, allowReadonl
60
60
  // if we are looking at something with a selection set
61
61
  else if (selections) {
62
62
  const rootObj = type;
63
+ // a selection can contain 1 of 3 things:
64
+ // - a field
65
+ // - an inline fragment
66
+ // - a fragment spread
67
+ // an inline fragment can refer to an interface that's not refered in another
68
+ // fragment so we need to break down all fragments into their concrete versions
69
+ // discriminated by __typename
63
70
  // before we can begin, we need to sort the selection set for this field for
64
71
  // fields defined on the interface as well as subtypes of the interface
65
- const inlineFragments = [];
72
+ const inlineFragments = {};
66
73
  // the rest of the selection can be a single type in the union
67
74
  const selectedFields = [];
68
75
  for (const selection of selections) {
69
76
  // if we found an inline fragment then we have a sub-condition on the fragment
70
- if (selection.kind === 'InlineFragment') {
71
- inlineFragments.push(selection);
77
+ if (selection.kind === 'InlineFragment' && selection.typeCondition) {
78
+ // the type of the fragment
79
+ const fragmentType = config.schema.getType(selection.typeCondition.name.value);
80
+ // if the parent is a non-union or interface then the __typename is only going to have a single
81
+ // value so we just need to add every field to the list
82
+ if (!graphql.isInterfaceType(type) && !graphql.isUnionType(type)) {
83
+ selectedFields.push(...selection.selectionSet.selections);
84
+ continue;
85
+ }
86
+ // the parent type is not concrete so the selections will have to be organized
87
+ // into discriminated and non discriminated parts
88
+ // if the fragment type is not an interface or union, we should just
89
+ // add the selection as part of the discriminated selection
90
+ if (!graphql.isInterfaceType(fragmentType) && !graphql.isUnionType(fragmentType)) {
91
+ // make sure we have to place to put the discriminated type
92
+ if (!inlineFragments[fragmentType.name]) {
93
+ inlineFragments[fragmentType.name] = [];
94
+ }
95
+ inlineFragments[fragmentType.name].push(...selection.selectionSet.selections);
96
+ // we're done processing this type
97
+ continue;
98
+ }
99
+ const possibleParents = config.schema.getPossibleTypes(type).map((t) => t.name);
100
+ // the fragment type is an interface or union and is getting mixed into an interface or union
101
+ // which means every possible type of fragment type needs to be mixed into the discriminated
102
+ // portion for the particular type
103
+ for (const possibleType of config.schema.getPossibleTypes(fragmentType)) {
104
+ // if the possible type is not a possible type of the parent, the intersection isn't possible
105
+ if (!possibleParents.includes(possibleType.name)) {
106
+ continue;
107
+ }
108
+ // make sure we have to place to put the discriminated type
109
+ if (!inlineFragments[possibleType.name]) {
110
+ inlineFragments[possibleType.name] = [];
111
+ }
112
+ // add the selection to the discriminated object of the intersecting type
113
+ inlineFragments[possibleType.name].push(...selection.selectionSet.selections);
114
+ }
115
+ }
116
+ // an inline fragment without a selection is just a fancy way of asking for fields
117
+ else if (selection.kind === 'InlineFragment' && !selection.typeCondition) {
118
+ selectedFields.push(...selection.selectionSet.selections);
72
119
  }
120
+ // the selection is just a normal field, add it to the non-discriminated object
73
121
  else {
74
122
  selectedFields.push(selection);
75
123
  }
@@ -105,12 +153,7 @@ function inlineType({ config, filepath, rootType, selections, root, allowReadonl
105
153
  }
106
154
  // if we are mixing in inline fragments, we need to a union of the possible options,
107
155
  // discriminated by the value of __typename
108
- const inlineFragmentSelections = inlineFragments.flatMap((fragment) => {
109
- // look up the type pointed by the type condition
110
- if (!fragment.typeCondition) {
111
- return [];
112
- }
113
- const typeName = fragment.typeCondition.name.value;
156
+ const inlineFragmentSelections = Object.entries(inlineFragments).flatMap(([typeName, fragment]) => {
114
157
  const fragmentRootType = config.schema.getType(typeName);
115
158
  if (!fragmentRootType) {
116
159
  return [];
@@ -120,7 +163,7 @@ function inlineType({ config, filepath, rootType, selections, root, allowReadonl
120
163
  config,
121
164
  filepath,
122
165
  rootType: fragmentRootType,
123
- selections: fragment.selectionSet.selections,
166
+ selections: fragment,
124
167
  allowReadonly,
125
168
  visitedTypes,
126
169
  root,
@@ -153,34 +196,14 @@ function inlineType({ config, filepath, rootType, selections, root, allowReadonl
153
196
  // we're done massaging the type
154
197
  return [{ type: fragmentRootType, tsType: fragmentType }];
155
198
  });
156
- if (inlineFragmentSelections.length > 0) {
157
- // these fragments could refer to types, unions, or interfaces
158
- // only mix the relevant ones
159
- const interfaceFragments = inlineFragmentSelections.filter(({ type }) => graphql.isInterfaceType(type));
160
- const unionFragments = inlineFragmentSelections.filter(({ type }) => graphql.isUnionType(type));
161
- const concreteFragments = inlineFragmentSelections.filter(({ type }) => {
162
- // look up the type in the schema
163
- return !graphql.isUnionType(type) && !graphql.isInterfaceType(type);
164
- });
165
- // build up the discriminated type
166
- let selectionTypes = concreteFragments.map(({ type, tsType }) => {
199
+ //
200
+ if (Object.keys(inlineFragmentSelections).length > 0) {
201
+ // // build up the discriminated type
202
+ let selectionTypes = Object.entries(inlineFragmentSelections).map(([typeName, { type, tsType }]) => {
167
203
  // the selection for a concrete type is really the intersection of itself
168
204
  // with every abstract type it implements. go over every fragment belonging
169
205
  // to an abstract type and check if this type implements it.
170
206
  return AST.tsParenthesizedType(AST.tsIntersectionType([tsType]
171
- // include the interface fragment if the concrete type implements it
172
- .concat(interfaceFragments
173
- .filter(({ type: abstractType }) => config.schema
174
- .getImplementations(abstractType)
175
- .objects.map(({ name }) => name)
176
- .includes(type.name))
177
- .map(({ tsType }) => tsType))
178
- // include the union fragment if the concrete type is a member
179
- .concat(unionFragments
180
- .filter(({ type }) => {
181
- return true;
182
- })
183
- .map(({ tsType }) => tsType))
184
207
  // remove any inner nullability flags
185
208
  .flatMap((type) => {
186
209
  // if we are looking at a union we might have nulls in there
@@ -196,7 +219,6 @@ function inlineType({ config, filepath, rootType, selections, root, allowReadonl
196
219
  result,
197
220
  AST.tsParenthesizedType(AST.tsUnionType(selectionTypes)),
198
221
  ]);
199
- // if we're supposed to leave a nullable type behind
200
222
  }
201
223
  }
202
224
  // we shouldn't get here
package/build/cmd.js CHANGED
@@ -72951,7 +72951,7 @@ export * from "${definitionsDir}"
72951
72951
 
72952
72952
  async function metaGenerator(config) {
72953
72953
  const meta = {
72954
- version: '0.15.1',
72954
+ version: '0.15.2',
72955
72955
  };
72956
72956
  await writeFile(config.metaFilePath, JSON.stringify(meta));
72957
72957
  }
@@ -73128,16 +73128,64 @@ function inlineType({ config, filepath, rootType, selections, root, allowReadonl
73128
73128
  // if we are looking at something with a selection set
73129
73129
  else if (selections) {
73130
73130
  const rootObj = type;
73131
+ // a selection can contain 1 of 3 things:
73132
+ // - a field
73133
+ // - an inline fragment
73134
+ // - a fragment spread
73135
+ // an inline fragment can refer to an interface that's not refered in another
73136
+ // fragment so we need to break down all fragments into their concrete versions
73137
+ // discriminated by __typename
73131
73138
  // before we can begin, we need to sort the selection set for this field for
73132
73139
  // fields defined on the interface as well as subtypes of the interface
73133
- const inlineFragments = [];
73140
+ const inlineFragments = {};
73134
73141
  // the rest of the selection can be a single type in the union
73135
73142
  const selectedFields = [];
73136
73143
  for (const selection of selections) {
73137
73144
  // if we found an inline fragment then we have a sub-condition on the fragment
73138
- if (selection.kind === 'InlineFragment') {
73139
- inlineFragments.push(selection);
73145
+ if (selection.kind === 'InlineFragment' && selection.typeCondition) {
73146
+ // the type of the fragment
73147
+ const fragmentType = config.schema.getType(selection.typeCondition.name.value);
73148
+ // if the parent is a non-union or interface then the __typename is only going to have a single
73149
+ // value so we just need to add every field to the list
73150
+ if (!graphql.isInterfaceType(type) && !graphql.isUnionType(type)) {
73151
+ selectedFields.push(...selection.selectionSet.selections);
73152
+ continue;
73153
+ }
73154
+ // the parent type is not concrete so the selections will have to be organized
73155
+ // into discriminated and non discriminated parts
73156
+ // if the fragment type is not an interface or union, we should just
73157
+ // add the selection as part of the discriminated selection
73158
+ if (!graphql.isInterfaceType(fragmentType) && !graphql.isUnionType(fragmentType)) {
73159
+ // make sure we have to place to put the discriminated type
73160
+ if (!inlineFragments[fragmentType.name]) {
73161
+ inlineFragments[fragmentType.name] = [];
73162
+ }
73163
+ inlineFragments[fragmentType.name].push(...selection.selectionSet.selections);
73164
+ // we're done processing this type
73165
+ continue;
73166
+ }
73167
+ const possibleParents = config.schema.getPossibleTypes(type).map((t) => t.name);
73168
+ // the fragment type is an interface or union and is getting mixed into an interface or union
73169
+ // which means every possible type of fragment type needs to be mixed into the discriminated
73170
+ // portion for the particular type
73171
+ for (const possibleType of config.schema.getPossibleTypes(fragmentType)) {
73172
+ // if the possible type is not a possible type of the parent, the intersection isn't possible
73173
+ if (!possibleParents.includes(possibleType.name)) {
73174
+ continue;
73175
+ }
73176
+ // make sure we have to place to put the discriminated type
73177
+ if (!inlineFragments[possibleType.name]) {
73178
+ inlineFragments[possibleType.name] = [];
73179
+ }
73180
+ // add the selection to the discriminated object of the intersecting type
73181
+ inlineFragments[possibleType.name].push(...selection.selectionSet.selections);
73182
+ }
73183
+ }
73184
+ // an inline fragment without a selection is just a fancy way of asking for fields
73185
+ else if (selection.kind === 'InlineFragment' && !selection.typeCondition) {
73186
+ selectedFields.push(...selection.selectionSet.selections);
73140
73187
  }
73188
+ // the selection is just a normal field, add it to the non-discriminated object
73141
73189
  else {
73142
73190
  selectedFields.push(selection);
73143
73191
  }
@@ -73173,12 +73221,7 @@ function inlineType({ config, filepath, rootType, selections, root, allowReadonl
73173
73221
  }
73174
73222
  // if we are mixing in inline fragments, we need to a union of the possible options,
73175
73223
  // discriminated by the value of __typename
73176
- const inlineFragmentSelections = inlineFragments.flatMap((fragment) => {
73177
- // look up the type pointed by the type condition
73178
- if (!fragment.typeCondition) {
73179
- return [];
73180
- }
73181
- const typeName = fragment.typeCondition.name.value;
73224
+ const inlineFragmentSelections = Object.entries(inlineFragments).flatMap(([typeName, fragment]) => {
73182
73225
  const fragmentRootType = config.schema.getType(typeName);
73183
73226
  if (!fragmentRootType) {
73184
73227
  return [];
@@ -73188,7 +73231,7 @@ function inlineType({ config, filepath, rootType, selections, root, allowReadonl
73188
73231
  config,
73189
73232
  filepath,
73190
73233
  rootType: fragmentRootType,
73191
- selections: fragment.selectionSet.selections,
73234
+ selections: fragment,
73192
73235
  allowReadonly,
73193
73236
  visitedTypes,
73194
73237
  root,
@@ -73221,34 +73264,14 @@ function inlineType({ config, filepath, rootType, selections, root, allowReadonl
73221
73264
  // we're done massaging the type
73222
73265
  return [{ type: fragmentRootType, tsType: fragmentType }];
73223
73266
  });
73224
- if (inlineFragmentSelections.length > 0) {
73225
- // these fragments could refer to types, unions, or interfaces
73226
- // only mix the relevant ones
73227
- const interfaceFragments = inlineFragmentSelections.filter(({ type }) => graphql.isInterfaceType(type));
73228
- const unionFragments = inlineFragmentSelections.filter(({ type }) => graphql.isUnionType(type));
73229
- const concreteFragments = inlineFragmentSelections.filter(({ type }) => {
73230
- // look up the type in the schema
73231
- return !graphql.isUnionType(type) && !graphql.isInterfaceType(type);
73232
- });
73233
- // build up the discriminated type
73234
- let selectionTypes = concreteFragments.map(({ type, tsType }) => {
73267
+ //
73268
+ if (Object.keys(inlineFragmentSelections).length > 0) {
73269
+ // // build up the discriminated type
73270
+ let selectionTypes = Object.entries(inlineFragmentSelections).map(([typeName, { type, tsType }]) => {
73235
73271
  // the selection for a concrete type is really the intersection of itself
73236
73272
  // with every abstract type it implements. go over every fragment belonging
73237
73273
  // to an abstract type and check if this type implements it.
73238
73274
  return AST$2.tsParenthesizedType(AST$2.tsIntersectionType([tsType]
73239
- // include the interface fragment if the concrete type implements it
73240
- .concat(interfaceFragments
73241
- .filter(({ type: abstractType }) => config.schema
73242
- .getImplementations(abstractType)
73243
- .objects.map(({ name }) => name)
73244
- .includes(type.name))
73245
- .map(({ tsType }) => tsType))
73246
- // include the union fragment if the concrete type is a member
73247
- .concat(unionFragments
73248
- .filter(({ type }) => {
73249
- return true;
73250
- })
73251
- .map(({ tsType }) => tsType))
73252
73275
  // remove any inner nullability flags
73253
73276
  .flatMap((type) => {
73254
73277
  // if we are looking at a union we might have nulls in there
@@ -73264,7 +73287,6 @@ function inlineType({ config, filepath, rootType, selections, root, allowReadonl
73264
73287
  result,
73265
73288
  AST$2.tsParenthesizedType(AST$2.tsUnionType(selectionTypes)),
73266
73289
  ]);
73267
- // if we're supposed to leave a nullable type behind
73268
73290
  }
73269
73291
  }
73270
73292
  // we shouldn't get here
@@ -74631,7 +74653,7 @@ async function runPipeline(config, docs) {
74631
74653
  }
74632
74654
  catch { }
74633
74655
  // if the previous version is different from the current version
74634
- const versionChanged = previousVersion && previousVersion !== '0.15.1';
74656
+ const versionChanged = previousVersion && previousVersion !== '0.15.2';
74635
74657
  await runPipeline$1(config, [
74636
74658
  typeCheck,
74637
74659
  uniqueDocumentNames,
@@ -74658,7 +74680,7 @@ async function runPipeline(config, docs) {
74658
74680
  if (config.logLevel === LogLevel.Quiet) ;
74659
74681
  else if (versionChanged) {
74660
74682
  console.log('💣 Detected new version of Houdini. Regenerating all documents...');
74661
- console.log('🎉 Welcome to 0.15.1!');
74683
+ console.log('🎉 Welcome to 0.15.2!');
74662
74684
  // if the user is coming from a version pre-15, point them to the migration guide
74663
74685
  const major = parseInt(previousVersion.split('.')[1]);
74664
74686
  if (major < 15) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "houdini",
3
- "version": "0.15.1",
3
+ "version": "0.15.2",
4
4
  "description": "The disappearing graphql client for SvelteKit",
5
5
  "workspaces": [
6
6
  "example",
@@ -62,17 +62,77 @@ export function inlineType({
62
62
  else if (selections) {
63
63
  const rootObj = type as graphql.GraphQLObjectType<any, any>
64
64
 
65
+ // a selection can contain 1 of 3 things:
66
+ // - a field
67
+ // - an inline fragment
68
+ // - a fragment spread
69
+
70
+ // an inline fragment can refer to an interface that's not refered in another
71
+ // fragment so we need to break down all fragments into their concrete versions
72
+ // discriminated by __typename
73
+
65
74
  // before we can begin, we need to sort the selection set for this field for
66
75
  // fields defined on the interface as well as subtypes of the interface
67
- const inlineFragments: graphql.InlineFragmentNode[] = []
76
+ const inlineFragments: { [typeName: string]: graphql.SelectionNode[] } = {}
68
77
  // the rest of the selection can be a single type in the union
69
78
  const selectedFields: graphql.SelectionNode[] = []
70
79
 
71
80
  for (const selection of selections) {
72
81
  // if we found an inline fragment then we have a sub-condition on the fragment
73
- if (selection.kind === 'InlineFragment') {
74
- inlineFragments.push(selection)
75
- } else {
82
+ if (selection.kind === 'InlineFragment' && selection.typeCondition) {
83
+ // the type of the fragment
84
+ const fragmentType = config.schema.getType(selection.typeCondition.name.value)!
85
+
86
+ // if the parent is a non-union or interface then the __typename is only going to have a single
87
+ // value so we just need to add every field to the list
88
+ if (!graphql.isInterfaceType(type) && !graphql.isUnionType(type)) {
89
+ selectedFields.push(...selection.selectionSet.selections)
90
+ continue
91
+ }
92
+
93
+ // the parent type is not concrete so the selections will have to be organized
94
+ // into discriminated and non discriminated parts
95
+
96
+ // if the fragment type is not an interface or union, we should just
97
+ // add the selection as part of the discriminated selection
98
+ if (!graphql.isInterfaceType(fragmentType) && !graphql.isUnionType(fragmentType)) {
99
+ // make sure we have to place to put the discriminated type
100
+ if (!inlineFragments[fragmentType.name]) {
101
+ inlineFragments[fragmentType.name] = []
102
+ }
103
+
104
+ inlineFragments[fragmentType.name].push(...selection.selectionSet.selections)
105
+
106
+ // we're done processing this type
107
+ continue
108
+ }
109
+
110
+ const possibleParents = config.schema.getPossibleTypes(type).map((t) => t.name)
111
+
112
+ // the fragment type is an interface or union and is getting mixed into an interface or union
113
+ // which means every possible type of fragment type needs to be mixed into the discriminated
114
+ // portion for the particular type
115
+ for (const possibleType of config.schema.getPossibleTypes(fragmentType)) {
116
+ // if the possible type is not a possible type of the parent, the intersection isn't possible
117
+ if (!possibleParents.includes(possibleType.name)) {
118
+ continue
119
+ }
120
+
121
+ // make sure we have to place to put the discriminated type
122
+ if (!inlineFragments[possibleType.name]) {
123
+ inlineFragments[possibleType.name] = []
124
+ }
125
+
126
+ // add the selection to the discriminated object of the intersecting type
127
+ inlineFragments[possibleType.name].push(...selection.selectionSet.selections)
128
+ }
129
+ }
130
+ // an inline fragment without a selection is just a fancy way of asking for fields
131
+ else if (selection.kind === 'InlineFragment' && !selection.typeCondition) {
132
+ selectedFields.push(...selection.selectionSet.selections)
133
+ }
134
+ // the selection is just a normal field, add it to the non-discriminated object
135
+ else {
76
136
  selectedFields.push(selection)
77
137
  }
78
138
  }
@@ -151,12 +211,7 @@ export function inlineType({
151
211
  const inlineFragmentSelections: {
152
212
  type: graphql.GraphQLNamedType
153
213
  tsType: TSTypeKind
154
- }[] = inlineFragments.flatMap((fragment: graphql.InlineFragmentNode) => {
155
- // look up the type pointed by the type condition
156
- if (!fragment.typeCondition) {
157
- return []
158
- }
159
- const typeName = fragment.typeCondition.name.value
214
+ }[] = Object.entries(inlineFragments).flatMap(([typeName, fragment]) => {
160
215
  const fragmentRootType = config.schema.getType(typeName)
161
216
  if (!fragmentRootType) {
162
217
  return []
@@ -167,7 +222,7 @@ export function inlineType({
167
222
  config,
168
223
  filepath,
169
224
  rootType: fragmentRootType,
170
- selections: fragment.selectionSet.selections,
225
+ selections: fragment,
171
226
  allowReadonly,
172
227
  visitedTypes,
173
228
  root,
@@ -217,72 +272,40 @@ export function inlineType({
217
272
  // we're done massaging the type
218
273
  return [{ type: fragmentRootType, tsType: fragmentType }]
219
274
  })
220
- if (inlineFragmentSelections.length > 0) {
221
- // these fragments could refer to types, unions, or interfaces
222
- // only mix the relevant ones
223
- const interfaceFragments = inlineFragmentSelections.filter(({ type }) =>
224
- graphql.isInterfaceType(type)
225
- )
226
- const unionFragments = inlineFragmentSelections.filter(({ type }) =>
227
- graphql.isUnionType(type)
228
- )
229
- const concreteFragments = inlineFragmentSelections.filter(({ type }) => {
230
- // look up the type in the schema
231
- return !graphql.isUnionType(type) && !graphql.isInterfaceType(type)
232
- })
233
275
 
234
- // build up the discriminated type
235
- let selectionTypes = concreteFragments.map(({ type, tsType }) => {
236
- // the selection for a concrete type is really the intersection of itself
237
- // with every abstract type it implements. go over every fragment belonging
238
- // to an abstract type and check if this type implements it.
239
- return AST.tsParenthesizedType(
240
- AST.tsIntersectionType(
241
- [tsType]
242
- // include the interface fragment if the concrete type implements it
243
- .concat(
244
- interfaceFragments
245
- .filter(({ type: abstractType }) =>
246
- config.schema
247
- .getImplementations(
248
- abstractType as graphql.GraphQLInterfaceType
249
- )
250
- .objects.map(({ name }) => name)
251
- .includes(type.name)
252
- )
253
- .map(({ tsType }) => tsType)
254
- )
255
- // include the union fragment if the concrete type is a member
256
- .concat(
257
- unionFragments
258
- .filter(({ type }) => {
259
- return true
260
- })
261
- .map(({ tsType }) => tsType)
262
- )
263
- // remove any inner nullability flags
264
- .flatMap((type) => {
265
- // if we are looking at a union we might have nulls in there
266
- if (type.type === 'TSUnionType') {
267
- return type.types.filter(
268
- (innerType) =>
269
- innerType.type !== 'TSNullKeyword' &&
270
- innerType.type !== 'TSUndefinedKeyword'
271
- )
272
- }
273
-
274
- return type
275
- })
276
+ //
277
+ if (Object.keys(inlineFragmentSelections).length > 0) {
278
+ // // build up the discriminated type
279
+ let selectionTypes = Object.entries(inlineFragmentSelections).map(
280
+ ([typeName, { type, tsType }]) => {
281
+ // the selection for a concrete type is really the intersection of itself
282
+ // with every abstract type it implements. go over every fragment belonging
283
+ // to an abstract type and check if this type implements it.
284
+ return AST.tsParenthesizedType(
285
+ AST.tsIntersectionType(
286
+ [tsType]
287
+ // remove any inner nullability flags
288
+ .flatMap((type) => {
289
+ // if we are looking at a union we might have nulls in there
290
+ if (type.type === 'TSUnionType') {
291
+ return type.types.filter(
292
+ (innerType) =>
293
+ innerType.type !== 'TSNullKeyword' &&
294
+ innerType.type !== 'TSUndefinedKeyword'
295
+ )
296
+ }
297
+ return type
298
+ })
299
+ )
276
300
  )
277
- )
278
- })
301
+ }
302
+ )
279
303
 
280
304
  // build up the list of fragment types
281
305
  result = AST.tsIntersectionType([
282
306
  result,
283
307
  AST.tsParenthesizedType(AST.tsUnionType(selectionTypes)),
284
308
  ])
285
- // if we're supposed to leave a nullable type behind
286
309
  }
287
310
  }
288
311
  // we shouldn't get here