attio 0.0.1-experimental.20241001 → 0.0.1-experimental.20241002
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/lib/api/start-graphql-server.js +1 -1
- package/lib/client/hooks/index.d.ts +0 -1
- package/lib/client/hooks/use-query.d.ts +4 -3
- package/lib/client/index.d.ts +1 -0
- package/lib/client/{hooks/run-query.d.ts → run-query.d.ts} +4 -0
- package/lib/commands/dev.js +8 -0
- package/lib/graphql/generate-operations.js +151 -0
- package/lib/graphql/generate-types.js +109 -0
- package/lib/graphql/parse-schema.js +65 -0
- package/lib/graphql.d.ts +4 -0
- package/lib/machines/code-gen-machine.js +102 -0
- package/lib/machines/dev-machine.js +32 -10
- package/lib/machines/js-machine.js +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/lib/util/find-node-modules-path.js +17 -0
- package/lib/util/update-env-types.js +3 -15
- package/lib/util/update-operation-types.js +13 -0
- package/package.json +6 -1
- package/lib/schema.graphql +0 -536
- package/lib/schema.json +0 -67
|
@@ -11,7 +11,7 @@ export function startGraphqlServer(sendBack) {
|
|
|
11
11
|
const startServer = async () => {
|
|
12
12
|
const currentFilePath = fileURLToPath(import.meta.url);
|
|
13
13
|
const currentDirPath = dirname(currentFilePath);
|
|
14
|
-
const schemaPath = path.resolve(currentDirPath, "..", "schema.graphql");
|
|
14
|
+
const schemaPath = path.resolve(currentDirPath, "..", "..", "schema.graphql");
|
|
15
15
|
const schemaString = fs.readFileSync(schemaPath, "utf8");
|
|
16
16
|
const port = await findAvailablePort(8700);
|
|
17
17
|
const schema = buildSchema(schemaString);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
import { Query } from "../run-query";
|
|
2
|
+
export declare function useQuery<Variables, Result>(
|
|
2
3
|
/** GraphQL query */
|
|
3
|
-
query:
|
|
4
|
+
query: Query<Variables, Result>,
|
|
4
5
|
/** GraphQL query variables */
|
|
5
|
-
variableValues?:
|
|
6
|
+
variableValues?: Variables): Result;
|
package/lib/client/index.d.ts
CHANGED
package/lib/commands/dev.js
CHANGED
|
@@ -53,6 +53,14 @@ export default function Dev({ options: { debug } }) {
|
|
|
53
53
|
React.createElement(Text, null,
|
|
54
54
|
"Env: ",
|
|
55
55
|
JSON.stringify(snapshot.children.env?.getSnapshot().value))),
|
|
56
|
+
React.createElement(Box, null,
|
|
57
|
+
React.createElement(Text, null,
|
|
58
|
+
"Code Gen:",
|
|
59
|
+
" ",
|
|
60
|
+
JSON.stringify(snapshot.children["code-gen"]?.getSnapshot()?.value),
|
|
61
|
+
" ",
|
|
62
|
+
snapshot.children["code-gen"]?.getSnapshot().context.error
|
|
63
|
+
?.message)),
|
|
56
64
|
snapshot.context.devVersion?.app_id && (React.createElement(Box, null,
|
|
57
65
|
React.createElement(Text, null,
|
|
58
66
|
"App ID: ",
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import { parse, visit, validate, print, OperationTypeNode, isObjectType, isListType, isNonNullType, isInputObjectType, isEnumType, getNamedType, } from "graphql";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import { format } from "prettier";
|
|
5
|
+
function findGraphQLFiles(dir) {
|
|
6
|
+
const files = [];
|
|
7
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
8
|
+
for (const entry of entries) {
|
|
9
|
+
const fullPath = path.join(dir, entry.name);
|
|
10
|
+
if (entry.isDirectory()) {
|
|
11
|
+
files.push(...findGraphQLFiles(fullPath));
|
|
12
|
+
}
|
|
13
|
+
else if (entry.isFile() && path.extname(entry.name) === ".graphql") {
|
|
14
|
+
files.push(fullPath);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return files;
|
|
18
|
+
}
|
|
19
|
+
function generateEnumTypeDefinition(type) {
|
|
20
|
+
const values = type
|
|
21
|
+
.getValues()
|
|
22
|
+
.map((v) => `'${v.name}'`)
|
|
23
|
+
.join(" | ");
|
|
24
|
+
return values;
|
|
25
|
+
}
|
|
26
|
+
function generateTypeDefinition(type) {
|
|
27
|
+
if (isNonNullType(type)) {
|
|
28
|
+
return generateTypeDefinition(type.ofType);
|
|
29
|
+
}
|
|
30
|
+
if (isListType(type)) {
|
|
31
|
+
return `${generateTypeDefinition(type.ofType)}`;
|
|
32
|
+
}
|
|
33
|
+
if (isObjectType(type) || isInputObjectType(type)) {
|
|
34
|
+
return type.name;
|
|
35
|
+
}
|
|
36
|
+
if (isEnumType(type)) {
|
|
37
|
+
return generateEnumTypeDefinition(type);
|
|
38
|
+
}
|
|
39
|
+
switch (type.name) {
|
|
40
|
+
case "Int":
|
|
41
|
+
case "Float":
|
|
42
|
+
return "number";
|
|
43
|
+
case "String":
|
|
44
|
+
case "ID":
|
|
45
|
+
return "string";
|
|
46
|
+
case "Boolean":
|
|
47
|
+
return "boolean";
|
|
48
|
+
default:
|
|
49
|
+
return "any";
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function generateInputObjectTypeDefinition(type) {
|
|
53
|
+
const fields = Object.values(type.getFields())
|
|
54
|
+
.map((field) => `${field.name}: ${generateTypeDefinition(field.type)}`)
|
|
55
|
+
.join(", ");
|
|
56
|
+
return `{ ${fields} }`;
|
|
57
|
+
}
|
|
58
|
+
function generateTypeDefinitionFromSelectionSet(selectionSet, parentType) {
|
|
59
|
+
const fieldDefinitions = selectionSet.selections
|
|
60
|
+
.map((selection) => {
|
|
61
|
+
if (selection.kind === "Field") {
|
|
62
|
+
const field = parentType.getFields()[selection.name.value];
|
|
63
|
+
if (!field) {
|
|
64
|
+
throw new Error(`Field ${selection.name.value} not found in type ${parentType.name}`);
|
|
65
|
+
}
|
|
66
|
+
let fieldType = field.type;
|
|
67
|
+
let fieldTypeDefinition = "";
|
|
68
|
+
if (selection.selectionSet) {
|
|
69
|
+
if (isObjectType(getNamedType(fieldType))) {
|
|
70
|
+
fieldTypeDefinition = generateTypeDefinitionFromSelectionSet(selection.selectionSet, getNamedType(fieldType));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
fieldTypeDefinition = generateTypeDefinition(fieldType);
|
|
75
|
+
}
|
|
76
|
+
return `${selection.name.value}: ${fieldTypeDefinition}${isListType(fieldType) ? "[]" : ""}`;
|
|
77
|
+
}
|
|
78
|
+
return "";
|
|
79
|
+
})
|
|
80
|
+
.filter(Boolean);
|
|
81
|
+
return `{${fieldDefinitions.join(",")}}`;
|
|
82
|
+
}
|
|
83
|
+
function generateReturnType(selectionSet, schema) {
|
|
84
|
+
const queryType = schema.getQueryType();
|
|
85
|
+
if (!queryType) {
|
|
86
|
+
throw new Error("Query type not found in schema");
|
|
87
|
+
}
|
|
88
|
+
return generateTypeDefinitionFromSelectionSet(selectionSet, queryType);
|
|
89
|
+
}
|
|
90
|
+
function generateOperationFunction(graphqlFileName, operationName, variableDefinitions, schema, selectionSet) {
|
|
91
|
+
const typeName = `${operationName.charAt(0).toUpperCase() + operationName.slice(1)}`;
|
|
92
|
+
const returnType = generateReturnType(selectionSet, schema);
|
|
93
|
+
let input;
|
|
94
|
+
if (variableDefinitions.length === 1) {
|
|
95
|
+
const varDef = variableDefinitions[0];
|
|
96
|
+
const varType = schema.getType(print(varDef.type).replace(/[!]/g, ""));
|
|
97
|
+
const varTypeString = isInputObjectType(varType)
|
|
98
|
+
? generateInputObjectTypeDefinition(varType)
|
|
99
|
+
: generateTypeDefinition(varType);
|
|
100
|
+
input = `export type ${typeName}Variables = ${varTypeString}`;
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
const variables = variableDefinitions
|
|
104
|
+
.map((def) => {
|
|
105
|
+
const varType = schema.getType(print(def.type).replace(/[!]/g, ""));
|
|
106
|
+
const varTypeString = isInputObjectType(varType)
|
|
107
|
+
? generateInputObjectTypeDefinition(varType)
|
|
108
|
+
: generateTypeDefinition(varType);
|
|
109
|
+
return `${def.variable.name.value}: ${varTypeString}`;
|
|
110
|
+
})
|
|
111
|
+
.join(", ");
|
|
112
|
+
input = `export interface ${typeName}Variables { ${variables} }`;
|
|
113
|
+
}
|
|
114
|
+
return `
|
|
115
|
+
declare module "./${graphqlFileName}" {
|
|
116
|
+
${input}
|
|
117
|
+
|
|
118
|
+
export interface ${typeName}Result ${returnType}
|
|
119
|
+
|
|
120
|
+
const value: Query<${typeName}Variables, ${typeName}Result>
|
|
121
|
+
export default value
|
|
122
|
+
}
|
|
123
|
+
`;
|
|
124
|
+
}
|
|
125
|
+
export async function generateOperationFromQuery(graphqlFileName, query, schema) {
|
|
126
|
+
const ast = parse(query);
|
|
127
|
+
let operations = "";
|
|
128
|
+
const validationErrors = validate(schema, ast);
|
|
129
|
+
if (validationErrors.length > 0) {
|
|
130
|
+
throw new Error(`Validation errors: ${validationErrors.map((e) => e.message).join("\n")}`);
|
|
131
|
+
}
|
|
132
|
+
visit(ast, {
|
|
133
|
+
OperationDefinition(node) {
|
|
134
|
+
if (node.name && node.operation === OperationTypeNode.QUERY) {
|
|
135
|
+
const operationName = node.name.value;
|
|
136
|
+
const variableDefinitions = node.variableDefinitions || [];
|
|
137
|
+
operations += generateOperationFunction(graphqlFileName, operationName, variableDefinitions, schema, node.selectionSet);
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
});
|
|
141
|
+
return format(operations, { parser: "typescript" });
|
|
142
|
+
}
|
|
143
|
+
export async function generateOperations(rootDir, schema) {
|
|
144
|
+
const graphqlFiles = findGraphQLFiles(rootDir);
|
|
145
|
+
let operations = "";
|
|
146
|
+
for (const file of graphqlFiles) {
|
|
147
|
+
const content = fs.readFileSync(file, "utf-8");
|
|
148
|
+
operations += await generateOperationFromQuery(path.basename(file), content, schema);
|
|
149
|
+
}
|
|
150
|
+
return format(operations, { parser: "typescript" });
|
|
151
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { isObjectType, isInputObjectType, isScalarType, isEnumType, isListType, isNonNullType, } from "graphql";
|
|
2
|
+
import { format } from "prettier";
|
|
3
|
+
function countTypeUsages(schema) {
|
|
4
|
+
const typeUsages = new Map();
|
|
5
|
+
Object.values(schema.getTypeMap()).forEach((type) => {
|
|
6
|
+
if ((isObjectType(type) || isInputObjectType(type)) && !type.name.startsWith("__")) {
|
|
7
|
+
Object.values(type.getFields()).forEach((field) => {
|
|
8
|
+
let fieldType = field.type;
|
|
9
|
+
while (isListType(fieldType) || isNonNullType(fieldType)) {
|
|
10
|
+
fieldType = fieldType.ofType;
|
|
11
|
+
}
|
|
12
|
+
if (isObjectType(fieldType) || isInputObjectType(fieldType)) {
|
|
13
|
+
const usage = typeUsages.get(fieldType.name) || { count: 0, type: fieldType };
|
|
14
|
+
usage.count++;
|
|
15
|
+
typeUsages.set(fieldType.name, usage);
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
return typeUsages;
|
|
21
|
+
}
|
|
22
|
+
function generateFieldType(type, schema, typeUsages, seenTypes = new Set()) {
|
|
23
|
+
if (isListType(type)) {
|
|
24
|
+
return `Array<${generateFieldType(type.ofType, schema, typeUsages, seenTypes)}>`;
|
|
25
|
+
}
|
|
26
|
+
if (isNonNullType(type)) {
|
|
27
|
+
return generateFieldType(type.ofType, schema, typeUsages, seenTypes);
|
|
28
|
+
}
|
|
29
|
+
if (isScalarType(type)) {
|
|
30
|
+
switch (type.name) {
|
|
31
|
+
case "ID":
|
|
32
|
+
case "String":
|
|
33
|
+
return "string";
|
|
34
|
+
case "Int":
|
|
35
|
+
case "Float":
|
|
36
|
+
return "number";
|
|
37
|
+
case "Boolean":
|
|
38
|
+
return "boolean";
|
|
39
|
+
default:
|
|
40
|
+
return "any";
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (isEnumType(type)) {
|
|
44
|
+
return type
|
|
45
|
+
.getValues()
|
|
46
|
+
.map((v) => `'${v.name}'`)
|
|
47
|
+
.join(" | ");
|
|
48
|
+
}
|
|
49
|
+
if (isObjectType(type) || isInputObjectType(type)) {
|
|
50
|
+
const usage = typeUsages.get(type.name);
|
|
51
|
+
if (usage && usage.count > 1) {
|
|
52
|
+
return type.name;
|
|
53
|
+
}
|
|
54
|
+
if (seenTypes.has(type.name)) {
|
|
55
|
+
return type.name;
|
|
56
|
+
}
|
|
57
|
+
seenTypes.add(type.name);
|
|
58
|
+
const fields = type.getFields();
|
|
59
|
+
let inlineType = "{";
|
|
60
|
+
Object.entries(fields).forEach(([fieldName, field]) => {
|
|
61
|
+
const fieldType = generateFieldType(field.type, schema, typeUsages, new Set(seenTypes));
|
|
62
|
+
inlineType += `${fieldName}: ${fieldType};`;
|
|
63
|
+
});
|
|
64
|
+
inlineType += "}";
|
|
65
|
+
return inlineType;
|
|
66
|
+
}
|
|
67
|
+
return "any";
|
|
68
|
+
}
|
|
69
|
+
function generateDocComment(description) {
|
|
70
|
+
if (!description)
|
|
71
|
+
return "";
|
|
72
|
+
const lines = description.split("\n");
|
|
73
|
+
if (lines.length === 1) {
|
|
74
|
+
return `/** ${description} */`;
|
|
75
|
+
}
|
|
76
|
+
return `/**\n * ${lines.join("\n * ")}\n */`;
|
|
77
|
+
}
|
|
78
|
+
function generateType(type, schema, typeUsages) {
|
|
79
|
+
let typeString = "";
|
|
80
|
+
const typeComment = generateDocComment(type.description ?? "");
|
|
81
|
+
if (typeComment) {
|
|
82
|
+
typeString += `${typeComment}\n`;
|
|
83
|
+
}
|
|
84
|
+
typeString += `export type ${type.name.charAt(0).toUpperCase() + type.name.slice(1)} = {`;
|
|
85
|
+
const fields = type.getFields();
|
|
86
|
+
Object.entries(fields).forEach(([fieldName, field]) => {
|
|
87
|
+
typeString += "\n";
|
|
88
|
+
const fieldComment = generateDocComment(field.description);
|
|
89
|
+
if (fieldComment) {
|
|
90
|
+
typeString += `${fieldComment}\n`;
|
|
91
|
+
}
|
|
92
|
+
const fieldType = generateFieldType(field.type, schema, typeUsages);
|
|
93
|
+
typeString += `${fieldName}: ${fieldType};`;
|
|
94
|
+
});
|
|
95
|
+
typeString += "\n};";
|
|
96
|
+
return typeString;
|
|
97
|
+
}
|
|
98
|
+
export async function generateTypesFromSchema(schema) {
|
|
99
|
+
const typeUsages = countTypeUsages(schema);
|
|
100
|
+
let types = "";
|
|
101
|
+
const typeMap = schema.getTypeMap();
|
|
102
|
+
Object.values(typeMap).forEach((type) => {
|
|
103
|
+
if ((isObjectType(type) || isInputObjectType(type)) && !type.name.startsWith("__")) {
|
|
104
|
+
types += generateType(type, schema, typeUsages);
|
|
105
|
+
types += "\n\n";
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
return await format(types, { parser: "typescript" });
|
|
109
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { codeFrameColumns } from "@babel/code-frame";
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import { parse, validateSchema, buildASTSchema } from "graphql";
|
|
4
|
+
import { validateSDL } from "graphql/validation/validate.js";
|
|
5
|
+
function formatGraphQlError(e, source, filename) {
|
|
6
|
+
if (e.locations?.length) {
|
|
7
|
+
return `${e.message}\n\n${filename}:${e.locations[0].line}\n\n${e.locations
|
|
8
|
+
.map(({ line, column }) => codeFrameColumns(source, {
|
|
9
|
+
start: { line, column },
|
|
10
|
+
}))
|
|
11
|
+
.join(`\n\n`)}\n`;
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
throw e;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export function parseSchemaString(schemaString, schemaPath) {
|
|
18
|
+
let parsedSchema;
|
|
19
|
+
try {
|
|
20
|
+
parsedSchema = parse(schemaString);
|
|
21
|
+
}
|
|
22
|
+
catch (ex) {
|
|
23
|
+
throw Object.assign(new Error(formatGraphQlError(ex, schemaString, schemaPath)), {
|
|
24
|
+
code: `GRAPHQL_SYNTAX_ERROR`,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
parsedSchema = {
|
|
28
|
+
...parsedSchema,
|
|
29
|
+
definitions: parsedSchema.definitions
|
|
30
|
+
.slice()
|
|
31
|
+
.sort((a, b) => {
|
|
32
|
+
if (!a.name)
|
|
33
|
+
return -1;
|
|
34
|
+
if (!b.name)
|
|
35
|
+
return 1;
|
|
36
|
+
if (a.name.value.toLowerCase() > b.name.value.toLowerCase())
|
|
37
|
+
return 1;
|
|
38
|
+
if (a.name.value.toLowerCase() < b.name.value.toLowerCase())
|
|
39
|
+
return -1;
|
|
40
|
+
return 0;
|
|
41
|
+
}),
|
|
42
|
+
};
|
|
43
|
+
const sdlValidationErrors = validateSDL(parsedSchema);
|
|
44
|
+
if (sdlValidationErrors.length) {
|
|
45
|
+
throw Object.assign(new Error(formatGraphQlError(sdlValidationErrors[0], schemaString, schemaPath)), {
|
|
46
|
+
code: `GRAPHQL_SCHEMA_ERROR`,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
const schema = buildASTSchema(parsedSchema, { assumeValid: false, assumeValidSDL: false });
|
|
50
|
+
const schemaValidationErrors = validateSchema(schema);
|
|
51
|
+
if (schemaValidationErrors.length > 0) {
|
|
52
|
+
throw Object.assign(new Error(formatGraphQlError(schemaValidationErrors[0], schemaString, schemaPath)), {
|
|
53
|
+
code: `GRAPHQL_SCHEMA_ERROR`,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
source: schemaString,
|
|
58
|
+
documentNode: parsedSchema,
|
|
59
|
+
schema,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
export function parseSchema(schemaPath) {
|
|
63
|
+
const schemaString = fs.readFileSync(schemaPath, "utf-8");
|
|
64
|
+
return parseSchemaString(schemaString, schemaPath);
|
|
65
|
+
}
|
package/lib/graphql.d.ts
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { sendTo, assign, setup, fromCallback } from "xstate";
|
|
2
|
+
import { parseSchema } from "../graphql/parse-schema.js";
|
|
3
|
+
import { findNodeModulesPath } from "../util/find-node-modules-path.js";
|
|
4
|
+
import { updateOperationTypes } from "../util/update-operation-types.js";
|
|
5
|
+
export const codeGenMachine = setup({
|
|
6
|
+
types: {
|
|
7
|
+
context: {},
|
|
8
|
+
events: {},
|
|
9
|
+
input: {},
|
|
10
|
+
},
|
|
11
|
+
guards: {
|
|
12
|
+
"all finished": (_, params) => params.finished.length === 2,
|
|
13
|
+
},
|
|
14
|
+
actors: {
|
|
15
|
+
loadSchema: fromCallback(({ sendBack }) => {
|
|
16
|
+
const loadSchema = async () => {
|
|
17
|
+
try {
|
|
18
|
+
const path = await findNodeModulesPath(["schema.graphql"]);
|
|
19
|
+
if (!path) {
|
|
20
|
+
sendBack({ type: "Error", error: new Error("No schema found") });
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
const { schema } = parseSchema(path);
|
|
24
|
+
sendBack({ type: "Schema Loaded", schema });
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
sendBack({ type: "Error", error });
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
loadSchema();
|
|
31
|
+
}),
|
|
32
|
+
generateOperations: fromCallback(({ sendBack, input }) => {
|
|
33
|
+
updateOperationTypes(input.schema)
|
|
34
|
+
.then(() => sendBack({ type: "Done" }))
|
|
35
|
+
.catch((error) => sendBack({ type: "Error", error }));
|
|
36
|
+
}),
|
|
37
|
+
},
|
|
38
|
+
actions: {
|
|
39
|
+
clearFinished: assign({
|
|
40
|
+
finished: [],
|
|
41
|
+
}),
|
|
42
|
+
setOperationsFinished: assign({
|
|
43
|
+
finished: (_, params) => params.finished.concat("operations.ts"),
|
|
44
|
+
}),
|
|
45
|
+
setError: assign({
|
|
46
|
+
error: (_, params) => params.error,
|
|
47
|
+
}),
|
|
48
|
+
setSchema: assign({
|
|
49
|
+
schema: (_, params) => params.schema,
|
|
50
|
+
}),
|
|
51
|
+
raiseDone: sendTo(({ context }) => context.parentRef, { type: "Code Generation Done" }),
|
|
52
|
+
},
|
|
53
|
+
}).createMachine({
|
|
54
|
+
id: "GraphQL Code Generation Machine",
|
|
55
|
+
context: ({ input }) => ({
|
|
56
|
+
schema: null,
|
|
57
|
+
finished: [],
|
|
58
|
+
parentRef: input.parentRef,
|
|
59
|
+
}),
|
|
60
|
+
states: {
|
|
61
|
+
"Load Schema": {
|
|
62
|
+
on: {
|
|
63
|
+
"Error": {
|
|
64
|
+
target: "Errored",
|
|
65
|
+
actions: { type: "setError", params: ({ event }) => event },
|
|
66
|
+
},
|
|
67
|
+
"Schema Loaded": {
|
|
68
|
+
target: "Generating Operations",
|
|
69
|
+
actions: { type: "setSchema", params: ({ event }) => event },
|
|
70
|
+
reenter: true,
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
invoke: {
|
|
74
|
+
src: "loadSchema",
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
"Done": {
|
|
78
|
+
entry: "raiseDone",
|
|
79
|
+
},
|
|
80
|
+
"Errored": {},
|
|
81
|
+
"Generating Operations": {
|
|
82
|
+
on: {
|
|
83
|
+
Done: {
|
|
84
|
+
target: "Done",
|
|
85
|
+
},
|
|
86
|
+
Error: {
|
|
87
|
+
target: "Errored",
|
|
88
|
+
actions: { type: "setError", params: ({ event }) => event },
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
invoke: {
|
|
92
|
+
src: "generateOperations",
|
|
93
|
+
input: ({ context }) => ({ schema: context.schema }),
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
initial: "Load Schema",
|
|
98
|
+
on: {
|
|
99
|
+
Change: ".Load Schema",
|
|
100
|
+
},
|
|
101
|
+
description: `Generates operations typescript types`,
|
|
102
|
+
});
|
|
@@ -9,6 +9,7 @@ import { startUpload } from "../api/start-upload.js";
|
|
|
9
9
|
import { loadAppConfigFile } from "../util/app-config.js";
|
|
10
10
|
import { loadDeveloperConfig, loadInitialDeveloperConfig, } from "../util/load-developer-config.js";
|
|
11
11
|
import { loadEnv } from "../util/load-env.js";
|
|
12
|
+
import { codeGenMachine } from "./code-gen-machine.js";
|
|
12
13
|
import { envMachine } from "./env-machine.js";
|
|
13
14
|
import { jsMachine } from "./js-machine.js";
|
|
14
15
|
import { tsMachine } from "./ts-machine.js";
|
|
@@ -22,10 +23,11 @@ export const devMachine = setup({
|
|
|
22
23
|
"have dev version": ({ context }) => Boolean(context.devVersion),
|
|
23
24
|
},
|
|
24
25
|
actors: {
|
|
25
|
-
javascript: jsMachine,
|
|
26
|
-
typescript: tsMachine,
|
|
27
|
-
env: envMachine,
|
|
28
|
-
|
|
26
|
+
"javascript": jsMachine,
|
|
27
|
+
"typescript": tsMachine,
|
|
28
|
+
"env": envMachine,
|
|
29
|
+
"code-gen": codeGenMachine,
|
|
30
|
+
"loadConfig": fromCallback(({ sendBack }) => {
|
|
29
31
|
const config = loadInitialDeveloperConfig();
|
|
30
32
|
if (typeof config === "string") {
|
|
31
33
|
sendBack({ type: "Initialization Error", error: config });
|
|
@@ -33,12 +35,12 @@ export const devMachine = setup({
|
|
|
33
35
|
}
|
|
34
36
|
sendBack({ type: "Initialized", config });
|
|
35
37
|
}),
|
|
36
|
-
listenForGraphqlOpen: fromCallback(({ input }) => {
|
|
38
|
+
"listenForGraphqlOpen": fromCallback(({ input }) => {
|
|
37
39
|
readline.emitKeypressEvents(process.stdin);
|
|
38
40
|
if (process.stdin.isTTY) {
|
|
39
41
|
process.stdin.setRawMode(true);
|
|
40
42
|
}
|
|
41
|
-
const handleKeyPress = (
|
|
43
|
+
const handleKeyPress = (_, key) => {
|
|
42
44
|
if (key.name?.toLowerCase() === "o") {
|
|
43
45
|
open(`http://localhost:${input.graphqlPort}/graphql`);
|
|
44
46
|
}
|
|
@@ -51,7 +53,7 @@ export const devMachine = setup({
|
|
|
51
53
|
}
|
|
52
54
|
};
|
|
53
55
|
}),
|
|
54
|
-
prepareUpload: fromCallback(({ sendBack }) => {
|
|
56
|
+
"prepareUpload": fromCallback(({ sendBack }) => {
|
|
55
57
|
const prepareUpload = async () => {
|
|
56
58
|
const config = await loadDeveloperConfig();
|
|
57
59
|
if (typeof config === "string")
|
|
@@ -76,7 +78,7 @@ export const devMachine = setup({
|
|
|
76
78
|
error: typeof error === "string" ? new Error(error) : error,
|
|
77
79
|
}));
|
|
78
80
|
}),
|
|
79
|
-
upload: fromCallback(({ sendBack, input: { config: { token, developer_slug: developerSlug }, contents, devVersion: { app_id: appId, app_dev_version_id: devVersionId }, }, }) => {
|
|
81
|
+
"upload": fromCallback(({ sendBack, input: { config: { token, developer_slug: developerSlug }, contents, devVersion: { app_id: appId, app_dev_version_id: devVersionId }, }, }) => {
|
|
80
82
|
const upload = async () => {
|
|
81
83
|
const { client_bundle_upload_url, server_bundle_upload_url, app_dev_version_bundle_id: bundleId, } = await startUpload({
|
|
82
84
|
token,
|
|
@@ -114,7 +116,7 @@ export const devMachine = setup({
|
|
|
114
116
|
};
|
|
115
117
|
upload().catch((error) => sendBack({ type: "Upload Error", error }));
|
|
116
118
|
}),
|
|
117
|
-
watch: fromCallback(({ sendBack }) => {
|
|
119
|
+
"watch": fromCallback(({ sendBack }) => {
|
|
118
120
|
const watcher = chokidar.watch([
|
|
119
121
|
"src/app",
|
|
120
122
|
"src/assets",
|
|
@@ -129,7 +131,7 @@ export const devMachine = setup({
|
|
|
129
131
|
watcher.close();
|
|
130
132
|
};
|
|
131
133
|
}),
|
|
132
|
-
graphql: fromCallback(({ sendBack }) => startGraphqlServer(sendBack)),
|
|
134
|
+
"graphql": fromCallback(({ sendBack }) => startGraphqlServer(sendBack)),
|
|
133
135
|
},
|
|
134
136
|
actions: {
|
|
135
137
|
clearUploadError: assign({ uploadError: undefined }),
|
|
@@ -137,6 +139,10 @@ export const devMachine = setup({
|
|
|
137
139
|
enqueue.sendTo("javascript", event);
|
|
138
140
|
enqueue.sendTo("typescript", event);
|
|
139
141
|
enqueue.sendTo("env", event);
|
|
142
|
+
enqueue.sendTo("code-gen", event);
|
|
143
|
+
}),
|
|
144
|
+
sendCodeGenerationDone: enqueueActions(({ enqueue }) => {
|
|
145
|
+
enqueue.sendTo("typescript", { type: "Change" });
|
|
140
146
|
}),
|
|
141
147
|
setConfig: assign({
|
|
142
148
|
config: (_, params) => params.config,
|
|
@@ -180,6 +186,11 @@ export const devMachine = setup({
|
|
|
180
186
|
id: "env",
|
|
181
187
|
input: ({ self }) => ({ parentRef: self }),
|
|
182
188
|
},
|
|
189
|
+
{
|
|
190
|
+
src: "code-gen",
|
|
191
|
+
id: "code-gen",
|
|
192
|
+
input: ({ self }) => ({ parentRef: self }),
|
|
193
|
+
},
|
|
183
194
|
{ src: "watch" },
|
|
184
195
|
],
|
|
185
196
|
states: {
|
|
@@ -276,6 +287,17 @@ export const devMachine = setup({
|
|
|
276
287
|
Watching: {},
|
|
277
288
|
},
|
|
278
289
|
initial: "Validating",
|
|
290
|
+
on: {
|
|
291
|
+
"Change": {
|
|
292
|
+
target: "TypeScript",
|
|
293
|
+
actions: "sendChange",
|
|
294
|
+
},
|
|
295
|
+
"Code Generation Done": {
|
|
296
|
+
target: "TypeScript",
|
|
297
|
+
description: `Re-enter TypeScript build when code generation is complete`,
|
|
298
|
+
actions: "sendCodeGenerationDone",
|
|
299
|
+
},
|
|
300
|
+
},
|
|
279
301
|
},
|
|
280
302
|
Graphql: {
|
|
281
303
|
invoke: {
|