Skip to content

Commit aed906a

Browse files
authored
Add json-modern target and typeNodes to output
Adds a json-modern target to the codegen command that is similar to the json target, but with the addition of ast type nodes to the output.
1 parent af5885e commit aed906a

10 files changed

Lines changed: 262 additions & 27 deletions

File tree

package-lock.json

Lines changed: 21 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import { parse } from "graphql";
2+
3+
import { loadSchema } from "../../loading";
4+
5+
import { compileToIR } from "../";
6+
7+
const schema = loadSchema(
8+
require.resolve("../../../../../__fixtures__/starwars/schema.json")
9+
);
10+
11+
describe("Compiling query documents to modern IR with typeNodes", () => {
12+
it(`should print IR with typeNodes on fields`, () => {
13+
const document = parse(`
14+
query HeroName($episode: Episode) {
15+
hero(episode: $episode) {
16+
name
17+
...withId
18+
}
19+
}
20+
21+
query Search($text: String!) {
22+
search(text: $text) {
23+
... on Character {
24+
name
25+
}
26+
}
27+
}
28+
29+
mutation CreateReviewForEpisode($episode: Episode!, $review: ReviewInput!) {
30+
createReview(episode: $episode, review: $review) {
31+
stars
32+
commentary
33+
}
34+
}
35+
36+
fragment withId on Character {
37+
id
38+
}
39+
`);
40+
41+
const { operations } = compileToIR(schema, document);
42+
43+
expect(
44+
operations["HeroName"].selectionSet.selections[0].selectionSet
45+
.selections[0].typeNode
46+
).toEqual({
47+
kind: "NonNullType",
48+
type: {
49+
kind: "NamedType",
50+
name: {
51+
kind: "Name",
52+
value: "String"
53+
}
54+
}
55+
});
56+
57+
expect(operations["HeroName"].variables[0].typeNode).toEqual({
58+
kind: "NamedType",
59+
name: {
60+
kind: "Name",
61+
value: "Episode"
62+
}
63+
});
64+
65+
expect(operations["Search"].variables[0].typeNode).toEqual({
66+
kind: "NonNullType",
67+
type: {
68+
kind: "NamedType",
69+
name: {
70+
kind: "Name",
71+
value: "String"
72+
}
73+
}
74+
});
75+
76+
expect(
77+
operations["Search"].selectionSet.selections[0].selectionSet.selections[0]
78+
.typeNode
79+
).toEqual({
80+
kind: "NamedType",
81+
name: { kind: "Name", value: "Character" }
82+
});
83+
84+
expect(
85+
operations["CreateReviewForEpisode"].selectionSet.selections[0]
86+
.selectionSet.selections[0].typeNode
87+
).toEqual({
88+
kind: "NonNullType",
89+
type: { kind: "NamedType", name: { kind: "Name", value: "Int" } }
90+
});
91+
});
92+
});

packages/apollo-codegen-core/src/compiler/__tests__/legacyIR.ts

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,6 @@
11
import { stripIndent } from "common-tags";
22

3-
import {
4-
parse,
5-
isType,
6-
GraphQLID,
7-
GraphQLString,
8-
GraphQLList,
9-
GraphQLNonNull
10-
} from "graphql";
3+
import { parse } from "graphql";
114

125
import { loadSchema } from "../../loading";
136

packages/apollo-codegen-core/src/compiler/index.ts

Lines changed: 56 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,11 @@ import {
2222
GraphQLNonNull,
2323
isEnumType,
2424
isInputObjectType,
25-
isScalarType
25+
isScalarType,
26+
NamedTypeNode,
27+
ListTypeNode,
28+
TypeNode,
29+
parseType
2630
} from "graphql";
2731

