@soda-gql/codegen 0.11.20 → 0.11.21
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/dist/index.cjs +372 -265
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +23 -5
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +23 -5
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +370 -266
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.mjs
CHANGED
|
@@ -6,271 +6,6 @@ import { basename, dirname, extname, join, relative, resolve } from "node:path";
|
|
|
6
6
|
import { build } from "esbuild";
|
|
7
7
|
import { createHash } from "node:crypto";
|
|
8
8
|
|
|
9
|
-
//#region packages/codegen/src/graphql-compat/emitter.ts
|
|
10
|
-
/**
|
|
11
|
-
* Emit TypeScript code for an operation.
|
|
12
|
-
*/
|
|
13
|
-
const emitOperation = (operation, options) => {
|
|
14
|
-
const lines = [];
|
|
15
|
-
const schema = options.schemaDocument ? createSchemaIndex(options.schemaDocument) : null;
|
|
16
|
-
const exportName = `${operation.name}Compat`;
|
|
17
|
-
const operationType = operation.kind;
|
|
18
|
-
lines.push(`export const ${exportName} = gql.${options.schemaName}(({ ${operationType}, $var }) =>`);
|
|
19
|
-
lines.push(` ${operationType}.compat({`);
|
|
20
|
-
lines.push(` name: ${JSON.stringify(operation.name)},`);
|
|
21
|
-
if (operation.variables.length > 0) {
|
|
22
|
-
lines.push(` variables: { ${emitVariables(operation.variables)} },`);
|
|
23
|
-
}
|
|
24
|
-
lines.push(` fields: ({ f, $ }) => ({`);
|
|
25
|
-
const fieldLinesResult = emitSelections(operation.selections, 3, operation.variables, schema);
|
|
26
|
-
if (fieldLinesResult.isErr()) {
|
|
27
|
-
return err(fieldLinesResult.error);
|
|
28
|
-
}
|
|
29
|
-
lines.push(fieldLinesResult.value);
|
|
30
|
-
lines.push(` }),`);
|
|
31
|
-
lines.push(` }),`);
|
|
32
|
-
lines.push(`);`);
|
|
33
|
-
return ok(lines.join("\n"));
|
|
34
|
-
};
|
|
35
|
-
/**
|
|
36
|
-
* Emit TypeScript code for a fragment.
|
|
37
|
-
*/
|
|
38
|
-
const emitFragment = (fragment, options) => {
|
|
39
|
-
const lines = [];
|
|
40
|
-
const schema = options.schemaDocument ? createSchemaIndex(options.schemaDocument) : null;
|
|
41
|
-
const hasVariables = fragment.variables.length > 0;
|
|
42
|
-
const exportName = `${fragment.name}Fragment`;
|
|
43
|
-
const destructure = hasVariables ? "fragment, $var" : "fragment";
|
|
44
|
-
lines.push(`export const ${exportName} = gql.${options.schemaName}(({ ${destructure} }) =>`);
|
|
45
|
-
lines.push(` fragment.${fragment.onType}({`);
|
|
46
|
-
if (hasVariables) {
|
|
47
|
-
lines.push(` variables: { ${emitVariables(fragment.variables)} },`);
|
|
48
|
-
}
|
|
49
|
-
const fieldsContext = hasVariables ? "{ f, $ }" : "{ f }";
|
|
50
|
-
lines.push(` fields: (${fieldsContext}) => ({`);
|
|
51
|
-
const fieldLinesResult = emitSelections(fragment.selections, 3, fragment.variables, schema);
|
|
52
|
-
if (fieldLinesResult.isErr()) {
|
|
53
|
-
return err(fieldLinesResult.error);
|
|
54
|
-
}
|
|
55
|
-
lines.push(fieldLinesResult.value);
|
|
56
|
-
lines.push(` }),`);
|
|
57
|
-
lines.push(` }),`);
|
|
58
|
-
lines.push(`);`);
|
|
59
|
-
return ok(lines.join("\n"));
|
|
60
|
-
};
|
|
61
|
-
/**
|
|
62
|
-
* Emit variable definitions.
|
|
63
|
-
*/
|
|
64
|
-
const emitVariables = (variables) => {
|
|
65
|
-
return variables.map((v) => `...$var(${JSON.stringify(v.name)}).${v.typeName}(${JSON.stringify(v.modifier)})`).join(", ");
|
|
66
|
-
};
|
|
67
|
-
/**
|
|
68
|
-
* Emit field selections (public API).
|
|
69
|
-
* Converts variable array to Set<string> and delegates to internal implementation.
|
|
70
|
-
*/
|
|
71
|
-
const emitSelections = (selections, indent, variables, schema) => {
|
|
72
|
-
const variableNames = new Set(variables.map((v) => v.name));
|
|
73
|
-
return emitSelectionsInternal(selections, indent, variableNames, schema);
|
|
74
|
-
};
|
|
75
|
-
/**
|
|
76
|
-
* Internal implementation for emitting field selections.
|
|
77
|
-
* Takes variableNames as Set<string> for recursive calls.
|
|
78
|
-
*/
|
|
79
|
-
const emitSelectionsInternal = (selections, indent, variableNames, schema) => {
|
|
80
|
-
const lines = [];
|
|
81
|
-
const inlineFragments = [];
|
|
82
|
-
const otherSelections = [];
|
|
83
|
-
for (const sel of selections) {
|
|
84
|
-
if (sel.kind === "inlineFragment") {
|
|
85
|
-
inlineFragments.push(sel);
|
|
86
|
-
} else {
|
|
87
|
-
otherSelections.push(sel);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
for (const sel of otherSelections) {
|
|
91
|
-
const result = emitSingleSelection(sel, indent, variableNames, schema);
|
|
92
|
-
if (result.isErr()) {
|
|
93
|
-
return err(result.error);
|
|
94
|
-
}
|
|
95
|
-
lines.push(result.value);
|
|
96
|
-
}
|
|
97
|
-
if (inlineFragments.length > 0) {
|
|
98
|
-
const unionResult = emitInlineFragmentsAsUnion(inlineFragments, indent, variableNames, schema);
|
|
99
|
-
if (unionResult.isErr()) {
|
|
100
|
-
return err(unionResult.error);
|
|
101
|
-
}
|
|
102
|
-
lines.push(unionResult.value);
|
|
103
|
-
}
|
|
104
|
-
return ok(lines.join("\n"));
|
|
105
|
-
};
|
|
106
|
-
/**
|
|
107
|
-
* Emit a single selection (field or fragment spread).
|
|
108
|
-
*/
|
|
109
|
-
const emitSingleSelection = (sel, indent, variableNames, schema) => {
|
|
110
|
-
const padding = " ".repeat(indent);
|
|
111
|
-
switch (sel.kind) {
|
|
112
|
-
case "field": return emitFieldSelection(sel, indent, variableNames, schema);
|
|
113
|
-
case "fragmentSpread": return ok(`${padding}...${sel.name}Fragment.spread(),`);
|
|
114
|
-
case "inlineFragment": return ok("");
|
|
115
|
-
}
|
|
116
|
-
};
|
|
117
|
-
/**
|
|
118
|
-
* Emit inline fragments grouped as a union selection.
|
|
119
|
-
* Format: { TypeA: ({ f }) => ({ ...fields }), TypeB: ({ f }) => ({ ...fields }) }
|
|
120
|
-
*/
|
|
121
|
-
const emitInlineFragmentsAsUnion = (inlineFragments, indent, variableNames, schema) => {
|
|
122
|
-
const padding = " ".repeat(indent);
|
|
123
|
-
for (const frag of inlineFragments) {
|
|
124
|
-
if (frag.onType === "") {
|
|
125
|
-
return err({
|
|
126
|
-
code: "GRAPHQL_INLINE_FRAGMENT_WITHOUT_TYPE",
|
|
127
|
-
message: "Inline fragments without type condition are not supported. Use `... on TypeName { }` syntax."
|
|
128
|
-
});
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
for (const frag of inlineFragments) {
|
|
132
|
-
if (schema && !schema.objects.has(frag.onType)) {
|
|
133
|
-
let isUnionMember = false;
|
|
134
|
-
for (const [, unionDef] of schema.unions) {
|
|
135
|
-
if (unionDef.members.has(frag.onType)) {
|
|
136
|
-
isUnionMember = true;
|
|
137
|
-
break;
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
if (!isUnionMember) {
|
|
141
|
-
return err({
|
|
142
|
-
code: "GRAPHQL_INLINE_FRAGMENT_ON_INTERFACE",
|
|
143
|
-
message: `Inline fragments on interface type "${frag.onType}" are not supported. Use union types instead.`,
|
|
144
|
-
onType: frag.onType
|
|
145
|
-
});
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
const entries = [];
|
|
150
|
-
for (const frag of inlineFragments) {
|
|
151
|
-
const innerPadding = " ".repeat(indent + 1);
|
|
152
|
-
const fieldsResult = emitSelectionsInternal(frag.selections, indent + 2, variableNames, schema);
|
|
153
|
-
if (fieldsResult.isErr()) {
|
|
154
|
-
return err(fieldsResult.error);
|
|
155
|
-
}
|
|
156
|
-
entries.push(`${innerPadding}${frag.onType}: ({ f }) => ({
|
|
157
|
-
${fieldsResult.value}
|
|
158
|
-
${innerPadding}}),`);
|
|
159
|
-
}
|
|
160
|
-
return ok(`${padding}...({
|
|
161
|
-
${entries.join("\n")}
|
|
162
|
-
${padding}}),`);
|
|
163
|
-
};
|
|
164
|
-
/**
|
|
165
|
-
* Emit a single field selection.
|
|
166
|
-
*/
|
|
167
|
-
const emitFieldSelection = (field, indent, variableNames, schema) => {
|
|
168
|
-
const padding = " ".repeat(indent);
|
|
169
|
-
const args = field.arguments;
|
|
170
|
-
const selections = field.selections;
|
|
171
|
-
const hasArgs = args && args.length > 0;
|
|
172
|
-
const hasSelections = selections && selections.length > 0;
|
|
173
|
-
if (!hasArgs && !hasSelections) {
|
|
174
|
-
return ok(`${padding}${field.name}: true,`);
|
|
175
|
-
}
|
|
176
|
-
let line = `${padding}...f.${field.name}(`;
|
|
177
|
-
if (hasArgs) {
|
|
178
|
-
const argsResult = emitArguments(args, variableNames);
|
|
179
|
-
if (argsResult.isErr()) {
|
|
180
|
-
return err(argsResult.error);
|
|
181
|
-
}
|
|
182
|
-
line += argsResult.value;
|
|
183
|
-
}
|
|
184
|
-
line += ")";
|
|
185
|
-
if (hasSelections) {
|
|
186
|
-
const hasInlineFragments = selections.some((s) => s.kind === "inlineFragment");
|
|
187
|
-
if (hasInlineFragments) {
|
|
188
|
-
const nestedResult = emitSelectionsInternal(selections, indent + 1, variableNames, schema);
|
|
189
|
-
if (nestedResult.isErr()) {
|
|
190
|
-
return err(nestedResult.error);
|
|
191
|
-
}
|
|
192
|
-
line += "({\n";
|
|
193
|
-
line += `${nestedResult.value}\n`;
|
|
194
|
-
line += `${padding}})`;
|
|
195
|
-
} else {
|
|
196
|
-
line += "(({ f }) => ({\n";
|
|
197
|
-
const nestedResult = emitSelectionsInternal(selections, indent + 1, variableNames, schema);
|
|
198
|
-
if (nestedResult.isErr()) {
|
|
199
|
-
return err(nestedResult.error);
|
|
200
|
-
}
|
|
201
|
-
line += `${nestedResult.value}\n`;
|
|
202
|
-
line += `${padding}}))`;
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
line += ",";
|
|
206
|
-
return ok(line);
|
|
207
|
-
};
|
|
208
|
-
/**
|
|
209
|
-
* Emit field arguments.
|
|
210
|
-
*/
|
|
211
|
-
const emitArguments = (args, variableNames) => {
|
|
212
|
-
if (args.length === 0) {
|
|
213
|
-
return ok("");
|
|
214
|
-
}
|
|
215
|
-
const argEntries = [];
|
|
216
|
-
for (const arg of args) {
|
|
217
|
-
const result = emitValue(arg.value, variableNames);
|
|
218
|
-
if (result.isErr()) {
|
|
219
|
-
return err(result.error);
|
|
220
|
-
}
|
|
221
|
-
argEntries.push(`${arg.name}: ${result.value}`);
|
|
222
|
-
}
|
|
223
|
-
return ok(`{ ${argEntries.join(", ")} }`);
|
|
224
|
-
};
|
|
225
|
-
/**
|
|
226
|
-
* Emit a value (literal or variable reference).
|
|
227
|
-
*/
|
|
228
|
-
const emitValue = (value, variableNames) => {
|
|
229
|
-
switch (value.kind) {
|
|
230
|
-
case "variable":
|
|
231
|
-
if (variableNames.has(value.name)) {
|
|
232
|
-
return ok(`$.${value.name}`);
|
|
233
|
-
}
|
|
234
|
-
return err({
|
|
235
|
-
code: "GRAPHQL_UNDECLARED_VARIABLE",
|
|
236
|
-
message: `Variable "$${value.name}" is not declared in the operation`,
|
|
237
|
-
variableName: value.name
|
|
238
|
-
});
|
|
239
|
-
case "int":
|
|
240
|
-
case "float": return ok(value.value);
|
|
241
|
-
case "string": return ok(JSON.stringify(value.value));
|
|
242
|
-
case "boolean": return ok(value.value ? "true" : "false");
|
|
243
|
-
case "null": return ok("null");
|
|
244
|
-
case "enum": return ok(JSON.stringify(value.value));
|
|
245
|
-
case "list": {
|
|
246
|
-
const values = [];
|
|
247
|
-
for (const v of value.values) {
|
|
248
|
-
const result = emitValue(v, variableNames);
|
|
249
|
-
if (result.isErr()) {
|
|
250
|
-
return err(result.error);
|
|
251
|
-
}
|
|
252
|
-
values.push(result.value);
|
|
253
|
-
}
|
|
254
|
-
return ok(`[${values.join(", ")}]`);
|
|
255
|
-
}
|
|
256
|
-
case "object": {
|
|
257
|
-
if (value.fields.length === 0) {
|
|
258
|
-
return ok("{}");
|
|
259
|
-
}
|
|
260
|
-
const entries = [];
|
|
261
|
-
for (const f of value.fields) {
|
|
262
|
-
const result = emitValue(f.value, variableNames);
|
|
263
|
-
if (result.isErr()) {
|
|
264
|
-
return err(result.error);
|
|
265
|
-
}
|
|
266
|
-
entries.push(`${f.name}: ${result.value}`);
|
|
267
|
-
}
|
|
268
|
-
return ok(`{ ${entries.join(", ")} }`);
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
};
|
|
272
|
-
|
|
273
|
-
//#endregion
|
|
274
9
|
//#region packages/codegen/src/graphql-compat/parser.ts
|
|
275
10
|
/**
|
|
276
11
|
* Parser for .graphql operation files.
|
|
@@ -1107,6 +842,375 @@ const collectFragmentDependencies = (selections) => {
|
|
|
1107
842
|
return [...fragments];
|
|
1108
843
|
};
|
|
1109
844
|
|
|
845
|
+
//#endregion
|
|
846
|
+
//#region packages/codegen/src/graphql-compat/emitter.ts
|
|
847
|
+
/**
|
|
848
|
+
* Map operation kind to root type name.
|
|
849
|
+
*/
|
|
850
|
+
const getRootTypeName = (kind) => {
|
|
851
|
+
switch (kind) {
|
|
852
|
+
case "query": return "Query";
|
|
853
|
+
case "mutation": return "Mutation";
|
|
854
|
+
case "subscription": return "Subscription";
|
|
855
|
+
}
|
|
856
|
+
};
|
|
857
|
+
/**
|
|
858
|
+
* Emit TypeScript code for an operation.
|
|
859
|
+
*/
|
|
860
|
+
const emitOperation = (operation, options) => {
|
|
861
|
+
const lines = [];
|
|
862
|
+
const schema = options.schemaDocument ? createSchemaIndex(options.schemaDocument) : null;
|
|
863
|
+
const exportName = `${operation.name}Compat`;
|
|
864
|
+
const operationType = operation.kind;
|
|
865
|
+
lines.push(`export const ${exportName} = gql.${options.schemaName}(({ ${operationType}, $var }) =>`);
|
|
866
|
+
lines.push(` ${operationType}.compat({`);
|
|
867
|
+
lines.push(` name: ${JSON.stringify(operation.name)},`);
|
|
868
|
+
if (operation.variables.length > 0) {
|
|
869
|
+
lines.push(` variables: { ${emitVariables(operation.variables)} },`);
|
|
870
|
+
}
|
|
871
|
+
const rootTypeName = getRootTypeName(operation.kind);
|
|
872
|
+
lines.push(` fields: ({ f, $ }) => ({`);
|
|
873
|
+
const fieldLinesResult = emitSelections(operation.selections, 3, operation.variables, schema, rootTypeName);
|
|
874
|
+
if (fieldLinesResult.isErr()) {
|
|
875
|
+
return err(fieldLinesResult.error);
|
|
876
|
+
}
|
|
877
|
+
lines.push(fieldLinesResult.value);
|
|
878
|
+
lines.push(` }),`);
|
|
879
|
+
lines.push(` }),`);
|
|
880
|
+
lines.push(`);`);
|
|
881
|
+
return ok(lines.join("\n"));
|
|
882
|
+
};
|
|
883
|
+
/**
|
|
884
|
+
* Emit TypeScript code for a fragment.
|
|
885
|
+
*/
|
|
886
|
+
const emitFragment = (fragment, options) => {
|
|
887
|
+
const lines = [];
|
|
888
|
+
const schema = options.schemaDocument ? createSchemaIndex(options.schemaDocument) : null;
|
|
889
|
+
const hasVariables = fragment.variables.length > 0;
|
|
890
|
+
const exportName = `${fragment.name}Fragment`;
|
|
891
|
+
const destructure = hasVariables ? "fragment, $var" : "fragment";
|
|
892
|
+
lines.push(`export const ${exportName} = gql.${options.schemaName}(({ ${destructure} }) =>`);
|
|
893
|
+
lines.push(` fragment.${fragment.onType}({`);
|
|
894
|
+
if (hasVariables) {
|
|
895
|
+
lines.push(` variables: { ${emitVariables(fragment.variables)} },`);
|
|
896
|
+
}
|
|
897
|
+
const fieldsContext = hasVariables ? "{ f, $ }" : "{ f }";
|
|
898
|
+
lines.push(` fields: (${fieldsContext}) => ({`);
|
|
899
|
+
const fieldLinesResult = emitSelections(fragment.selections, 3, fragment.variables, schema, fragment.onType);
|
|
900
|
+
if (fieldLinesResult.isErr()) {
|
|
901
|
+
return err(fieldLinesResult.error);
|
|
902
|
+
}
|
|
903
|
+
lines.push(fieldLinesResult.value);
|
|
904
|
+
lines.push(` }),`);
|
|
905
|
+
lines.push(` }),`);
|
|
906
|
+
lines.push(`);`);
|
|
907
|
+
return ok(lines.join("\n"));
|
|
908
|
+
};
|
|
909
|
+
/**
|
|
910
|
+
* Emit variable definitions.
|
|
911
|
+
*/
|
|
912
|
+
const emitVariables = (variables) => {
|
|
913
|
+
return variables.map((v) => `...$var(${JSON.stringify(v.name)}).${v.typeName}(${JSON.stringify(v.modifier)})`).join(", ");
|
|
914
|
+
};
|
|
915
|
+
/**
|
|
916
|
+
* Emit field selections (public API).
|
|
917
|
+
* Converts variable array to Set<string> and delegates to internal implementation.
|
|
918
|
+
*/
|
|
919
|
+
const emitSelections = (selections, indent, variables, schema, parentTypeName) => {
|
|
920
|
+
const variableNames = new Set(variables.map((v) => v.name));
|
|
921
|
+
return emitSelectionsInternal(selections, indent, variableNames, schema, parentTypeName);
|
|
922
|
+
};
|
|
923
|
+
/**
|
|
924
|
+
* Internal implementation for emitting field selections.
|
|
925
|
+
* Takes variableNames as Set<string> for recursive calls.
|
|
926
|
+
*/
|
|
927
|
+
const emitSelectionsInternal = (selections, indent, variableNames, schema, parentTypeName) => {
|
|
928
|
+
const lines = [];
|
|
929
|
+
const inlineFragments = [];
|
|
930
|
+
const otherSelections = [];
|
|
931
|
+
for (const sel of selections) {
|
|
932
|
+
if (sel.kind === "inlineFragment") {
|
|
933
|
+
inlineFragments.push(sel);
|
|
934
|
+
} else {
|
|
935
|
+
otherSelections.push(sel);
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
for (const sel of otherSelections) {
|
|
939
|
+
const result = emitSingleSelection(sel, indent, variableNames, schema, parentTypeName);
|
|
940
|
+
if (result.isErr()) {
|
|
941
|
+
return err(result.error);
|
|
942
|
+
}
|
|
943
|
+
lines.push(result.value);
|
|
944
|
+
}
|
|
945
|
+
if (inlineFragments.length > 0) {
|
|
946
|
+
const unionResult = emitInlineFragmentsAsUnion(inlineFragments, indent, variableNames, schema);
|
|
947
|
+
if (unionResult.isErr()) {
|
|
948
|
+
return err(unionResult.error);
|
|
949
|
+
}
|
|
950
|
+
lines.push(unionResult.value);
|
|
951
|
+
}
|
|
952
|
+
return ok(lines.join("\n"));
|
|
953
|
+
};
|
|
954
|
+
/**
|
|
955
|
+
* Emit a single selection (field or fragment spread).
|
|
956
|
+
*/
|
|
957
|
+
const emitSingleSelection = (sel, indent, variableNames, schema, parentTypeName) => {
|
|
958
|
+
const padding = " ".repeat(indent);
|
|
959
|
+
switch (sel.kind) {
|
|
960
|
+
case "field": return emitFieldSelection(sel, indent, variableNames, schema, parentTypeName);
|
|
961
|
+
case "fragmentSpread": return ok(`${padding}...${sel.name}Fragment.spread(),`);
|
|
962
|
+
case "inlineFragment": return ok("");
|
|
963
|
+
}
|
|
964
|
+
};
|
|
965
|
+
/**
|
|
966
|
+
* Emit inline fragments grouped as a union selection.
|
|
967
|
+
* Format: { TypeA: ({ f }) => ({ ...fields }), TypeB: ({ f }) => ({ ...fields }) }
|
|
968
|
+
*/
|
|
969
|
+
const emitInlineFragmentsAsUnion = (inlineFragments, indent, variableNames, schema) => {
|
|
970
|
+
const padding = " ".repeat(indent);
|
|
971
|
+
for (const frag of inlineFragments) {
|
|
972
|
+
if (frag.onType === "") {
|
|
973
|
+
return err({
|
|
974
|
+
code: "GRAPHQL_INLINE_FRAGMENT_WITHOUT_TYPE",
|
|
975
|
+
message: "Inline fragments without type condition are not supported. Use `... on TypeName { }` syntax."
|
|
976
|
+
});
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
for (const frag of inlineFragments) {
|
|
980
|
+
if (schema && !schema.objects.has(frag.onType)) {
|
|
981
|
+
let isUnionMember = false;
|
|
982
|
+
for (const [, unionDef] of schema.unions) {
|
|
983
|
+
if (unionDef.members.has(frag.onType)) {
|
|
984
|
+
isUnionMember = true;
|
|
985
|
+
break;
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
if (!isUnionMember) {
|
|
989
|
+
return err({
|
|
990
|
+
code: "GRAPHQL_INLINE_FRAGMENT_ON_INTERFACE",
|
|
991
|
+
message: `Inline fragments on interface type "${frag.onType}" are not supported. Use union types instead.`,
|
|
992
|
+
onType: frag.onType
|
|
993
|
+
});
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
const entries = [];
|
|
998
|
+
for (const frag of inlineFragments) {
|
|
999
|
+
const innerPadding = " ".repeat(indent + 1);
|
|
1000
|
+
const fieldsResult = emitSelectionsInternal(frag.selections, indent + 2, variableNames, schema, frag.onType);
|
|
1001
|
+
if (fieldsResult.isErr()) {
|
|
1002
|
+
return err(fieldsResult.error);
|
|
1003
|
+
}
|
|
1004
|
+
entries.push(`${innerPadding}${frag.onType}: ({ f }) => ({
|
|
1005
|
+
${fieldsResult.value}
|
|
1006
|
+
${innerPadding}}),`);
|
|
1007
|
+
}
|
|
1008
|
+
return ok(`${padding}...({
|
|
1009
|
+
${entries.join("\n")}
|
|
1010
|
+
${padding}}),`);
|
|
1011
|
+
};
|
|
1012
|
+
/**
|
|
1013
|
+
* Emit a single field selection.
|
|
1014
|
+
*/
|
|
1015
|
+
const emitFieldSelection = (field, indent, variableNames, schema, parentTypeName) => {
|
|
1016
|
+
const padding = " ".repeat(indent);
|
|
1017
|
+
const args = field.arguments;
|
|
1018
|
+
const selections = field.selections;
|
|
1019
|
+
const hasArgs = args && args.length > 0;
|
|
1020
|
+
const hasSelections = selections && selections.length > 0;
|
|
1021
|
+
if (!hasArgs && !hasSelections) {
|
|
1022
|
+
return ok(`${padding}${field.name}: true,`);
|
|
1023
|
+
}
|
|
1024
|
+
let line = `${padding}...f.${field.name}(`;
|
|
1025
|
+
if (hasArgs) {
|
|
1026
|
+
const argsResult = emitArguments(args, variableNames, schema, parentTypeName, field.name);
|
|
1027
|
+
if (argsResult.isErr()) {
|
|
1028
|
+
return err(argsResult.error);
|
|
1029
|
+
}
|
|
1030
|
+
line += argsResult.value;
|
|
1031
|
+
}
|
|
1032
|
+
line += ")";
|
|
1033
|
+
if (hasSelections) {
|
|
1034
|
+
const hasInlineFragments = selections.some((s) => s.kind === "inlineFragment");
|
|
1035
|
+
const nestedParentType = schema && parentTypeName ? getFieldReturnType(schema, parentTypeName, field.name) ?? undefined : undefined;
|
|
1036
|
+
if (hasInlineFragments) {
|
|
1037
|
+
const nestedResult = emitSelectionsInternal(selections, indent + 1, variableNames, schema, nestedParentType);
|
|
1038
|
+
if (nestedResult.isErr()) {
|
|
1039
|
+
return err(nestedResult.error);
|
|
1040
|
+
}
|
|
1041
|
+
line += "({\n";
|
|
1042
|
+
line += `${nestedResult.value}\n`;
|
|
1043
|
+
line += `${padding}})`;
|
|
1044
|
+
} else {
|
|
1045
|
+
line += "(({ f }) => ({\n";
|
|
1046
|
+
const nestedResult = emitSelectionsInternal(selections, indent + 1, variableNames, schema, nestedParentType);
|
|
1047
|
+
if (nestedResult.isErr()) {
|
|
1048
|
+
return err(nestedResult.error);
|
|
1049
|
+
}
|
|
1050
|
+
line += `${nestedResult.value}\n`;
|
|
1051
|
+
line += `${padding}}))`;
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
line += ",";
|
|
1055
|
+
return ok(line);
|
|
1056
|
+
};
|
|
1057
|
+
/**
|
|
1058
|
+
* Check if a modifier represents a list type (contains []).
|
|
1059
|
+
*/
|
|
1060
|
+
const isListModifier = (modifier) => {
|
|
1061
|
+
return modifier.includes("[]");
|
|
1062
|
+
};
|
|
1063
|
+
/**
|
|
1064
|
+
* Determine if a value needs to be wrapped in an array for list coercion.
|
|
1065
|
+
* Returns true if:
|
|
1066
|
+
* - Expected type is a list
|
|
1067
|
+
* - Value is NOT already a list
|
|
1068
|
+
* - Value is NOT a variable (runtime handles coercion)
|
|
1069
|
+
* - Value is NOT null
|
|
1070
|
+
*/
|
|
1071
|
+
const needsListCoercion = (value, expectedModifier) => {
|
|
1072
|
+
if (!expectedModifier) return false;
|
|
1073
|
+
if (!isListModifier(expectedModifier)) return false;
|
|
1074
|
+
if (value.kind === "variable") return false;
|
|
1075
|
+
if (value.kind === "null") return false;
|
|
1076
|
+
if (value.kind === "list") return false;
|
|
1077
|
+
return true;
|
|
1078
|
+
};
|
|
1079
|
+
/**
|
|
1080
|
+
* Extract the element type from a list type by removing the outermost list modifier.
|
|
1081
|
+
* For example: "![]!" (non-null list of non-null) → "!" (non-null element)
|
|
1082
|
+
* "?[]![]!" (nested lists) → "?[]!" (inner list type)
|
|
1083
|
+
* Returns null if the modifier doesn't represent a list type.
|
|
1084
|
+
*/
|
|
1085
|
+
const getListElementType = (expectedType) => {
|
|
1086
|
+
const { modifier, typeName } = expectedType;
|
|
1087
|
+
const listMatch = modifier.match(/^(.+?)(\[\][!?])$/);
|
|
1088
|
+
if (!listMatch || !listMatch[1]) return null;
|
|
1089
|
+
return {
|
|
1090
|
+
typeName,
|
|
1091
|
+
modifier: listMatch[1]
|
|
1092
|
+
};
|
|
1093
|
+
};
|
|
1094
|
+
/**
|
|
1095
|
+
* Emit a value with type context for list coercion.
|
|
1096
|
+
*/
|
|
1097
|
+
const emitValueWithType = (value, expectedType, variableNames, schema) => {
|
|
1098
|
+
const shouldCoerce = needsListCoercion(value, expectedType?.modifier);
|
|
1099
|
+
if (value.kind === "object" && expectedType && schema) {
|
|
1100
|
+
return emitObjectWithType(value, expectedType.typeName, variableNames, schema, shouldCoerce);
|
|
1101
|
+
}
|
|
1102
|
+
if (value.kind === "list" && expectedType && schema) {
|
|
1103
|
+
const elementType = getListElementType(expectedType);
|
|
1104
|
+
if (elementType) {
|
|
1105
|
+
const values = [];
|
|
1106
|
+
for (const v of value.values) {
|
|
1107
|
+
const result$1 = emitValueWithType(v, elementType, variableNames, schema);
|
|
1108
|
+
if (result$1.isErr()) return result$1;
|
|
1109
|
+
values.push(result$1.value);
|
|
1110
|
+
}
|
|
1111
|
+
return ok(`[${values.join(", ")}]`);
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
const result = emitValue(value, variableNames);
|
|
1115
|
+
if (result.isErr()) return result;
|
|
1116
|
+
if (shouldCoerce) {
|
|
1117
|
+
return ok(`[${result.value}]`);
|
|
1118
|
+
}
|
|
1119
|
+
return result;
|
|
1120
|
+
};
|
|
1121
|
+
/**
|
|
1122
|
+
* Emit an object value with type context for recursive list coercion.
|
|
1123
|
+
*/
|
|
1124
|
+
const emitObjectWithType = (value, inputTypeName, variableNames, schema, wrapInArray) => {
|
|
1125
|
+
if (value.fields.length === 0) {
|
|
1126
|
+
return ok(wrapInArray ? "[{}]" : "{}");
|
|
1127
|
+
}
|
|
1128
|
+
const entries = [];
|
|
1129
|
+
for (const f of value.fields) {
|
|
1130
|
+
const fieldType = getInputFieldType(schema, inputTypeName, f.name);
|
|
1131
|
+
if (fieldType === null) {
|
|
1132
|
+
return err({
|
|
1133
|
+
code: "GRAPHQL_UNKNOWN_FIELD",
|
|
1134
|
+
message: `Unknown field "${f.name}" on input type "${inputTypeName}"`,
|
|
1135
|
+
typeName: inputTypeName,
|
|
1136
|
+
fieldName: f.name
|
|
1137
|
+
});
|
|
1138
|
+
}
|
|
1139
|
+
const result = emitValueWithType(f.value, fieldType, variableNames, schema);
|
|
1140
|
+
if (result.isErr()) {
|
|
1141
|
+
return err(result.error);
|
|
1142
|
+
}
|
|
1143
|
+
entries.push(`${f.name}: ${result.value}`);
|
|
1144
|
+
}
|
|
1145
|
+
const objectStr = `{ ${entries.join(", ")} }`;
|
|
1146
|
+
return ok(wrapInArray ? `[${objectStr}]` : objectStr);
|
|
1147
|
+
};
|
|
1148
|
+
/**
|
|
1149
|
+
* Emit field arguments with type context for list coercion.
|
|
1150
|
+
*/
|
|
1151
|
+
const emitArguments = (args, variableNames, schema, parentTypeName, fieldName) => {
|
|
1152
|
+
if (args.length === 0) {
|
|
1153
|
+
return ok("");
|
|
1154
|
+
}
|
|
1155
|
+
const argEntries = [];
|
|
1156
|
+
for (const arg of args) {
|
|
1157
|
+
const expectedType = schema && parentTypeName && fieldName ? getArgumentType(schema, parentTypeName, fieldName, arg.name) : null;
|
|
1158
|
+
const result = emitValueWithType(arg.value, expectedType, variableNames, schema);
|
|
1159
|
+
if (result.isErr()) {
|
|
1160
|
+
return err(result.error);
|
|
1161
|
+
}
|
|
1162
|
+
argEntries.push(`${arg.name}: ${result.value}`);
|
|
1163
|
+
}
|
|
1164
|
+
return ok(`{ ${argEntries.join(", ")} }`);
|
|
1165
|
+
};
|
|
1166
|
+
/**
|
|
1167
|
+
* Emit a value (literal or variable reference).
|
|
1168
|
+
*/
|
|
1169
|
+
const emitValue = (value, variableNames) => {
|
|
1170
|
+
switch (value.kind) {
|
|
1171
|
+
case "variable":
|
|
1172
|
+
if (variableNames.has(value.name)) {
|
|
1173
|
+
return ok(`$.${value.name}`);
|
|
1174
|
+
}
|
|
1175
|
+
return err({
|
|
1176
|
+
code: "GRAPHQL_UNDECLARED_VARIABLE",
|
|
1177
|
+
message: `Variable "$${value.name}" is not declared in the operation`,
|
|
1178
|
+
variableName: value.name
|
|
1179
|
+
});
|
|
1180
|
+
case "int":
|
|
1181
|
+
case "float": return ok(value.value);
|
|
1182
|
+
case "string": return ok(JSON.stringify(value.value));
|
|
1183
|
+
case "boolean": return ok(value.value ? "true" : "false");
|
|
1184
|
+
case "null": return ok("null");
|
|
1185
|
+
case "enum": return ok(JSON.stringify(value.value));
|
|
1186
|
+
case "list": {
|
|
1187
|
+
const values = [];
|
|
1188
|
+
for (const v of value.values) {
|
|
1189
|
+
const result = emitValue(v, variableNames);
|
|
1190
|
+
if (result.isErr()) {
|
|
1191
|
+
return err(result.error);
|
|
1192
|
+
}
|
|
1193
|
+
values.push(result.value);
|
|
1194
|
+
}
|
|
1195
|
+
return ok(`[${values.join(", ")}]`);
|
|
1196
|
+
}
|
|
1197
|
+
case "object": {
|
|
1198
|
+
if (value.fields.length === 0) {
|
|
1199
|
+
return ok("{}");
|
|
1200
|
+
}
|
|
1201
|
+
const entries = [];
|
|
1202
|
+
for (const f of value.fields) {
|
|
1203
|
+
const result = emitValue(f.value, variableNames);
|
|
1204
|
+
if (result.isErr()) {
|
|
1205
|
+
return err(result.error);
|
|
1206
|
+
}
|
|
1207
|
+
entries.push(`${f.name}: ${result.value}`);
|
|
1208
|
+
}
|
|
1209
|
+
return ok(`{ ${entries.join(", ")} }`);
|
|
1210
|
+
}
|
|
1211
|
+
}
|
|
1212
|
+
};
|
|
1213
|
+
|
|
1110
1214
|
//#endregion
|
|
1111
1215
|
//#region packages/codegen/src/inject-template.ts
|
|
1112
1216
|
const templateContents = `\
|
|
@@ -1611,5 +1715,5 @@ export * from "./_internal";
|
|
|
1611
1715
|
};
|
|
1612
1716
|
|
|
1613
1717
|
//#endregion
|
|
1614
|
-
export { collectVariableUsages, emitFragment, emitOperation, hashSchema, inferVariablesFromUsages, isModifierAssignable, loadSchema, mergeModifiers, mergeVariableUsages, parseGraphqlFile, parseGraphqlSource, parseTypeNode, runCodegen, sortFragmentsByDependency, transformParsedGraphql, writeInjectTemplate };
|
|
1718
|
+
export { collectVariableUsages, emitFragment, emitOperation, getArgumentType, getFieldReturnType, getInputFieldType, hashSchema, inferVariablesFromUsages, isModifierAssignable, loadSchema, mergeModifiers, mergeVariableUsages, parseGraphqlFile, parseGraphqlSource, parseTypeNode, runCodegen, sortFragmentsByDependency, transformParsedGraphql, writeInjectTemplate };
|
|
1615
1719
|
//# sourceMappingURL=index.mjs.map
|