@soda-gql/codegen 0.11.20 → 0.11.22

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 CHANGED
@@ -6,271 +6,6 @@ let node_path = require("node:path");
6
6
  let esbuild = require("esbuild");
7
7
  let node_crypto = require("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 ? require_generator.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 (0, neverthrow.err)(fieldLinesResult.error);
28
- }
29
- lines.push(fieldLinesResult.value);
30
- lines.push(` }),`);
31
- lines.push(` }),`);
32
- lines.push(`);`);
33
- return (0, neverthrow.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 ? require_generator.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 (0, neverthrow.err)(fieldLinesResult.error);
54
- }
55
- lines.push(fieldLinesResult.value);
56
- lines.push(` }),`);
57
- lines.push(` }),`);
58
- lines.push(`);`);
59
- return (0, neverthrow.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 (0, neverthrow.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 (0, neverthrow.err)(unionResult.error);
101
- }
102
- lines.push(unionResult.value);
103
- }
104
- return (0, neverthrow.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 (0, neverthrow.ok)(`${padding}...${sel.name}Fragment.spread(),`);
114
- case "inlineFragment": return (0, neverthrow.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 (0, neverthrow.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 (0, neverthrow.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 (0, neverthrow.err)(fieldsResult.error);
155
- }
156
- entries.push(`${innerPadding}${frag.onType}: ({ f }) => ({
157
- ${fieldsResult.value}
158
- ${innerPadding}}),`);
159
- }
160
- return (0, neverthrow.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 (0, neverthrow.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 (0, neverthrow.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 (0, neverthrow.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 (0, neverthrow.err)(nestedResult.error);
200
- }
201
- line += `${nestedResult.value}\n`;
202
- line += `${padding}}))`;
203
- }
204
- }
205
- line += ",";
206
- return (0, neverthrow.ok)(line);
207
- };
208
- /**
209
- * Emit field arguments.
210
- */
211
- const emitArguments = (args, variableNames) => {
212
- if (args.length === 0) {
213
- return (0, neverthrow.ok)("");
214
- }
215
- const argEntries = [];
216
- for (const arg of args) {
217
- const result = emitValue(arg.value, variableNames);
218
- if (result.isErr()) {
219
- return (0, neverthrow.err)(result.error);
220
- }
221
- argEntries.push(`${arg.name}: ${result.value}`);
222
- }
223
- return (0, neverthrow.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 (0, neverthrow.ok)(`$.${value.name}`);
233
- }
234
- return (0, neverthrow.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 (0, neverthrow.ok)(value.value);
241
- case "string": return (0, neverthrow.ok)(JSON.stringify(value.value));
242
- case "boolean": return (0, neverthrow.ok)(value.value ? "true" : "false");
243
- case "null": return (0, neverthrow.ok)("null");
244
- case "enum": return (0, neverthrow.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 (0, neverthrow.err)(result.error);
251
- }
252
- values.push(result.value);
253
- }
254
- return (0, neverthrow.ok)(`[${values.join(", ")}]`);
255
- }
256
- case "object": {
257
- if (value.fields.length === 0) {
258
- return (0, neverthrow.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 (0, neverthrow.err)(result.error);
265
- }
266
- entries.push(`${f.name}: ${result.value}`);
267
- }
268
- return (0, neverthrow.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,383 @@ 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
+ * Uses schema.operationTypes if available, falls back to standard names.
850
+ */
851
+ const getRootTypeName = (schema, kind) => {
852
+ if (schema) {
853
+ switch (kind) {
854
+ case "query": return schema.operationTypes.query ?? "Query";
855
+ case "mutation": return schema.operationTypes.mutation ?? "Mutation";
856
+ case "subscription": return schema.operationTypes.subscription ?? "Subscription";
857
+ }
858
+ }
859
+ switch (kind) {
860
+ case "query": return "Query";
861
+ case "mutation": return "Mutation";
862
+ case "subscription": return "Subscription";
863
+ }
864
+ };
865
+ /**
866
+ * Emit TypeScript code for an operation.
867
+ */
868
+ const emitOperation = (operation, options) => {
869
+ const lines = [];
870
+ const schema = options.schemaDocument ? require_generator.createSchemaIndex(options.schemaDocument) : null;
871
+ const exportName = `${operation.name}Compat`;
872
+ const operationType = operation.kind;
873
+ lines.push(`export const ${exportName} = gql.${options.schemaName}(({ ${operationType}, $var }) =>`);
874
+ lines.push(` ${operationType}.compat({`);
875
+ lines.push(` name: ${JSON.stringify(operation.name)},`);
876
+ if (operation.variables.length > 0) {
877
+ lines.push(` variables: { ${emitVariables(operation.variables)} },`);
878
+ }
879
+ const rootTypeName = getRootTypeName(schema, operation.kind);
880
+ lines.push(` fields: ({ f, $ }) => ({`);
881
+ const fieldLinesResult = emitSelections(operation.selections, 3, operation.variables, schema, rootTypeName);
882
+ if (fieldLinesResult.isErr()) {
883
+ return (0, neverthrow.err)(fieldLinesResult.error);
884
+ }
885
+ lines.push(fieldLinesResult.value);
886
+ lines.push(` }),`);
887
+ lines.push(` }),`);
888
+ lines.push(`);`);
889
+ return (0, neverthrow.ok)(lines.join("\n"));
890
+ };
891
+ /**
892
+ * Emit TypeScript code for a fragment.
893
+ */
894
+ const emitFragment = (fragment, options) => {
895
+ const lines = [];
896
+ const schema = options.schemaDocument ? require_generator.createSchemaIndex(options.schemaDocument) : null;
897
+ const hasVariables = fragment.variables.length > 0;
898
+ const exportName = `${fragment.name}Fragment`;
899
+ const destructure = hasVariables ? "fragment, $var" : "fragment";
900
+ lines.push(`export const ${exportName} = gql.${options.schemaName}(({ ${destructure} }) =>`);
901
+ lines.push(` fragment.${fragment.onType}({`);
902
+ if (hasVariables) {
903
+ lines.push(` variables: { ${emitVariables(fragment.variables)} },`);
904
+ }
905
+ const fieldsContext = hasVariables ? "{ f, $ }" : "{ f }";
906
+ lines.push(` fields: (${fieldsContext}) => ({`);
907
+ const fieldLinesResult = emitSelections(fragment.selections, 3, fragment.variables, schema, fragment.onType);
908
+ if (fieldLinesResult.isErr()) {
909
+ return (0, neverthrow.err)(fieldLinesResult.error);
910
+ }
911
+ lines.push(fieldLinesResult.value);
912
+ lines.push(` }),`);
913
+ lines.push(` }),`);
914
+ lines.push(`);`);
915
+ return (0, neverthrow.ok)(lines.join("\n"));
916
+ };
917
+ /**
918
+ * Emit variable definitions.
919
+ */
920
+ const emitVariables = (variables) => {
921
+ return variables.map((v) => `...$var(${JSON.stringify(v.name)}).${v.typeName}(${JSON.stringify(v.modifier)})`).join(", ");
922
+ };
923
+ /**
924
+ * Emit field selections (public API).
925
+ * Converts variable array to Set<string> and delegates to internal implementation.
926
+ */
927
+ const emitSelections = (selections, indent, variables, schema, parentTypeName) => {
928
+ const variableNames = new Set(variables.map((v) => v.name));
929
+ return emitSelectionsInternal(selections, indent, variableNames, schema, parentTypeName);
930
+ };
931
+ /**
932
+ * Internal implementation for emitting field selections.
933
+ * Takes variableNames as Set<string> for recursive calls.
934
+ */
935
+ const emitSelectionsInternal = (selections, indent, variableNames, schema, parentTypeName) => {
936
+ const lines = [];
937
+ const inlineFragments = [];
938
+ const otherSelections = [];
939
+ for (const sel of selections) {
940
+ if (sel.kind === "inlineFragment") {
941
+ inlineFragments.push(sel);
942
+ } else {
943
+ otherSelections.push(sel);
944
+ }
945
+ }
946
+ for (const sel of otherSelections) {
947
+ const result = emitSingleSelection(sel, indent, variableNames, schema, parentTypeName);
948
+ if (result.isErr()) {
949
+ return (0, neverthrow.err)(result.error);
950
+ }
951
+ lines.push(result.value);
952
+ }
953
+ if (inlineFragments.length > 0) {
954
+ const unionResult = emitInlineFragmentsAsUnion(inlineFragments, indent, variableNames, schema);
955
+ if (unionResult.isErr()) {
956
+ return (0, neverthrow.err)(unionResult.error);
957
+ }
958
+ lines.push(unionResult.value);
959
+ }
960
+ return (0, neverthrow.ok)(lines.join("\n"));
961
+ };
962
+ /**
963
+ * Emit a single selection (field or fragment spread).
964
+ */
965
+ const emitSingleSelection = (sel, indent, variableNames, schema, parentTypeName) => {
966
+ const padding = " ".repeat(indent);
967
+ switch (sel.kind) {
968
+ case "field": return emitFieldSelection(sel, indent, variableNames, schema, parentTypeName);
969
+ case "fragmentSpread": return (0, neverthrow.ok)(`${padding}...${sel.name}Fragment.spread(),`);
970
+ case "inlineFragment": return (0, neverthrow.ok)("");
971
+ }
972
+ };
973
+ /**
974
+ * Emit inline fragments grouped as a union selection.
975
+ * Format: { TypeA: ({ f }) => ({ ...fields }), TypeB: ({ f }) => ({ ...fields }) }
976
+ */
977
+ const emitInlineFragmentsAsUnion = (inlineFragments, indent, variableNames, schema) => {
978
+ const padding = " ".repeat(indent);
979
+ for (const frag of inlineFragments) {
980
+ if (frag.onType === "") {
981
+ return (0, neverthrow.err)({
982
+ code: "GRAPHQL_INLINE_FRAGMENT_WITHOUT_TYPE",
983
+ message: "Inline fragments without type condition are not supported. Use `... on TypeName { }` syntax."
984
+ });
985
+ }
986
+ }
987
+ for (const frag of inlineFragments) {
988
+ if (schema && !schema.objects.has(frag.onType)) {
989
+ let isUnionMember = false;
990
+ for (const [, unionDef] of schema.unions) {
991
+ if (unionDef.members.has(frag.onType)) {
992
+ isUnionMember = true;
993
+ break;
994
+ }
995
+ }
996
+ if (!isUnionMember) {
997
+ return (0, neverthrow.err)({
998
+ code: "GRAPHQL_INLINE_FRAGMENT_ON_INTERFACE",
999
+ message: `Inline fragments on interface type "${frag.onType}" are not supported. Use union types instead.`,
1000
+ onType: frag.onType
1001
+ });
1002
+ }
1003
+ }
1004
+ }
1005
+ const entries = [];
1006
+ for (const frag of inlineFragments) {
1007
+ const innerPadding = " ".repeat(indent + 1);
1008
+ const fieldsResult = emitSelectionsInternal(frag.selections, indent + 2, variableNames, schema, frag.onType);
1009
+ if (fieldsResult.isErr()) {
1010
+ return (0, neverthrow.err)(fieldsResult.error);
1011
+ }
1012
+ entries.push(`${innerPadding}${frag.onType}: ({ f }) => ({
1013
+ ${fieldsResult.value}
1014
+ ${innerPadding}}),`);
1015
+ }
1016
+ return (0, neverthrow.ok)(`${padding}...({
1017
+ ${entries.join("\n")}
1018
+ ${padding}}),`);
1019
+ };
1020
+ /**
1021
+ * Emit a single field selection.
1022
+ */
1023
+ const emitFieldSelection = (field, indent, variableNames, schema, parentTypeName) => {
1024
+ const padding = " ".repeat(indent);
1025
+ const args = field.arguments;
1026
+ const selections = field.selections;
1027
+ const hasArgs = args && args.length > 0;
1028
+ const hasSelections = selections && selections.length > 0;
1029
+ if (!hasArgs && !hasSelections) {
1030
+ return (0, neverthrow.ok)(`${padding}${field.name}: true,`);
1031
+ }
1032
+ let line = `${padding}...f.${field.name}(`;
1033
+ if (hasArgs) {
1034
+ const argsResult = emitArguments(args, variableNames, schema, parentTypeName, field.name);
1035
+ if (argsResult.isErr()) {
1036
+ return (0, neverthrow.err)(argsResult.error);
1037
+ }
1038
+ line += argsResult.value;
1039
+ }
1040
+ line += ")";
1041
+ if (hasSelections) {
1042
+ const hasInlineFragments = selections.some((s) => s.kind === "inlineFragment");
1043
+ const nestedParentType = schema && parentTypeName ? getFieldReturnType(schema, parentTypeName, field.name) ?? undefined : undefined;
1044
+ if (hasInlineFragments) {
1045
+ const nestedResult = emitSelectionsInternal(selections, indent + 1, variableNames, schema, nestedParentType);
1046
+ if (nestedResult.isErr()) {
1047
+ return (0, neverthrow.err)(nestedResult.error);
1048
+ }
1049
+ line += "({\n";
1050
+ line += `${nestedResult.value}\n`;
1051
+ line += `${padding}})`;
1052
+ } else {
1053
+ line += "(({ f }) => ({\n";
1054
+ const nestedResult = emitSelectionsInternal(selections, indent + 1, variableNames, schema, nestedParentType);
1055
+ if (nestedResult.isErr()) {
1056
+ return (0, neverthrow.err)(nestedResult.error);
1057
+ }
1058
+ line += `${nestedResult.value}\n`;
1059
+ line += `${padding}}))`;
1060
+ }
1061
+ }
1062
+ line += ",";
1063
+ return (0, neverthrow.ok)(line);
1064
+ };
1065
+ /**
1066
+ * Check if a modifier represents a list type (contains []).
1067
+ */
1068
+ const isListModifier = (modifier) => {
1069
+ return modifier.includes("[]");
1070
+ };
1071
+ /**
1072
+ * Determine if a value needs to be wrapped in an array for list coercion.
1073
+ * Returns true if:
1074
+ * - Expected type is a list
1075
+ * - Value is NOT already a list
1076
+ * - Value is NOT a variable (runtime handles coercion)
1077
+ * - Value is NOT null
1078
+ */
1079
+ const needsListCoercion = (value, expectedModifier) => {
1080
+ if (!expectedModifier) return false;
1081
+ if (!isListModifier(expectedModifier)) return false;
1082
+ if (value.kind === "variable") return false;
1083
+ if (value.kind === "null") return false;
1084
+ if (value.kind === "list") return false;
1085
+ return true;
1086
+ };
1087
+ /**
1088
+ * Extract the element type from a list type by removing the outermost list modifier.
1089
+ * For example: "![]!" (non-null list of non-null) → "!" (non-null element)
1090
+ * "?[]![]!" (nested lists) → "?[]!" (inner list type)
1091
+ * Returns null if the modifier doesn't represent a list type.
1092
+ */
1093
+ const getListElementType = (expectedType) => {
1094
+ const { modifier, typeName } = expectedType;
1095
+ const listMatch = modifier.match(/^(.+?)(\[\][!?])$/);
1096
+ if (!listMatch || !listMatch[1]) return null;
1097
+ return {
1098
+ typeName,
1099
+ modifier: listMatch[1]
1100
+ };
1101
+ };
1102
+ /**
1103
+ * Emit a value with type context for list coercion.
1104
+ */
1105
+ const emitValueWithType = (value, expectedType, variableNames, schema) => {
1106
+ const shouldCoerce = needsListCoercion(value, expectedType?.modifier);
1107
+ if (value.kind === "object" && expectedType && schema) {
1108
+ return emitObjectWithType(value, expectedType.typeName, variableNames, schema, shouldCoerce);
1109
+ }
1110
+ if (value.kind === "list" && expectedType && schema) {
1111
+ const elementType = getListElementType(expectedType);
1112
+ if (elementType) {
1113
+ const values = [];
1114
+ for (const v of value.values) {
1115
+ const result$1 = emitValueWithType(v, elementType, variableNames, schema);
1116
+ if (result$1.isErr()) return result$1;
1117
+ values.push(result$1.value);
1118
+ }
1119
+ return (0, neverthrow.ok)(`[${values.join(", ")}]`);
1120
+ }
1121
+ }
1122
+ const result = emitValue(value, variableNames);
1123
+ if (result.isErr()) return result;
1124
+ if (shouldCoerce) {
1125
+ return (0, neverthrow.ok)(`[${result.value}]`);
1126
+ }
1127
+ return result;
1128
+ };
1129
+ /**
1130
+ * Emit an object value with type context for recursive list coercion.
1131
+ */
1132
+ const emitObjectWithType = (value, inputTypeName, variableNames, schema, wrapInArray) => {
1133
+ if (value.fields.length === 0) {
1134
+ return (0, neverthrow.ok)(wrapInArray ? "[{}]" : "{}");
1135
+ }
1136
+ const entries = [];
1137
+ for (const f of value.fields) {
1138
+ const fieldType = getInputFieldType(schema, inputTypeName, f.name);
1139
+ if (fieldType === null) {
1140
+ return (0, neverthrow.err)({
1141
+ code: "GRAPHQL_UNKNOWN_FIELD",
1142
+ message: `Unknown field "${f.name}" on input type "${inputTypeName}"`,
1143
+ typeName: inputTypeName,
1144
+ fieldName: f.name
1145
+ });
1146
+ }
1147
+ const result = emitValueWithType(f.value, fieldType, variableNames, schema);
1148
+ if (result.isErr()) {
1149
+ return (0, neverthrow.err)(result.error);
1150
+ }
1151
+ entries.push(`${f.name}: ${result.value}`);
1152
+ }
1153
+ const objectStr = `{ ${entries.join(", ")} }`;
1154
+ return (0, neverthrow.ok)(wrapInArray ? `[${objectStr}]` : objectStr);
1155
+ };
1156
+ /**
1157
+ * Emit field arguments with type context for list coercion.
1158
+ */
1159
+ const emitArguments = (args, variableNames, schema, parentTypeName, fieldName) => {
1160
+ if (args.length === 0) {
1161
+ return (0, neverthrow.ok)("");
1162
+ }
1163
+ const argEntries = [];
1164
+ for (const arg of args) {
1165
+ const expectedType = schema && parentTypeName && fieldName ? getArgumentType(schema, parentTypeName, fieldName, arg.name) : null;
1166
+ const result = emitValueWithType(arg.value, expectedType, variableNames, schema);
1167
+ if (result.isErr()) {
1168
+ return (0, neverthrow.err)(result.error);
1169
+ }
1170
+ argEntries.push(`${arg.name}: ${result.value}`);
1171
+ }
1172
+ return (0, neverthrow.ok)(`{ ${argEntries.join(", ")} }`);
1173
+ };
1174
+ /**
1175
+ * Emit a value (literal or variable reference).
1176
+ */
1177
+ const emitValue = (value, variableNames) => {
1178
+ switch (value.kind) {
1179
+ case "variable":
1180
+ if (variableNames.has(value.name)) {
1181
+ return (0, neverthrow.ok)(`$.${value.name}`);
1182
+ }
1183
+ return (0, neverthrow.err)({
1184
+ code: "GRAPHQL_UNDECLARED_VARIABLE",
1185
+ message: `Variable "$${value.name}" is not declared in the operation`,
1186
+ variableName: value.name
1187
+ });
1188
+ case "int":
1189
+ case "float": return (0, neverthrow.ok)(value.value);
1190
+ case "string": return (0, neverthrow.ok)(JSON.stringify(value.value));
1191
+ case "boolean": return (0, neverthrow.ok)(value.value ? "true" : "false");
1192
+ case "null": return (0, neverthrow.ok)("null");
1193
+ case "enum": return (0, neverthrow.ok)(JSON.stringify(value.value));
1194
+ case "list": {
1195
+ const values = [];
1196
+ for (const v of value.values) {
1197
+ const result = emitValue(v, variableNames);
1198
+ if (result.isErr()) {
1199
+ return (0, neverthrow.err)(result.error);
1200
+ }
1201
+ values.push(result.value);
1202
+ }
1203
+ return (0, neverthrow.ok)(`[${values.join(", ")}]`);
1204
+ }
1205
+ case "object": {
1206
+ if (value.fields.length === 0) {
1207
+ return (0, neverthrow.ok)("{}");
1208
+ }
1209
+ const entries = [];
1210
+ for (const f of value.fields) {
1211
+ const result = emitValue(f.value, variableNames);
1212
+ if (result.isErr()) {
1213
+ return (0, neverthrow.err)(result.error);
1214
+ }
1215
+ entries.push(`${f.name}: ${result.value}`);
1216
+ }
1217
+ return (0, neverthrow.ok)(`{ ${entries.join(", ")} }`);
1218
+ }
1219
+ }
1220
+ };
1221
+
1110
1222
  //#endregion
1111
1223
  //#region packages/codegen/src/inject-template.ts
1112
1224
  const templateContents = `\
@@ -1614,6 +1726,9 @@ export * from "./_internal";
1614
1726
  exports.collectVariableUsages = collectVariableUsages;
1615
1727
  exports.emitFragment = emitFragment;
1616
1728
  exports.emitOperation = emitOperation;
1729
+ exports.getArgumentType = getArgumentType;
1730
+ exports.getFieldReturnType = getFieldReturnType;
1731
+ exports.getInputFieldType = getInputFieldType;
1617
1732
  exports.hashSchema = hashSchema;
1618
1733
  exports.inferVariablesFromUsages = inferVariablesFromUsages;
1619
1734
  exports.isModifierAssignable = isModifierAssignable;