-
-
Notifications
You must be signed in to change notification settings - Fork 801
/
parse-graphql-sdl.ts
111 lines (101 loc) · 2.77 KB
/
parse-graphql-sdl.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
import {
ASTNode,
DocumentNode,
Source as GraphQLSource,
isTypeSystemDefinitionNode,
Kind,
parse,
print,
StringValueNode,
visit,
} from 'graphql';
import { dedentBlockStringValue, getLeadingCommentBlock } from './comments.js';
import { GraphQLParseOptions } from './Interfaces.js';
export function parseGraphQLSDL(
location: string | undefined,
rawSDL: string,
options: GraphQLParseOptions = {},
) {
let document: DocumentNode;
try {
if (options.commentDescriptions && rawSDL.includes('#')) {
document = transformCommentsToDescriptions(rawSDL, options);
// If noLocation=true, we need to make sure to print and parse it again, to remove locations,
// since `transformCommentsToDescriptions` must have locations set in order to transform the comments
// into descriptions.
if (options.noLocation) {
document = parse(print(document), options);
}
} else {
document = parse(new GraphQLSource(rawSDL, location), options);
}
} catch (e: any) {
if (e.message.includes('EOF') && rawSDL.replace(/(\#[^*]*)/g, '').trim() === '') {
document = {
kind: Kind.DOCUMENT,
definitions: [],
};
} else {
throw e;
}
}
return {
location,
document,
};
}
export function transformCommentsToDescriptions(
sourceSdl: string,
options: GraphQLParseOptions = {},
): DocumentNode {
const parsedDoc = parse(sourceSdl, {
...options,
noLocation: false,
});
const modifiedDoc = visit(parsedDoc, {
leave: (node: ASTNode) => {
if (isDescribable(node)) {
const rawValue = getLeadingCommentBlock(node);
if (rawValue !== undefined) {
const commentsBlock = dedentBlockStringValue('\n' + rawValue);
const isBlock = commentsBlock.includes('\n');
if (!node.description) {
return {
...node,
description: {
kind: Kind.STRING,
value: commentsBlock,
block: isBlock,
},
};
} else {
return {
...node,
description: {
...node.description,
value: node.description.value + '\n' + commentsBlock,
block: true,
},
};
}
}
}
},
});
return modifiedDoc;
}
type DiscriminateUnion<T, U> = T extends U ? T : never;
type DescribableASTNodes = DiscriminateUnion<
ASTNode,
{
description?: StringValueNode;
}
>;
export function isDescribable(node: ASTNode): node is DescribableASTNodes {
return (
isTypeSystemDefinitionNode(node) ||
node.kind === Kind.FIELD_DEFINITION ||
node.kind === Kind.INPUT_VALUE_DEFINITION ||
node.kind === Kind.ENUM_VALUE_DEFINITION
);
}