-
Notifications
You must be signed in to change notification settings - Fork 0
/
GraphQLSchema.decorator.ts
113 lines (95 loc) · 2.52 KB
/
GraphQLSchema.decorator.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
112
113
import fs from "fs";
import { klass, property, propertyVoid } from "../index";
type SchemaType = "number" | "string" | "boolean" | "ID";
type SchemaMap = {
[key: string]: {
type?: SchemaType;
description?: string;
required?: boolean;
};
};
const schemaFileMap: { [key: string]: SchemaMap } = {};
type PropType = [SchemaType, string];
type OptionalPropType = Partial<PropType>;
export const field = property<OptionalPropType>(
({
key,
type,
args: [schemaType, description] = [],
metadata: { filePath },
}) => {
if (!schemaFileMap[filePath]) {
schemaFileMap[filePath] = {};
}
const schema = schemaFileMap[filePath];
schema[key] = {
type: schemaType || (type as SchemaType),
};
if (description?.trim().length) {
schema[key].description = description?.trim();
}
}
);
export const auto = propertyVoid(
({ key, type, metadata: { filePath, code } }) => {
if (!schemaFileMap[filePath]) {
schemaFileMap[filePath] = {};
}
const schema = schemaFileMap[filePath];
if (type !== "number" && type !== "string" && type !== "boolean") {
throw `Invalid or missing type definition\n\n${code}`;
}
schema[key] = {
type: type as SchemaType,
};
}
);
export const required = propertyVoid(
({ key, type, metadata: { filePath } }) => {
if (!schemaFileMap[filePath]) {
schemaFileMap[filePath] = {};
}
const schema = schemaFileMap[filePath];
console.assert(key, "property name must exist");
if (!schema[key]) {
schema[key] = {
required: true,
};
} else {
schema[key].required = true;
}
}
);
export const type = klass<[string] | undefined>(
async ({ args: [object], metadata: { filePath } }) => {
if (!schemaFileMap[filePath]) {
return;
}
const schemaFile = filePath.replace(".ts", ".graphql");
const map = schemaFileMap[filePath];
const stringifyField = (key: string) => {
const { type, description, required = false } = map[key];
let content: string = ` ${key}: ${type}`;
if (required) {
content += "!";
}
if (description) {
content = ` # ${description}\n` + content;
}
return content;
};
await fs.promises.writeFile(
schemaFile,
`
type ${object} {
${Object.keys(map).map(stringifyField).join("\n")}
}
`,
{
encoding: "utf-8",
}
);
console.log("Saved GraphQL schema to", schemaFile);
}
);
export const decorators = { auto, field, type, required };