@luvio/graphql-parser 0.62.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/babel.config.js +1 -0
- package/dist/argument-node.d.ts +4 -0
- package/dist/ast.d.ts +95 -0
- package/dist/constants.d.ts +12 -0
- package/dist/directive-node.d.ts +5 -0
- package/dist/document.d.ts +3 -0
- package/dist/field-node.d.ts +4 -0
- package/dist/fragment-spread-node.d.ts +4 -0
- package/dist/fragment.d.ts +3 -0
- package/dist/inline-fragment-node.d.ts +4 -0
- package/dist/luvioGraphqlParser.js +3887 -0
- package/dist/main.d.ts +4 -0
- package/dist/operation/index.d.ts +3 -0
- package/dist/operation/query/index.d.ts +6 -0
- package/dist/type-node.d.ts +3 -0
- package/dist/value-node.d.ts +4 -0
- package/dist/variable-definition.d.ts +4 -0
- package/dist/visitor.d.ts +4 -0
- package/jest.config.js +8 -0
- package/package.json +19 -0
- package/rollup.config.js +19 -0
- package/scripts/cli.mjs +18 -0
- package/src/__tests__/ast.spec.ts +109 -0
- package/src/__tests__/main.spec.ts +600 -0
- package/src/__tests__/type-node.spec.ts +82 -0
- package/src/argument-node.ts +18 -0
- package/src/ast.ts +200 -0
- package/src/constants.ts +14 -0
- package/src/directive-node.ts +36 -0
- package/src/document.ts +33 -0
- package/src/field-node.ts +72 -0
- package/src/fragment-spread-node.ts +28 -0
- package/src/fragment.ts +46 -0
- package/src/inline-fragment-node.ts +31 -0
- package/src/main.ts +58 -0
- package/src/operation/index.ts +12 -0
- package/src/operation/query/index.ts +78 -0
- package/src/type-node.ts +39 -0
- package/src/value-node.ts +71 -0
- package/src/variable-definition.ts +37 -0
- package/src/visitor.ts +62 -0
- package/tsconfig.json +9 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ArgumentNode } from 'graphql/language';
|
|
2
|
+
import { LuvioArgumentNode } from './ast';
|
|
3
|
+
import { TransformState } from './operation/query';
|
|
4
|
+
import { transform as transformValueNode } from './value-node';
|
|
5
|
+
|
|
6
|
+
export function transform(node: ArgumentNode, transformState: TransformState): LuvioArgumentNode {
|
|
7
|
+
const {
|
|
8
|
+
kind,
|
|
9
|
+
name: { value: nodeName },
|
|
10
|
+
value: nodeValue,
|
|
11
|
+
} = node;
|
|
12
|
+
const valueNode = transformValueNode(nodeValue, transformState);
|
|
13
|
+
return {
|
|
14
|
+
kind,
|
|
15
|
+
name: nodeName,
|
|
16
|
+
value: valueNode,
|
|
17
|
+
};
|
|
18
|
+
}
|
package/src/ast.ts
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DocumentNode,
|
|
3
|
+
OperationDefinitionNode,
|
|
4
|
+
FieldNode,
|
|
5
|
+
ArgumentNode,
|
|
6
|
+
IntValueNode,
|
|
7
|
+
ListValueNode,
|
|
8
|
+
ObjectValueNode,
|
|
9
|
+
FloatValueNode,
|
|
10
|
+
StringValueNode,
|
|
11
|
+
BooleanValueNode,
|
|
12
|
+
NullValueNode,
|
|
13
|
+
EnumValueNode,
|
|
14
|
+
VariableNode,
|
|
15
|
+
DirectiveNode,
|
|
16
|
+
VariableDefinitionNode,
|
|
17
|
+
NonNullTypeNode,
|
|
18
|
+
ListTypeNode,
|
|
19
|
+
NamedTypeNode,
|
|
20
|
+
FragmentSpreadNode,
|
|
21
|
+
InlineFragmentNode,
|
|
22
|
+
FragmentDefinitionNode,
|
|
23
|
+
DefinitionNode,
|
|
24
|
+
TypeNode,
|
|
25
|
+
} from 'graphql/language';
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Luvio specific custom GraphQL AST
|
|
29
|
+
*
|
|
30
|
+
* - Omit Location
|
|
31
|
+
* - flatten NameNode for easier value access
|
|
32
|
+
* - Add luvioSelections for custom selections
|
|
33
|
+
* - LuvioSelectionCustomFieldNode for fields with custom client side directives
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
/* Document */
|
|
37
|
+
export interface LuvioDocumentNode extends Omit<DocumentNode, 'loc' | 'definitions'> {
|
|
38
|
+
definitions: LuvioDefinitionNode[];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export type LuvioDefinitionNode = LuvioOperationDefinitionNode | LuvioFragmentDefinitionNode;
|
|
42
|
+
|
|
43
|
+
export interface LuvioOperationDefinitionNode
|
|
44
|
+
extends Omit<
|
|
45
|
+
OperationDefinitionNode,
|
|
46
|
+
'loc' | 'name' | 'variableDefinitions' | 'directives' | 'selectionSet'
|
|
47
|
+
> {
|
|
48
|
+
name?: string;
|
|
49
|
+
variableDefinitions?: LuvioVariableDefinitionNode[];
|
|
50
|
+
directives?: LuvioDirectiveNode[];
|
|
51
|
+
luvioSelections: LuvioSelectionNode[];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface LuvioVariableDefinitionNode
|
|
55
|
+
extends Omit<
|
|
56
|
+
VariableDefinitionNode,
|
|
57
|
+
'loc' | 'variable' | 'type' | 'defaultValue' | 'directives'
|
|
58
|
+
> {
|
|
59
|
+
variable: LuvioVariableNode;
|
|
60
|
+
type: LuvioTypeNode;
|
|
61
|
+
defaultValue?: LuvioValueNode;
|
|
62
|
+
directives?: LuvioDirectiveNode[];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface LuvioVariableNode extends Omit<VariableNode, 'loc' | 'name'> {
|
|
66
|
+
name: string;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export type LuvioSelectionNode = LuvioFieldNode | LuvioFragmentSpreadNode | LuvioInlineFragmentNode;
|
|
70
|
+
|
|
71
|
+
export type LuvioFieldNode =
|
|
72
|
+
| LuvioSelectionScalarFieldNode
|
|
73
|
+
| LuvioSelectionObjectFieldNode
|
|
74
|
+
| LuvioSelectionCustomFieldNode;
|
|
75
|
+
|
|
76
|
+
export interface LuvioArgumentNode extends Omit<ArgumentNode, 'loc' | 'name' | 'value'> {
|
|
77
|
+
name: string;
|
|
78
|
+
value: LuvioValueNode;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/* Fragments */
|
|
82
|
+
export interface LuvioFragmentSpreadNode
|
|
83
|
+
extends Omit<FragmentSpreadNode, 'loc' | 'name' | 'directives'> {
|
|
84
|
+
name: string;
|
|
85
|
+
directives?: LuvioDirectiveNode[];
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export interface LuvioInlineFragmentNode
|
|
89
|
+
extends Omit<InlineFragmentNode, 'loc' | 'typeCondition' | 'directives' | 'selectionSet'> {
|
|
90
|
+
typeCondition?: LuvioNamedTypeNode;
|
|
91
|
+
directives?: LuvioDirectiveNode[];
|
|
92
|
+
luvioSelections: LuvioSelectionNode[];
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export interface LuvioFragmentDefinitionNode
|
|
96
|
+
extends Omit<
|
|
97
|
+
FragmentDefinitionNode,
|
|
98
|
+
'loc' | 'name' | 'variableDefinitions' | 'typeCondition' | 'directives' | 'selectionSet'
|
|
99
|
+
> {
|
|
100
|
+
name: string;
|
|
101
|
+
// Note: fragment variable definitions are experimental and may be changed
|
|
102
|
+
// or removed in the future.
|
|
103
|
+
variableDefinitions?: LuvioVariableDefinitionNode[];
|
|
104
|
+
typeCondition: LuvioNamedTypeNode;
|
|
105
|
+
directives?: LuvioDirectiveNode[];
|
|
106
|
+
luvioSelections: LuvioSelectionNode[];
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/* Values */
|
|
110
|
+
export type LuvioValueNode =
|
|
111
|
+
| LuvioVariableNode
|
|
112
|
+
| IntValueNode
|
|
113
|
+
| FloatValueNode
|
|
114
|
+
| StringValueNode
|
|
115
|
+
| BooleanValueNode
|
|
116
|
+
| NullValueNode
|
|
117
|
+
| EnumValueNode
|
|
118
|
+
| LuvioListValueNode
|
|
119
|
+
| LuvioObjectValueNode;
|
|
120
|
+
|
|
121
|
+
export interface LuvioListValueNode extends Omit<ListValueNode, 'loc' | 'values'> {
|
|
122
|
+
values: LuvioValueNode[];
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export interface LuvioObjectValueNode extends Omit<ObjectValueNode, 'loc' | 'fields'> {
|
|
126
|
+
fields: {
|
|
127
|
+
[name: string]: LuvioValueNode;
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/* Directives */
|
|
132
|
+
export interface LuvioDirectiveNode extends Omit<DirectiveNode, 'loc' | 'name' | 'arguments'> {
|
|
133
|
+
name: string;
|
|
134
|
+
arguments?: LuvioArgumentNode[];
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/* Type Reference */
|
|
138
|
+
export type LuvioTypeNode = LuvioNamedTypeNode | LuvioListTypeNode | LuvioNonNullTypeNode;
|
|
139
|
+
|
|
140
|
+
export interface LuvioNamedTypeNode extends Omit<NamedTypeNode, 'loc' | 'name'> {
|
|
141
|
+
name: string;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export interface LuvioListTypeNode extends Omit<ListTypeNode, 'loc' | 'type'> {
|
|
145
|
+
type: LuvioTypeNode;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export interface LuvioNonNullTypeNode extends Omit<NonNullTypeNode, 'loc' | 'type'> {
|
|
149
|
+
type: LuvioNamedTypeNode | LuvioListTypeNode;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/* Custom Selection Fields */
|
|
153
|
+
export interface LuvioSelectionScalarFieldNode
|
|
154
|
+
extends Omit<
|
|
155
|
+
FieldNode,
|
|
156
|
+
'kind' | 'loc' | 'alias' | 'name' | 'arguments' | 'directives' | 'selectionSet'
|
|
157
|
+
> {
|
|
158
|
+
kind: 'ScalarFieldSelection';
|
|
159
|
+
alias?: string;
|
|
160
|
+
name: string;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export interface LuvioSelectionObjectFieldNode
|
|
164
|
+
extends Omit<
|
|
165
|
+
FieldNode,
|
|
166
|
+
'kind' | 'loc' | 'alias' | 'name' | 'arguments' | 'directives' | 'selectionSet'
|
|
167
|
+
> {
|
|
168
|
+
kind: 'ObjectFieldSelection';
|
|
169
|
+
alias?: string;
|
|
170
|
+
name: string;
|
|
171
|
+
arguments?: LuvioArgumentNode[];
|
|
172
|
+
directives?: LuvioDirectiveNode[];
|
|
173
|
+
luvioSelections?: LuvioSelectionNode[];
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export interface LuvioSelectionCustomFieldNode extends Omit<LuvioSelectionObjectFieldNode, 'kind'> {
|
|
177
|
+
kind: 'CustomFieldSelection';
|
|
178
|
+
type: string;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/* Util Functions */
|
|
182
|
+
export function isOperationDefinitionNode(input: DefinitionNode): input is OperationDefinitionNode {
|
|
183
|
+
return input.kind === 'OperationDefinition';
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export function isFragmentDefinitionNode(input: DefinitionNode): input is FragmentDefinitionNode {
|
|
187
|
+
return input.kind === 'FragmentDefinition';
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export function isNamedTypeNode(input: TypeNode): input is NamedTypeNode {
|
|
191
|
+
return input.kind === 'NamedType';
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
export function isListTypeNode(input: TypeNode): input is ListTypeNode {
|
|
195
|
+
return input.kind === 'ListType';
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export function isNonNullTypeNode(input: TypeNode): input is NonNullTypeNode {
|
|
199
|
+
return input.kind === 'NonNullType';
|
|
200
|
+
}
|
package/src/constants.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export const CUSTOM_DIRECTIVE_CONNECTION = 'connection';
|
|
2
|
+
export const CUSTOM_DIRECTIVE_RESOURCE = 'resource';
|
|
3
|
+
|
|
4
|
+
export const NODE_KIND_CUSTOM_FIELD_SELECTION = 'CustomFieldSelection';
|
|
5
|
+
export const NODE_KIND_FIELD = 'Field';
|
|
6
|
+
export const NODE_KIND_FRAGMENT_SPREAD = 'FragmentSpread';
|
|
7
|
+
export const NODE_KIND_INLINE_FRAGMENT = 'InlineFragment';
|
|
8
|
+
export const NODE_KIND_LIST_TYPE = 'ListType';
|
|
9
|
+
export const NODE_KIND_NAMED_TYPE = 'NamedType';
|
|
10
|
+
export const NODE_KIND_NON_NULL_TYPE = 'NonNullType';
|
|
11
|
+
export const NODE_KIND_OBJECT_FIELD_SELECTION = 'ObjectFieldSelection';
|
|
12
|
+
export const NODE_KIND_SCALAR_FIELD_SELECTION = 'ScalarFieldSelection';
|
|
13
|
+
|
|
14
|
+
export const NODE_TYPE_CONNECTION = 'Connection';
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { DirectiveNode } from 'graphql/language';
|
|
2
|
+
import { LuvioArgumentNode, LuvioDirectiveNode } from './ast';
|
|
3
|
+
import { transform as transformArgumentNode } from './argument-node';
|
|
4
|
+
import { CUSTOM_DIRECTIVE_CONNECTION, CUSTOM_DIRECTIVE_RESOURCE } from './constants';
|
|
5
|
+
import { TransformState } from './operation/query';
|
|
6
|
+
|
|
7
|
+
export function transform(node: DirectiveNode, transformState: TransformState): LuvioDirectiveNode {
|
|
8
|
+
const {
|
|
9
|
+
kind,
|
|
10
|
+
name: { value: nodeName },
|
|
11
|
+
arguments: nodeArguments,
|
|
12
|
+
} = node;
|
|
13
|
+
const ret: LuvioDirectiveNode = {
|
|
14
|
+
kind,
|
|
15
|
+
name: nodeName,
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
if (nodeArguments !== undefined && nodeArguments.length > 0) {
|
|
19
|
+
let returnArguments: LuvioArgumentNode[] = [];
|
|
20
|
+
for (var index = 0; index < nodeArguments.length; index++) {
|
|
21
|
+
const argumentNode = nodeArguments[index];
|
|
22
|
+
const value = transformArgumentNode(argumentNode, transformState);
|
|
23
|
+
returnArguments.push(value);
|
|
24
|
+
}
|
|
25
|
+
ret.arguments = returnArguments;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return ret;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function isCustomDirective(node: DirectiveNode): boolean {
|
|
32
|
+
return (
|
|
33
|
+
node.name.value === CUSTOM_DIRECTIVE_CONNECTION ||
|
|
34
|
+
node.name.value === CUSTOM_DIRECTIVE_RESOURCE
|
|
35
|
+
);
|
|
36
|
+
}
|
package/src/document.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { DocumentNode } from 'graphql/language';
|
|
2
|
+
import {
|
|
3
|
+
LuvioDocumentNode,
|
|
4
|
+
LuvioDefinitionNode,
|
|
5
|
+
isOperationDefinitionNode,
|
|
6
|
+
isFragmentDefinitionNode,
|
|
7
|
+
} from './ast';
|
|
8
|
+
import { transform as operationDefinitionTransform } from './operation';
|
|
9
|
+
import { transform as fragmentDefinitionTransform } from './fragment';
|
|
10
|
+
|
|
11
|
+
export function transform(root: DocumentNode): LuvioDocumentNode {
|
|
12
|
+
const { kind, definitions } = root;
|
|
13
|
+
const luvioDefinitions: LuvioDefinitionNode[] = [];
|
|
14
|
+
for (let i = 0; i < definitions.length; i++) {
|
|
15
|
+
const definition = definitions[i];
|
|
16
|
+
if (isOperationDefinitionNode(definition)) {
|
|
17
|
+
luvioDefinitions.push(operationDefinitionTransform(definition));
|
|
18
|
+
} else if (isFragmentDefinitionNode(definition)) {
|
|
19
|
+
luvioDefinitions.push(fragmentDefinitionTransform(definition));
|
|
20
|
+
} else {
|
|
21
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
22
|
+
throw new Error(
|
|
23
|
+
`Unsupported ${definition.kind} definition. Only OperationDefinition and FragmentDefinition are supported in a GraphQL Document`
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return {
|
|
30
|
+
kind,
|
|
31
|
+
definitions: luvioDefinitions,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { FieldNode, StringValueNode } from 'graphql/language';
|
|
2
|
+
import { transform as transformArgumentNode } from './argument-node';
|
|
3
|
+
import { LuvioArgumentNode, LuvioFieldNode } from './ast';
|
|
4
|
+
import {
|
|
5
|
+
CUSTOM_DIRECTIVE_CONNECTION,
|
|
6
|
+
CUSTOM_DIRECTIVE_RESOURCE,
|
|
7
|
+
NODE_KIND_CUSTOM_FIELD_SELECTION,
|
|
8
|
+
NODE_KIND_OBJECT_FIELD_SELECTION,
|
|
9
|
+
NODE_KIND_SCALAR_FIELD_SELECTION,
|
|
10
|
+
NODE_TYPE_CONNECTION,
|
|
11
|
+
} from './constants';
|
|
12
|
+
import { isCustomDirective, transform as transformDirectiveNode } from './directive-node';
|
|
13
|
+
import { TransformState } from './operation/query';
|
|
14
|
+
|
|
15
|
+
export function transform(node: FieldNode, transformState: TransformState): LuvioFieldNode {
|
|
16
|
+
const { name, alias, arguments: fieldArgs, selectionSet, directives } = node;
|
|
17
|
+
|
|
18
|
+
let luvioNode: LuvioFieldNode = {
|
|
19
|
+
kind: NODE_KIND_OBJECT_FIELD_SELECTION,
|
|
20
|
+
name: name.value,
|
|
21
|
+
luvioSelections: [],
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
if (selectionSet === undefined || selectionSet.selections.length === 0) {
|
|
25
|
+
luvioNode = {
|
|
26
|
+
kind: NODE_KIND_SCALAR_FIELD_SELECTION,
|
|
27
|
+
name: name.value,
|
|
28
|
+
};
|
|
29
|
+
} else {
|
|
30
|
+
// object or custom field node
|
|
31
|
+
if (directives !== undefined && directives.length > 0) {
|
|
32
|
+
const customDirectiveNode = directives.find(isCustomDirective);
|
|
33
|
+
if (customDirectiveNode === undefined) {
|
|
34
|
+
// transform non client-side directives
|
|
35
|
+
luvioNode.directives = directives.map((directive) =>
|
|
36
|
+
transformDirectiveNode(directive, transformState)
|
|
37
|
+
);
|
|
38
|
+
} else {
|
|
39
|
+
if (customDirectiveNode.name.value === CUSTOM_DIRECTIVE_CONNECTION) {
|
|
40
|
+
luvioNode = {
|
|
41
|
+
kind: NODE_KIND_CUSTOM_FIELD_SELECTION,
|
|
42
|
+
name: name.value,
|
|
43
|
+
type: NODE_TYPE_CONNECTION,
|
|
44
|
+
luvioSelections: [],
|
|
45
|
+
};
|
|
46
|
+
} else if (customDirectiveNode.name.value === CUSTOM_DIRECTIVE_RESOURCE) {
|
|
47
|
+
luvioNode = {
|
|
48
|
+
kind: NODE_KIND_CUSTOM_FIELD_SELECTION,
|
|
49
|
+
name: name.value,
|
|
50
|
+
type: (customDirectiveNode!.arguments![0].value as StringValueNode).value,
|
|
51
|
+
luvioSelections: [],
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (fieldArgs !== undefined && fieldArgs.length > 0) {
|
|
58
|
+
const returnArguments: LuvioArgumentNode[] = [];
|
|
59
|
+
for (var index = 0; index < fieldArgs.length; index++) {
|
|
60
|
+
const value = transformArgumentNode(fieldArgs[index], transformState);
|
|
61
|
+
returnArguments.push(value);
|
|
62
|
+
}
|
|
63
|
+
luvioNode.arguments = returnArguments;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (alias !== undefined) {
|
|
68
|
+
luvioNode.alias = alias.value;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return luvioNode;
|
|
72
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { FragmentSpreadNode } from 'graphql/language';
|
|
2
|
+
import { LuvioFragmentSpreadNode } from './ast';
|
|
3
|
+
import { transform as transformDirectiveNode } from './directive-node';
|
|
4
|
+
import { TransformState } from './operation/query';
|
|
5
|
+
|
|
6
|
+
export function transform(
|
|
7
|
+
node: FragmentSpreadNode,
|
|
8
|
+
transformState: TransformState
|
|
9
|
+
): LuvioFragmentSpreadNode {
|
|
10
|
+
const {
|
|
11
|
+
kind,
|
|
12
|
+
name: { value },
|
|
13
|
+
directives,
|
|
14
|
+
} = node;
|
|
15
|
+
|
|
16
|
+
const luvioNode: LuvioFragmentSpreadNode = {
|
|
17
|
+
kind,
|
|
18
|
+
name: value,
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
if (directives !== undefined && directives.length > 0) {
|
|
22
|
+
luvioNode.directives = directives.map((directive) =>
|
|
23
|
+
transformDirectiveNode(directive, transformState)
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return luvioNode;
|
|
28
|
+
}
|
package/src/fragment.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { FragmentDefinitionNode } from 'graphql/language';
|
|
2
|
+
import { LuvioFieldNode, LuvioFragmentDefinitionNode, LuvioSelectionNode } from './ast';
|
|
3
|
+
import { selectionSetVisitor } from './visitor';
|
|
4
|
+
import { transform as transformDirectiveNode } from './directive-node';
|
|
5
|
+
import { NODE_KIND_OBJECT_FIELD_SELECTION } from './constants';
|
|
6
|
+
|
|
7
|
+
export function transform(node: FragmentDefinitionNode): LuvioFragmentDefinitionNode {
|
|
8
|
+
const {
|
|
9
|
+
kind: nodeKind,
|
|
10
|
+
name: { value: nodeName },
|
|
11
|
+
typeCondition: {
|
|
12
|
+
kind: typeKind,
|
|
13
|
+
name: { value: typeName },
|
|
14
|
+
},
|
|
15
|
+
directives,
|
|
16
|
+
} = node;
|
|
17
|
+
|
|
18
|
+
// dummy root node
|
|
19
|
+
const fragmentRoot: LuvioFieldNode = {
|
|
20
|
+
kind: NODE_KIND_OBJECT_FIELD_SELECTION,
|
|
21
|
+
name: 'fragment',
|
|
22
|
+
luvioSelections: [],
|
|
23
|
+
};
|
|
24
|
+
const currentNodePath: LuvioSelectionNode[] = [fragmentRoot];
|
|
25
|
+
|
|
26
|
+
const transformState = { variablesUsed: {} };
|
|
27
|
+
selectionSetVisitor(node, currentNodePath, transformState);
|
|
28
|
+
|
|
29
|
+
const luvioNode: LuvioFragmentDefinitionNode = {
|
|
30
|
+
kind: nodeKind,
|
|
31
|
+
name: nodeName,
|
|
32
|
+
typeCondition: {
|
|
33
|
+
kind: typeKind,
|
|
34
|
+
name: typeName,
|
|
35
|
+
},
|
|
36
|
+
luvioSelections: fragmentRoot.luvioSelections!,
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
if (directives !== undefined && directives.length > 0) {
|
|
40
|
+
luvioNode.directives = directives.map((node) =>
|
|
41
|
+
transformDirectiveNode(node, transformState)
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return luvioNode;
|
|
46
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { InlineFragmentNode } from 'graphql/language';
|
|
2
|
+
import { LuvioInlineFragmentNode } from './ast';
|
|
3
|
+
import { transform as transformDirectiveNode } from './directive-node';
|
|
4
|
+
import { TransformState } from './operation/query';
|
|
5
|
+
|
|
6
|
+
export function transform(
|
|
7
|
+
node: InlineFragmentNode,
|
|
8
|
+
transformState: TransformState
|
|
9
|
+
): LuvioInlineFragmentNode {
|
|
10
|
+
const { kind: nodeKind, typeCondition, directives } = node;
|
|
11
|
+
|
|
12
|
+
const luvioNode: LuvioInlineFragmentNode = {
|
|
13
|
+
kind: nodeKind,
|
|
14
|
+
luvioSelections: [],
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
if (typeCondition !== undefined) {
|
|
18
|
+
luvioNode.typeCondition = {
|
|
19
|
+
kind: typeCondition.kind,
|
|
20
|
+
name: typeCondition.name.value,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (directives !== undefined && directives.length > 0) {
|
|
25
|
+
luvioNode.directives = directives.map((directive) =>
|
|
26
|
+
transformDirectiveNode(directive, transformState)
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return luvioNode;
|
|
31
|
+
}
|
package/src/main.ts
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import {
|
|
2
|
+
parse,
|
|
3
|
+
BooleanValueNode,
|
|
4
|
+
FloatValueNode,
|
|
5
|
+
IntValueNode,
|
|
6
|
+
StringValueNode,
|
|
7
|
+
} from 'graphql/language';
|
|
8
|
+
import {
|
|
9
|
+
LuvioDocumentNode,
|
|
10
|
+
LuvioArgumentNode,
|
|
11
|
+
LuvioDefinitionNode,
|
|
12
|
+
LuvioObjectValueNode,
|
|
13
|
+
LuvioOperationDefinitionNode,
|
|
14
|
+
LuvioSelectionCustomFieldNode,
|
|
15
|
+
LuvioSelectionNode,
|
|
16
|
+
LuvioSelectionObjectFieldNode,
|
|
17
|
+
LuvioSelectionScalarFieldNode,
|
|
18
|
+
LuvioValueNode,
|
|
19
|
+
LuvioFieldNode,
|
|
20
|
+
LuvioVariableDefinitionNode,
|
|
21
|
+
LuvioVariableNode,
|
|
22
|
+
LuvioNamedTypeNode,
|
|
23
|
+
LuvioListTypeNode,
|
|
24
|
+
LuvioListValueNode,
|
|
25
|
+
LuvioTypeNode,
|
|
26
|
+
} from './ast';
|
|
27
|
+
import { transform } from './document';
|
|
28
|
+
|
|
29
|
+
export function parseAndVisit(source: string): LuvioDocumentNode {
|
|
30
|
+
// TODO: handle generic <Type>
|
|
31
|
+
const ast = parse(source);
|
|
32
|
+
return transform(ast);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// type exports
|
|
36
|
+
export {
|
|
37
|
+
BooleanValueNode,
|
|
38
|
+
FloatValueNode,
|
|
39
|
+
IntValueNode,
|
|
40
|
+
StringValueNode,
|
|
41
|
+
LuvioDocumentNode,
|
|
42
|
+
LuvioArgumentNode,
|
|
43
|
+
LuvioDefinitionNode,
|
|
44
|
+
LuvioObjectValueNode,
|
|
45
|
+
LuvioOperationDefinitionNode,
|
|
46
|
+
LuvioSelectionCustomFieldNode,
|
|
47
|
+
LuvioSelectionNode,
|
|
48
|
+
LuvioSelectionObjectFieldNode,
|
|
49
|
+
LuvioSelectionScalarFieldNode,
|
|
50
|
+
LuvioValueNode,
|
|
51
|
+
LuvioFieldNode,
|
|
52
|
+
LuvioVariableDefinitionNode,
|
|
53
|
+
LuvioVariableNode,
|
|
54
|
+
LuvioNamedTypeNode,
|
|
55
|
+
LuvioListTypeNode,
|
|
56
|
+
LuvioListValueNode,
|
|
57
|
+
LuvioTypeNode,
|
|
58
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { OperationDefinitionNode } from 'graphql/language';
|
|
2
|
+
import { LuvioOperationDefinitionNode } from '../ast';
|
|
3
|
+
import { transform as QueryTransform } from './query';
|
|
4
|
+
|
|
5
|
+
export function transform(node: OperationDefinitionNode): LuvioOperationDefinitionNode {
|
|
6
|
+
const { operation } = node;
|
|
7
|
+
if (operation === 'query') {
|
|
8
|
+
return QueryTransform(node);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
throw new Error(`Unsupported ${operation} operation. Only query operation is supported`);
|
|
12
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { OperationDefinitionNode, VariableDefinitionNode } from 'graphql/language';
|
|
2
|
+
import { LuvioFieldNode, LuvioOperationDefinitionNode, LuvioSelectionNode } from '../../ast';
|
|
3
|
+
import { selectionSetVisitor } from '../../visitor';
|
|
4
|
+
import { transform as transformVariableDefinition } from '../../variable-definition';
|
|
5
|
+
import { transform as transformDirectiveNode } from '../../directive-node';
|
|
6
|
+
|
|
7
|
+
export interface TransformState {
|
|
8
|
+
variablesUsed: Record<string, true>;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function transform(node: OperationDefinitionNode): LuvioOperationDefinitionNode {
|
|
12
|
+
const queryRoot: LuvioFieldNode = {
|
|
13
|
+
kind: 'ObjectFieldSelection',
|
|
14
|
+
name: 'query',
|
|
15
|
+
luvioSelections: [],
|
|
16
|
+
};
|
|
17
|
+
const currentNodePath: LuvioSelectionNode[] = [queryRoot];
|
|
18
|
+
|
|
19
|
+
const transformState = {
|
|
20
|
+
variablesUsed: {},
|
|
21
|
+
};
|
|
22
|
+
selectionSetVisitor(node, currentNodePath, transformState);
|
|
23
|
+
|
|
24
|
+
const operationDefinition: LuvioOperationDefinitionNode = {
|
|
25
|
+
kind: 'OperationDefinition',
|
|
26
|
+
operation: 'query',
|
|
27
|
+
luvioSelections: queryRoot.luvioSelections!,
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
if (node.name !== undefined) {
|
|
31
|
+
operationDefinition.name = node.name.value;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const { variableDefinitions, directives } = node;
|
|
35
|
+
if (variableDefinitions !== undefined && variableDefinitions.length > 0) {
|
|
36
|
+
operationDefinition.variableDefinitions = variableDefinitions.map((variableDefinition) =>
|
|
37
|
+
transformVariableDefinition(variableDefinition, transformState)
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (directives !== undefined && directives.length > 0) {
|
|
42
|
+
operationDefinition.directives = directives.map((node) =>
|
|
43
|
+
transformDirectiveNode(node, transformState)
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
validateVariables(variableDefinitions, transformState);
|
|
48
|
+
|
|
49
|
+
return operationDefinition;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function validateVariables(
|
|
53
|
+
variableDefinitions: readonly VariableDefinitionNode[] | undefined,
|
|
54
|
+
transformState: TransformState
|
|
55
|
+
) {
|
|
56
|
+
const variablesDefined: Record<string, true> = {};
|
|
57
|
+
|
|
58
|
+
if (variableDefinitions !== undefined) {
|
|
59
|
+
for (let i = 0, len = variableDefinitions.length; i < len; i++) {
|
|
60
|
+
const definedVariableName = variableDefinitions[i].variable.name.value;
|
|
61
|
+
variablesDefined[definedVariableName] = true;
|
|
62
|
+
if (transformState.variablesUsed[definedVariableName] === undefined) {
|
|
63
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
64
|
+
throw new Error(`Variable $${definedVariableName} was defined but never used.`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const usedVariableKeys = Object.keys(transformState.variablesUsed);
|
|
71
|
+
for (let i = 0, len = usedVariableKeys.length; i < len; i++) {
|
|
72
|
+
if (variablesDefined[usedVariableKeys[i]] !== true) {
|
|
73
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
74
|
+
throw new Error(`Variable $${usedVariableKeys[i]} was used but never defined.`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
package/src/type-node.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { TypeNode } from 'graphql/language';
|
|
2
|
+
import { isListTypeNode, isNamedTypeNode, isNonNullTypeNode, LuvioTypeNode } from './ast';
|
|
3
|
+
import { NODE_KIND_NAMED_TYPE, NODE_KIND_LIST_TYPE, NODE_KIND_NON_NULL_TYPE } from './constants';
|
|
4
|
+
|
|
5
|
+
export function transform(node: TypeNode): LuvioTypeNode {
|
|
6
|
+
if (isNamedTypeNode(node)) {
|
|
7
|
+
return {
|
|
8
|
+
kind: NODE_KIND_NAMED_TYPE,
|
|
9
|
+
name: node.name.value,
|
|
10
|
+
};
|
|
11
|
+
} else if (isListTypeNode(node)) {
|
|
12
|
+
return {
|
|
13
|
+
kind: NODE_KIND_LIST_TYPE,
|
|
14
|
+
type: transform(node.type),
|
|
15
|
+
};
|
|
16
|
+
} else if (isNonNullTypeNode(node)) {
|
|
17
|
+
if (isNamedTypeNode(node.type)) {
|
|
18
|
+
return {
|
|
19
|
+
kind: NODE_KIND_NON_NULL_TYPE,
|
|
20
|
+
type: {
|
|
21
|
+
kind: NODE_KIND_NAMED_TYPE,
|
|
22
|
+
name: node.type.name.value,
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
} else if (isListTypeNode(node.type)) {
|
|
26
|
+
return {
|
|
27
|
+
kind: NODE_KIND_NON_NULL_TYPE,
|
|
28
|
+
type: {
|
|
29
|
+
kind: NODE_KIND_LIST_TYPE,
|
|
30
|
+
type: transform(node.type.type),
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
} else {
|
|
34
|
+
throw new Error('Unsupported NonNullTypeNode');
|
|
35
|
+
}
|
|
36
|
+
} else {
|
|
37
|
+
throw new Error('Unsupported TypeNode');
|
|
38
|
+
}
|
|
39
|
+
}
|