-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgenerator.ts
108 lines (101 loc) · 2.62 KB
/
generator.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
import {
generateArgs,
getAliasFieldName,
getArgsFieldName,
isAliasKey,
isArgsKey,
isInlineFragmentKey,
} from "./decorators";
import { GQObject, GQType } from "./types";
interface GQObjectInfo {
fragment?: string;
fields: Record<string, GQType>;
fieldArgs: Record<string, any>;
fieldAlias: Record<string, string>;
}
function extractDecorators(obj: GQObject) {
const info: GQObjectInfo = {
fragment: undefined,
fields: {},
fieldArgs: {},
fieldAlias: {},
};
for (const [key, value] of Object.entries(obj)) {
if (isInlineFragmentKey(key)) {
info.fragment = value as string;
} else if (isArgsKey(key)) {
const fieldName = getArgsFieldName(key);
info.fieldArgs[fieldName] = value;
} else if (isAliasKey(key)) {
const fieldName = getAliasFieldName(key);
info.fieldAlias[fieldName] = value as string;
} else {
info.fields[key] = value;
}
}
return info;
}
/**
* Generates a gql query fields from an object
* @param object
*
* @example
* queryFields({foo: "", bar: 0}) => 'foo bar'
*/
export function queryFields(object: GQObject): string {
const info = extractDecorators(object);
const text = Object.entries(info.fields).reduce((acc, [k, v]) => {
let field = `${k}`;
if (info.fieldAlias[k]) field += `:${info.fieldAlias[k]}`;
if (info.fieldArgs[k]) field += `(${generateArgs(info.fieldArgs[k])})`;
acc += `${field} ${queryObject(v)}`;
return acc;
}, "");
return info.fragment
? `... on ${info.fragment} {
${text}}
`
: text;
}
function isGQObject(obj: GQType): obj is GQObject {
return (
!!obj &&
obj.constructor === Object && // isLiteralObject
Object.keys(obj).length > 0
);
}
/**
* Generates a gql type query string from an object
* @param object
*
* @example
* queryObject({foo: "", bar: 0}) => '{ foo bar }'
*/
export function queryObject(object: GQType): string {
let result = "";
if (Array.isArray(object)) {
result += object.map(queryObject);
} else if (isGQObject(object)) {
result += `{
${queryFields(object)}}
`;
}
return result;
}
/**
* Convenience function for creating queries with syntax coloring due to 'gql' tag naming
*
* @example
* gql`query MyQuery($input: String) { ${GQueryObject} ${GQueryOtherObject} }`
*/
export const gql = (chunks: TemplateStringsArray, ...types: GQType[]) =>
types.reduce<string>(
(acc, val, i) => (acc += stringify(val) + chunks[i + 1]),
chunks[0]
);
const stringify = (type: GQType): string =>
Array.isArray(type)
? type.map(item => stringify(item)).join("")
: isGQObject(type)
? queryFields(type)
: queryObject(type);