2832
import {
@@ -48,6 +52,7 @@ export interface CompilerOptions {
4852
useReadOnlyTypes?: boolean;
4953
suppressSwiftMultilineStringLiterals?: boolean;
5054
omitDeprecatedEnumCases?: boolean;
55+
exposeTypeNodes?: boolean;
5156
}
5257

5358
export interface CompilerContext {
@@ -65,6 +70,7 @@ export interface Operation {
6570
variables: {
6671
name: string;
6772
type: GraphQLType;
73+
typeNode?: TypeNode;
6874
}[];
6975
filePath: string;
7076
source: string;
@@ -77,6 +83,7 @@ export interface Fragment {
7783
fragmentName: string;
7884
source: string;
7985
type: GraphQLCompositeType;
86+
typeNode?: TypeNode;
8087
selectionSet: SelectionSet;
8188
}
8289

@@ -89,6 +96,7 @@ export interface Argument {
8996
name: string;
9097
value: any;
9198
type?: GraphQLInputType;
99+
typeNode?: TypeNode;
92100
}
93101

94102
export type Selection =
@@ -104,6 +112,7 @@ export interface Field {
104112
alias?: string;
105113
args?: Argument[];
106114
type: GraphQLOutputType;
115+
typeNode?: TypeNode;
107116
description?: string;
108117
isDeprecated?: boolean;
109118
deprecationReason?: string;
@@ -114,6 +123,7 @@ export interface Field {
114123
export interface TypeCondition {
115124
kind: "TypeCondition";
116125
type: GraphQLCompositeType;
126+
typeNode?: TypeNode;
117127
selectionSet: SelectionSet;
118128
}
119129

@@ -131,10 +141,23 @@ export interface FragmentSpread {
131141
selectionSet: SelectionSet;
132142
}
133143

144+
export function stripProp(propName: string, obj: Object) {
145+
let cloned = JSON.parse(JSON.stringify(obj));
146+
for (let prop in cloned) {
147+
if (prop === propName) delete cloned[prop];
148+
else if (typeof cloned[prop] === "object") {
149+
cloned[prop] = stripProp(propName, cloned[prop]);
150+
}
151+
}
152+
return cloned;
153+
}
154+
134155
export function compileToIR(
135156
schema: GraphQLSchema,
136157
document: DocumentNode,
137-
options: CompilerOptions = {}
158+
options: CompilerOptions = {
159+
exposeTypeNodes: true
160+
}
138161
): CompilerContext {
139162
if (options.addTypename) {
140163
document = withTypenameFieldAddedWhereNeeded(document);
@@ -235,7 +258,15 @@ class Compiler {
235258
const name = node.variable.name.value;
236259
const type = typeFromAST(this.schema, node.type as NonNullTypeNode);
237260
this.addTypeUsed(getNamedType(type as GraphQLType));
238-
return { name, type: type as GraphQLNonNull<any> };
261+
const typeNode =
262+
this.options.exposeTypeNodes && type
263+
? stripProp("loc", parseType(type.toString()))
264+
: undefined;
265+
return {
266+
name,
267+
type: type as GraphQLNonNull<any>,
268+
typeNode
269+
};
239270
}
240271
);
241272

@@ -270,6 +301,10 @@ class Compiler {
270301
fragmentDefinition.typeCondition
271302
) as GraphQLCompositeType;
272303

304+
const typeNode = this.options.exposeTypeNodes
305+
? stripProp("loc", parseType(type.toString()))
306+
: undefined;
307+
273308
return {
274309
fragmentName,
275310
filePath,
@@ -278,7 +313,8 @@ class Compiler {
278313
selectionSet: this.compileSelectionSet(
279314
fragmentDefinition.selectionSet,
280315
type
281-
)
316+
),
317+
typeNode
282318
};
283319
}
284320

@@ -329,8 +365,11 @@ class Compiler {
329365
}
330366

331367
const fieldType = fieldDef.type;
332-
const unmodifiedFieldType = getNamedType(fieldType);
368+
const typeNode = this.options.exposeTypeNodes
369+
? stripProp("loc", parseType(fieldType.toString()))
370+
: undefined;
333371

372+
const unmodifiedFieldType = getNamedType(fieldType);
334373
this.addTypeUsed(unmodifiedFieldType);
335374

336375
const { description, isDeprecated, deprecationReason } = fieldDef;
@@ -344,10 +383,16 @@ class Compiler {
344383
const argDef = fieldDef.args.find(
345384
argDef => argDef.name === arg.name.value
346385
);
386+
const argDefType = (argDef && argDef.type) || undefined;
387+
const argDeftypeNode =
388+
this.options.exposeTypeNodes && argDefType
389+
? stripProp("loc", parseType(argDefType.toString()))
390+
: undefined;
347391
return {
348392
name,
349393
value: valueFromValueNode(arg.value),
350-
type: (argDef && argDef.type) || undefined
394+
type: argDefType,
395+
typeNode: argDeftypeNode
351396
};
352397
})
353398
: undefined;
@@ -359,6 +404,7 @@ class Compiler {
359404
alias,
360405
args,
361406
type: fieldType,
407+
typeNode,
362408
description:
363409
!isMetaFieldName(name) && description ? description : undefined,
364410
isDeprecated,
@@ -391,9 +437,13 @@ class Compiler {
391437
const possibleTypesForTypeCondition = this.possibleTypesForType(
392438
type
393439
).filter(type => possibleTypes.includes(type));
440+
const typeConditiontypeNode = this.options.exposeTypeNodes
441+
? stripProp("loc", parseType(type.toString()))
442+
: undefined;
394443
return {
395444
kind: "TypeCondition",
396445
type,
446+
typeNode: typeConditiontypeNode,
397447
selectionSet: this.compileSelectionSet(
398448
selectionNode.selectionSet,
399449
type,

packages/apollo-codegen-core/src/compiler/legacyIR.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export interface CompilerOptions {
2929
customScalarsPrefix?: string;
3030
namespace?: string;
3131
generateOperationIds?: boolean;
32+
exposeRawTypes?: boolean;
3233
}
3334

3435
export interface LegacyCompilerContext {
@@ -104,7 +105,10 @@ export interface Argument {
104105
export function compileToLegacyIR(
105106
schema: GraphQLSchema,
106107
document: DocumentNode,
107-
options: CompilerOptions = { mergeInFieldsFromFragmentSpreads: true }
108+
options: CompilerOptions = {
109+
mergeInFieldsFromFragmentSpreads: true,
110+
exposeRawTypes: false
111+
}
108112
): LegacyCompilerContext {
109113
const context = compileToIR(schema, document, options);
110114
const transformer = new LegacyIRTransformer(context, options);

packages/apollo-codegen-core/src/serializeToJSON.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,11 @@ import {
1010
} from "graphql";
1111

1212
import { LegacyCompilerContext } from "./compiler/legacyIR";
13+
import { CompilerContext } from "./compiler";
1314

14-
export default function serializeToJSON(context: LegacyCompilerContext) {
15+
export default function serializeToJSON(
16+
context: LegacyCompilerContext | CompilerContext
17+
) {
1518
return serializeAST(
1619
{
1720
operations: Object.values(context.operations),

0 commit comments

Comments
 (0)