@comet/admin-generator 8.17.1 → 9.0.0-beta.0

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.
Files changed (87) hide show
  1. package/bin/admin-generator.mjs +3 -0
  2. package/dist/adminGenerator.d.mts +1 -0
  3. package/dist/adminGenerator.mjs +4441 -0
  4. package/dist/index.d.mts +344 -0
  5. package/dist/index.mjs +4440 -0
  6. package/package.json +31 -21
  7. package/bin/admin-generator.js +0 -8
  8. package/lib/adminGenerator.d.ts +0 -1
  9. package/lib/adminGenerator.js +0 -8
  10. package/lib/commands/generate/config/parseConfig.d.ts +0 -1
  11. package/lib/commands/generate/config/parseConfig.js +0 -72
  12. package/lib/commands/generate/config/transformConfig.d.ts +0 -7
  13. package/lib/commands/generate/config/transformConfig.js +0 -264
  14. package/lib/commands/generate/generate-command.d.ts +0 -340
  15. package/lib/commands/generate/generate-command.js +0 -112
  16. package/lib/commands/generate/generateForm/asyncSelect/generateAsyncSelect.d.ts +0 -26
  17. package/lib/commands/generate/generateForm/asyncSelect/generateAsyncSelect.js +0 -364
  18. package/lib/commands/generate/generateForm/extractErrorEnums.d.ts +0 -16
  19. package/lib/commands/generate/generateForm/extractErrorEnums.js +0 -100
  20. package/lib/commands/generate/generateForm/flatFormFieldsFromFormConfig.d.ts +0 -2
  21. package/lib/commands/generate/generateForm/flatFormFieldsFromFormConfig.js +0 -22
  22. package/lib/commands/generate/generateForm/formField/findIntrospectionFieldType.d.ts +0 -6
  23. package/lib/commands/generate/generateForm/formField/findIntrospectionFieldType.js +0 -22
  24. package/lib/commands/generate/generateForm/formField/options.d.ts +0 -24
  25. package/lib/commands/generate/generateForm/formField/options.js +0 -85
  26. package/lib/commands/generate/generateForm/generateComponentFormField.d.ts +0 -5
  27. package/lib/commands/generate/generateForm/generateComponentFormField.js +0 -22
  28. package/lib/commands/generate/generateForm/generateErrorHandling.d.ts +0 -8
  29. package/lib/commands/generate/generateForm/generateErrorHandling.js +0 -24
  30. package/lib/commands/generate/generateForm/generateErrorMessages.d.ts +0 -11
  31. package/lib/commands/generate/generateForm/generateErrorMessages.js +0 -28
  32. package/lib/commands/generate/generateForm/generateFields.d.ts +0 -42
  33. package/lib/commands/generate/generateForm/generateFields.js +0 -87
  34. package/lib/commands/generate/generateForm/generateForm.d.ts +0 -14
  35. package/lib/commands/generate/generateForm/generateForm.js +0 -565
  36. package/lib/commands/generate/generateForm/generateFormField.d.ts +0 -12
  37. package/lib/commands/generate/generateForm/generateFormField.js +0 -368
  38. package/lib/commands/generate/generateForm/generateFormLayout.d.ts +0 -12
  39. package/lib/commands/generate/generateForm/generateFormLayout.js +0 -154
  40. package/lib/commands/generate/generateForm/generateFormValues.d.ts +0 -40
  41. package/lib/commands/generate/generateForm/generateFormValues.js +0 -219
  42. package/lib/commands/generate/generateForm/generateFragmentByFormFragmentFields.d.ts +0 -11
  43. package/lib/commands/generate/generateForm/generateFragmentByFormFragmentFields.js +0 -29
  44. package/lib/commands/generate/generateForm/getForwardedGqlArgs.d.ts +0 -18
  45. package/lib/commands/generate/generateForm/getForwardedGqlArgs.js +0 -79
  46. package/lib/commands/generate/generateGrid/detectMuiXVersion.d.ts +0 -5
  47. package/lib/commands/generate/generateGrid/detectMuiXVersion.js +0 -32
  48. package/lib/commands/generate/generateGrid/findInputObjectType.d.ts +0 -2
  49. package/lib/commands/generate/generateGrid/findInputObjectType.js +0 -15
  50. package/lib/commands/generate/generateGrid/generateGqlFieldList.d.ts +0 -6
  51. package/lib/commands/generate/generateGrid/generateGqlFieldList.js +0 -56
  52. package/lib/commands/generate/generateGrid/generateGrid.d.ts +0 -16
  53. package/lib/commands/generate/generateGrid/generateGrid.js +0 -1017
  54. package/lib/commands/generate/generateGrid/generateGridToolbar.d.ts +0 -15
  55. package/lib/commands/generate/generateGrid/generateGridToolbar.js +0 -90
  56. package/lib/commands/generate/generateGrid/getForwardedGqlArgs.d.ts +0 -13
  57. package/lib/commands/generate/generateGrid/getForwardedGqlArgs.js +0 -59
  58. package/lib/commands/generate/generateGrid/getPropsForFilterProp.d.ts +0 -14
  59. package/lib/commands/generate/generateGrid/getPropsForFilterProp.js +0 -13
  60. package/lib/commands/generate/generateGrid/usableFields.d.ts +0 -14
  61. package/lib/commands/generate/generateGrid/usableFields.js +0 -3
  62. package/lib/commands/generate/utils/camelCaseToHumanReadable.d.ts +0 -1
  63. package/lib/commands/generate/utils/camelCaseToHumanReadable.js +0 -7
  64. package/lib/commands/generate/utils/columnVisibility.d.ts +0 -6
  65. package/lib/commands/generate/utils/columnVisibility.js +0 -2
  66. package/lib/commands/generate/utils/convertConfigImport.d.ts +0 -6
  67. package/lib/commands/generate/utils/convertConfigImport.js +0 -14
  68. package/lib/commands/generate/utils/findMutationType.d.ts +0 -3
  69. package/lib/commands/generate/utils/findMutationType.js +0 -18
  70. package/lib/commands/generate/utils/findQueryType.d.ts +0 -2
  71. package/lib/commands/generate/utils/findQueryType.js +0 -18
  72. package/lib/commands/generate/utils/findRootBlocks.d.ts +0 -8
  73. package/lib/commands/generate/utils/findRootBlocks.js +0 -66
  74. package/lib/commands/generate/utils/generateGqlOperation.d.ts +0 -12
  75. package/lib/commands/generate/utils/generateGqlOperation.js +0 -87
  76. package/lib/commands/generate/utils/generateImportsCode.d.ts +0 -6
  77. package/lib/commands/generate/utils/generateImportsCode.js +0 -31
  78. package/lib/commands/generate/utils/intl.d.ts +0 -20
  79. package/lib/commands/generate/utils/intl.js +0 -44
  80. package/lib/commands/generate/utils/isFieldOptional.d.ts +0 -7
  81. package/lib/commands/generate/utils/isFieldOptional.js +0 -21
  82. package/lib/commands/generate/utils/runtimeTypeGuards.d.ts +0 -20
  83. package/lib/commands/generate/utils/runtimeTypeGuards.js +0 -22
  84. package/lib/commands/generate/utils/writeGenerated.d.ts +0 -1
  85. package/lib/commands/generate/utils/writeGenerated.js +0 -123
  86. package/lib/index.d.ts +0 -2
  87. package/lib/index.js +0 -6
package/dist/index.mjs ADDED
@@ -0,0 +1,4440 @@
1
+ import { GraphQLFileLoader } from "@graphql-tools/graphql-file-loader";
2
+ import { loadSchema } from "@graphql-tools/load";
3
+ import { exec } from "child_process";
4
+ import { Command } from "commander";
5
+ import fs, { existsSync, promises, readFileSync } from "fs";
6
+ import { glob } from "glob";
7
+ import { introspectionFromSchema } from "graphql";
8
+ import * as path from "path";
9
+ import { basename, dirname } from "path";
10
+ import { promisify } from "util";
11
+ import { createJiti } from "jiti";
12
+ import * as ts$1 from "typescript";
13
+ import ts from "typescript";
14
+ import { camelCase, capitalCase } from "change-case";
15
+ import { FormattedMessage } from "react-intl";
16
+ import pluralize from "pluralize";
17
+ import objectPath from "object-path";
18
+
19
+ //#region rolldown:runtime
20
+ var __commonJSMin = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
21
+
22
+ //#endregion
23
+ //#region src/commands/generate/config/transformConfig.ts
24
+ const supportedImportPaths = [
25
+ "[type=grid].columns.filterOperators",
26
+ "[type=grid].columns.block",
27
+ "[type=grid].columns.component",
28
+ ...Array.from(Array(5).keys()).map((i) => `[type=form]${".fields".repeat(i + 1)}.validate`),
29
+ ...Array.from(Array(5).keys()).map((i) => `[type=form]${".fields".repeat(i + 1)}.block`),
30
+ ...Array.from(Array(5).keys()).map((i) => `[type=form]${".fields".repeat(i + 1)}.component`)
31
+ ];
32
+ const supportedInlineCodePaths = ["[type=grid].columns.renderCell", ...Array.from(Array(5).keys()).map((i) => `[type=form]${".fields".repeat(i + 1)}.validate`)];
33
+ function transformConfigFile(fileName, sourceText) {
34
+ const sourceFile = ts$1.createSourceFile(fileName, sourceText, ts$1.ScriptTarget.ES2024, true);
35
+ const importedIdentifiers = collectImports(sourceFile);
36
+ function configTransformer() {
37
+ return (context) => {
38
+ const visit = (node, path$1) => {
39
+ if (ts$1.isCallExpression(node)) {
40
+ if (node.expression.getText() === "injectFormVariables") {
41
+ if (!path$1.startsWith("[type=form].fields")) throw new Error(`injectFormVariables can only be used in form field definitions: ${path$1}`);
42
+ if (node.arguments.length !== 1) throw new Error(`injectFormVariables expects exactly one argument`);
43
+ const injectFormVariablesArg = node.arguments[0];
44
+ if (!ts$1.isArrowFunction(injectFormVariablesArg)) throw new Error(`injectFormVariables expects an arrow function as its argument`);
45
+ node = injectFormVariablesArg.body;
46
+ }
47
+ }
48
+ if (ts$1.isArrowFunction(node)) if (supportedInlineCodePaths.includes(path$1)) {
49
+ let code = node.getText();
50
+ if (code.endsWith(",")) code = code.slice(0, -1);
51
+ const imports = findUsedImports(node.body, importedIdentifiers);
52
+ return ts$1.factory.createObjectLiteralExpression([ts$1.factory.createPropertyAssignment("code", ts$1.factory.createStringLiteral(code)), ts$1.factory.createPropertyAssignment("imports", ts$1.factory.createArrayLiteralExpression(imports.map((imprt) => {
53
+ return ts$1.factory.createObjectLiteralExpression([
54
+ ts$1.factory.createPropertyAssignment("name", ts$1.factory.createStringLiteral(imprt.name)),
55
+ ts$1.factory.createPropertyAssignment("import", ts$1.factory.createStringLiteral(imprt.import)),
56
+ ...imprt.defaultImport ? [ts$1.factory.createPropertyAssignment("defaultImport", ts$1.factory.createTrue())] : []
57
+ ]);
58
+ })))], true);
59
+ } else throw new Error(`Inline Function is not allowed here and calling the function is not supported: ${path$1}`);
60
+ else if (ts$1.isIdentifier(node)) {
61
+ const imported = importedIdentifiers.get(node.text);
62
+ if (imported) {
63
+ if (supportedImportPaths.includes(path$1)) return ts$1.factory.createObjectLiteralExpression([ts$1.factory.createPropertyAssignment("name", ts$1.factory.createStringLiteral(node.text)), ts$1.factory.createPropertyAssignment("import", ts$1.factory.createStringLiteral(imported.import))], true);
64
+ }
65
+ }
66
+ if (![
67
+ ts$1.SyntaxKind.Identifier,
68
+ ts$1.SyntaxKind.ArrayLiteralExpression,
69
+ ts$1.SyntaxKind.ObjectLiteralExpression,
70
+ ts$1.SyntaxKind.TaggedTemplateExpression,
71
+ ts$1.SyntaxKind.SpreadElement,
72
+ ts$1.SyntaxKind.PropertyAssignment,
73
+ ts$1.SyntaxKind.ShorthandPropertyAssignment
74
+ ].includes(node.kind)) return node;
75
+ let newPath = path$1;
76
+ if (path$1 == "") {
77
+ if (ts$1.isObjectLiteralExpression(node)) {
78
+ const typeProperty = getTypePropertyFromObjectLiteral(node);
79
+ newPath = typeProperty ? `[type=${typeProperty}]` : "";
80
+ }
81
+ } else if (ts$1.isPropertyAssignment(node)) newPath = `${path$1}.${node.name.getText()}`;
82
+ return ts$1.visitEachChild(node, (child) => {
83
+ return visit(child, newPath);
84
+ }, context);
85
+ };
86
+ return (node) => ts$1.visitNode(node, (child) => visit(child, ""));
87
+ };
88
+ }
89
+ const configNode = findConfigNode(sourceFile);
90
+ const transformedConfigNode = ts$1.transform(configNode, [configTransformer()]).transformed[0];
91
+ const updatedSource = ts$1.transform(sourceFile, [(context) => {
92
+ const visitor = (node) => {
93
+ if (node === configNode) return transformedConfigNode;
94
+ return ts$1.visitEachChild(node, visitor, context);
95
+ };
96
+ return (node) => ts$1.visitNode(node, visitor);
97
+ }]).transformed[0];
98
+ return ts$1.createPrinter().printFile(updatedSource);
99
+ }
100
+ function findConfigNode(sourceFile) {
101
+ let ret;
102
+ sourceFile.forEachChild((node) => {
103
+ if (ts$1.isExportAssignment(node)) {
104
+ const exportedNode = node.expression;
105
+ if (ts$1.isCallExpression(exportedNode) && exportedNode.expression.getText() == "defineConfig") {
106
+ const args = exportedNode.arguments;
107
+ if (args.length != 1) throw new Error(`Expected exactly one argument for defineConfig`);
108
+ ret = args[0];
109
+ return false;
110
+ } else if (ts$1.isSatisfiesExpression(exportedNode)) {
111
+ if (ts$1.isObjectLiteralExpression(exportedNode.expression)) {
112
+ ret = exportedNode.expression;
113
+ return false;
114
+ }
115
+ } else if (ts$1.isObjectLiteralExpression(exportedNode)) {
116
+ ret = exportedNode;
117
+ return false;
118
+ }
119
+ }
120
+ });
121
+ if (!ret) throw new Error(`No default export found, please export the GeneratorConfig as default, preferrable using defineConfig helper.`);
122
+ return ret;
123
+ }
124
+ function getTypePropertyFromObjectLiteral(node) {
125
+ for (const property of node.properties) if (ts$1.isPropertyAssignment(property)) {
126
+ if (property.name.getText() == "type") {
127
+ const propertyAssignmentInitializer = property.initializer;
128
+ if (ts$1.isStringLiteral(propertyAssignmentInitializer)) return propertyAssignmentInitializer.text;
129
+ }
130
+ }
131
+ return null;
132
+ }
133
+ function collectImports(rootNode) {
134
+ const importedIdentifiers = /* @__PURE__ */ new Map();
135
+ function visit(node) {
136
+ if (ts$1.isImportDeclaration(node) && node.importClause) {
137
+ const moduleSpecifier = node.moduleSpecifier.text;
138
+ if (node.importClause.namedBindings && ts$1.isNamedImports(node.importClause.namedBindings)) for (const element of node.importClause.namedBindings.elements) {
139
+ const localName = element.name.text;
140
+ const originalName = element.propertyName ? element.propertyName.text : localName;
141
+ importedIdentifiers.set(localName, {
142
+ name: originalName,
143
+ import: moduleSpecifier
144
+ });
145
+ }
146
+ else if (node.importClause.name && ts$1.isIdentifier(node.importClause.name)) {
147
+ const localName = node.importClause.name.text;
148
+ importedIdentifiers.set(localName, {
149
+ defaultImport: true,
150
+ name: localName,
151
+ import: moduleSpecifier
152
+ });
153
+ }
154
+ }
155
+ ts$1.forEachChild(node, visit);
156
+ }
157
+ visit(rootNode);
158
+ return importedIdentifiers;
159
+ }
160
+ function findUsedImports(rootNode, importedIdentifiers) {
161
+ const imports = [];
162
+ const usedNames = /* @__PURE__ */ new Set();
163
+ function collectUsedIdentifiers(node) {
164
+ if (ts$1.isIdentifier(node)) usedNames.add(node.text);
165
+ ts$1.forEachChild(node, collectUsedIdentifiers);
166
+ }
167
+ collectUsedIdentifiers(rootNode);
168
+ for (const name of usedNames) {
169
+ const imported = importedIdentifiers.get(name);
170
+ if (imported) imports.push(imported);
171
+ }
172
+ return imports;
173
+ }
174
+
175
+ //#endregion
176
+ //#region src/commands/generate/config/parseConfig.ts
177
+ let alias;
178
+ try {
179
+ const tsConfigJson = readFileSync("tsconfig.json", "utf-8");
180
+ const tsConfig = JSON.parse(tsConfigJson);
181
+ if (tsConfig.compilerOptions?.paths) {
182
+ alias = {};
183
+ for (const [key, value] of Object.entries(tsConfig.compilerOptions.paths)) {
184
+ const cleanedKey = key.replace("/*", "");
185
+ const cleanedValue = value[0].replace("/*", "");
186
+ alias[cleanedKey] = `${process.cwd()}/${cleanedValue}`;
187
+ }
188
+ }
189
+ } catch (error) {
190
+ console.warn("Failed to parse TSConfig paths, import aliases might not work. See original error below");
191
+ console.warn(error);
192
+ }
193
+ const jiti = createJiti(import.meta.url, {
194
+ alias,
195
+ fsCache: false,
196
+ jsx: { runtime: "automatic" }
197
+ });
198
+ async function parseConfig(file) {
199
+ const transformedConfig = transformConfigFile(file, await promises.readFile(file, "utf-8"));
200
+ const tempFileName = `${dirname(file)}/.temp-${basename(file)}`;
201
+ await promises.writeFile(tempFileName, transformedConfig, "utf-8");
202
+ let executedConfig;
203
+ try {
204
+ executedConfig = await jiti.import(tempFileName.replace(/\.tsx?$/, ""), { default: true });
205
+ } catch (e) {
206
+ console.error(e);
207
+ throw new Error(`Error executing config file ${file}: ${e}`);
208
+ }
209
+ await promises.rm(tempFileName);
210
+ return executedConfig;
211
+ }
212
+
213
+ //#endregion
214
+ //#region src/commands/generate/utils/convertConfigImport.ts
215
+ function convertConfigImport(imprt) {
216
+ let importPath = imprt.import;
217
+ if (importPath.startsWith("../")) importPath = `../${importPath}`;
218
+ else if (importPath.startsWith("./")) importPath = `.${importPath}`;
219
+ return {
220
+ name: imprt.name,
221
+ importPath,
222
+ defaultImport: imprt.defaultImport
223
+ };
224
+ }
225
+
226
+ //#endregion
227
+ //#region src/commands/generate/utils/findMutationType.ts
228
+ function findMutationType(mutationName, schema) {
229
+ if (!schema.__schema.mutationType) throw new Error("Schema has no Mutation type");
230
+ const queryType = schema.__schema.types.find((type) => type.name === schema.__schema.mutationType?.name);
231
+ if (!queryType) throw new Error("Can't find Mutation type in gql schema");
232
+ return queryType.fields.find((field) => field.name === mutationName);
233
+ }
234
+ function findMutationTypeOrThrow(mutationName, schema) {
235
+ const ret = findMutationType(mutationName, schema);
236
+ if (!ret) throw new Error(`Can't find Mutation ${mutationName} in gql schema`);
237
+ return ret;
238
+ }
239
+
240
+ //#endregion
241
+ //#region src/commands/generate/utils/generateGqlOperation.ts
242
+ function generateGqlQueryTreeFromFields(fields) {
243
+ function getOrCreateNode(root$1, path$1) {
244
+ let node = root$1;
245
+ for (const part of path$1) {
246
+ if (!node.children[part]) node.children[part] = {
247
+ children: {},
248
+ fragments: []
249
+ };
250
+ node = node.children[part];
251
+ }
252
+ return node;
253
+ }
254
+ const root = {
255
+ children: {},
256
+ fragments: []
257
+ };
258
+ for (const field of fields) {
259
+ const fragmentMatch = field.match(/(.*)(\.{3}.*)/);
260
+ if (fragmentMatch) {
261
+ const key = fragmentMatch[1].trim();
262
+ const fragment = fragmentMatch[2].trim();
263
+ if (key === "") root.fragments.push(fragment);
264
+ else getOrCreateNode(root, key.split(".").filter(Boolean)).fragments.push(fragment);
265
+ } else {
266
+ const path$1 = field.split(".").filter(Boolean);
267
+ if (path$1.length === 0) continue;
268
+ getOrCreateNode(root, path$1);
269
+ }
270
+ }
271
+ function recursiveStringify$1(node) {
272
+ const parts = [];
273
+ for (const key of Object.keys(node.children)) {
274
+ const child = node.children[key];
275
+ const childStr = recursiveStringify$1(child);
276
+ if (childStr) parts.push(`${key} { ${childStr} }`);
277
+ else parts.push(key);
278
+ }
279
+ if (node.fragments.length > 0) parts.push(...node.fragments);
280
+ return parts.join(" ");
281
+ }
282
+ return recursiveStringify$1(root);
283
+ }
284
+ function generateGqlOperation(options) {
285
+ let queryArgs = "";
286
+ if (options.variables && options.variables.length > 0) {
287
+ queryArgs += `(`;
288
+ queryArgs += options.variables.map((v) => `$${v.name}: ${v.type}`).join(", ");
289
+ queryArgs += `)`;
290
+ }
291
+ let rootQueryArgs = "";
292
+ if (options.variables && options.variables.length > 0) {
293
+ rootQueryArgs += `(`;
294
+ rootQueryArgs += options.variables.map((v) => `${v.name}: $${v.name}`).join(", ");
295
+ rootQueryArgs += `)`;
296
+ }
297
+ return `
298
+ ${options.type} ${options.operationName}${queryArgs} {
299
+ ${options.rootOperation}${rootQueryArgs} {
300
+ ${generateGqlQueryTreeFromFields(options.fields)}
301
+ }
302
+ }
303
+ ${(options.fragmentVariables ?? []).join("\n")}
304
+ `;
305
+ }
306
+
307
+ //#endregion
308
+ //#region src/commands/generate/utils/generateImportsCode.ts
309
+ function generateImportsCode(imports) {
310
+ const importsNameToPath = /* @__PURE__ */ new Map();
311
+ return imports.filter((imp) => {
312
+ if (importsNameToPath.has(imp.name)) if (importsNameToPath.get(imp.name) !== imp.importPath) throw new Error(`Duplicate import name ${imp.name}`);
313
+ else return false;
314
+ importsNameToPath.set(imp.name, imp.importPath);
315
+ return true;
316
+ }).map((imp) => {
317
+ if (imp.defaultImport) return `import ${imp.name} from "${imp.importPath}";`;
318
+ else return `import { ${imp.name} } from "${imp.importPath}";`;
319
+ }).join("\n");
320
+ }
321
+
322
+ //#endregion
323
+ //#region src/commands/generate/utils/runtimeTypeGuards.ts
324
+ /**
325
+ * Type Guard used by generator runtime for places where runtime vs. configtime types mismatch
326
+ */
327
+ function isGeneratorConfigImport(value) {
328
+ if (value && typeof value === "object" && "import" in value && "name" in value) return true;
329
+ return false;
330
+ }
331
+ /**
332
+ * Type Guard used by generator runtime for places where runtime vs. configtime types mismatch
333
+ */
334
+ function isGeneratorConfigCode(value) {
335
+ if (value && typeof value === "object" && "code" in value && "imports" in value) return true;
336
+ return false;
337
+ }
338
+
339
+ //#endregion
340
+ //#region src/commands/generate/generateForm/extractErrorEnums.ts
341
+ /**
342
+ * Extracts error enum type names from create and update mutations.
343
+ * Navigates: Mutation → return type → payload object → errors field → LIST → error object → code field → ENUM
344
+ */
345
+ function extractErrorEnumsFromMutations({ createMutationType, updateMutationType, gqlIntrospection }) {
346
+ const createErrorEnum = createMutationType ? extractErrorEnumFromMutation(createMutationType, gqlIntrospection) : void 0;
347
+ const updateErrorEnum = updateMutationType ? extractErrorEnumFromMutation(updateMutationType, gqlIntrospection) : void 0;
348
+ return {
349
+ createErrorEnum,
350
+ updateErrorEnum,
351
+ useDifferentEnums: Boolean(createErrorEnum && updateErrorEnum && createErrorEnum !== updateErrorEnum)
352
+ };
353
+ }
354
+ /**
355
+ * Extracts error enum type name from a single mutation field.
356
+ * Returns undefined if mutation doesn't have error enum.
357
+ */
358
+ function extractErrorEnumFromMutation(mutationType, gqlIntrospection) {
359
+ try {
360
+ let returnType = mutationType.type;
361
+ if (returnType.kind === "NON_NULL") returnType = returnType.ofType;
362
+ if (returnType.kind !== "OBJECT") return;
363
+ const payloadType = gqlIntrospection.__schema.types.find((type) => type.kind === "OBJECT" && type.name === returnType.name);
364
+ if (!payloadType) return;
365
+ const errorsField = payloadType.fields.find((field) => field.name === "errors");
366
+ if (!errorsField) return;
367
+ return extractEnumFromErrorsField(errorsField, gqlIntrospection);
368
+ } catch {
369
+ return;
370
+ }
371
+ }
372
+ /**
373
+ * Extracts enum type name from the errors field.
374
+ * Traverses: errors field → unwrap NON_NULL → unwrap LIST → unwrap NON_NULL → error OBJECT → code field → ENUM
375
+ */
376
+ function extractEnumFromErrorsField(errorsField, gqlIntrospection) {
377
+ try {
378
+ let errorsType = errorsField.type;
379
+ if (errorsType.kind === "NON_NULL") errorsType = errorsType.ofType;
380
+ if (errorsType.kind !== "LIST") return;
381
+ let errorItemType = errorsType.ofType;
382
+ if (errorItemType.kind === "NON_NULL") errorItemType = errorItemType.ofType;
383
+ if (errorItemType.kind !== "OBJECT") return;
384
+ const errorObjectType = gqlIntrospection.__schema.types.find((type) => type.kind === "OBJECT" && type.name === errorItemType.name);
385
+ if (!errorObjectType) return;
386
+ const codeField = errorObjectType.fields.find((field) => field.name === "code");
387
+ if (!codeField) return;
388
+ let codeType = codeField.type;
389
+ if (codeType.kind === "NON_NULL") codeType = codeType.ofType;
390
+ if (codeType.kind !== "ENUM") return;
391
+ return codeType.name;
392
+ } catch {
393
+ return;
394
+ }
395
+ }
396
+
397
+ //#endregion
398
+ //#region src/commands/generate/generateForm/flatFormFieldsFromFormConfig.ts
399
+ function flatFormFieldsFromFormConfig(config) {
400
+ return config.fields.reduce((acc, field) => {
401
+ if (isFormLayoutConfig(field)) field.fields.forEach((nestedFieldConfig) => {
402
+ if (isFormFieldConfig(nestedFieldConfig)) acc.push(nestedFieldConfig);
403
+ });
404
+ else if (isFormFieldConfig(field)) acc.push(field);
405
+ return acc;
406
+ }, []);
407
+ }
408
+
409
+ //#endregion
410
+ //#region src/commands/generate/generateForm/generateErrorHandling.ts
411
+ /**
412
+ * Generates error handling code for form submissions.
413
+ * Creates errors.reduce() implementation that maps GraphQL errors to Final Form submission errors.
414
+ */
415
+ function generateErrorHandlingCode({ mutationResponsePath, errorMessagesVariable }) {
416
+ return `
417
+ if (${mutationResponsePath}.errors.length) {
418
+ return ${mutationResponsePath}.errors.reduce(
419
+ (submissionErrors, error) => {
420
+ const errorMessage = ${errorMessagesVariable}[error.code];
421
+ if (error.field) {
422
+ submissionErrors[error.field] = errorMessage;
423
+ } else {
424
+ submissionErrors[FORM_ERROR] = errorMessage;
425
+ }
426
+ return submissionErrors;
427
+ },
428
+ {} as Record<string, ReactNode>,
429
+ );
430
+ }`;
431
+ }
432
+
433
+ //#endregion
434
+ //#region src/commands/generate/utils/camelCaseToHumanReadable.ts
435
+ function camelCaseToHumanReadable(s) {
436
+ return capitalCase(s);
437
+ }
438
+
439
+ //#endregion
440
+ //#region src/commands/generate/generateForm/generateErrorMessages.ts
441
+ /**
442
+ * Generates TypeScript code for submissionErrorMessages object(s).
443
+ * Creates a mapped type object with FormattedMessage components for each error code.
444
+ */
445
+ function generateErrorMessagesCode({ enumName, gqlType, variableName, gqlIntrospection }) {
446
+ const enumType = gqlIntrospection.__schema.types.find((type) => type.kind === "ENUM" && type.name === enumName);
447
+ if (!enumType || enumType.enumValues.length === 0) return "";
448
+ return `const ${variableName}: Record<GQL${enumName}, ReactNode> = {
449
+ ${enumType.enumValues.map((enumValue) => {
450
+ const errorCode = enumValue.name;
451
+ const defaultMessage = enumValue.description || camelCaseToHumanReadable(errorCode);
452
+ return `${errorCode}: <FormattedMessage id="${`${gqlType.toLowerCase()}.form.error.${errorCode}`}" defaultMessage="${defaultMessage}" />`;
453
+ }).join(",\n")},
454
+ };`;
455
+ }
456
+
457
+ //#endregion
458
+ //#region src/commands/generate/generateForm/generateComponentFormField.ts
459
+ function generateComponentFormField({ config }) {
460
+ if (!isGeneratorConfigImport(config.component)) throw new Error("config.component must be a GeneratorConfigImport");
461
+ return {
462
+ imports: [convertConfigImport(config.component)],
463
+ formProps: [],
464
+ hooksCode: "",
465
+ formFragmentFields: [],
466
+ formValuesConfig: [],
467
+ finalFormConfig: void 0,
468
+ code: `<${config.component.name} />`,
469
+ gqlDocuments: {}
470
+ };
471
+ }
472
+
473
+ //#endregion
474
+ //#region ../../../node_modules/.pnpm/react@19.2.4/node_modules/react/cjs/react.production.js
475
+ /**
476
+ * @license React
477
+ * react.production.js
478
+ *
479
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
480
+ *
481
+ * This source code is licensed under the MIT license found in the
482
+ * LICENSE file in the root directory of this source tree.
483
+ */
484
+ var require_react_production = /* @__PURE__ */ __commonJSMin(((exports) => {
485
+ var REACT_ELEMENT_TYPE = Symbol.for("react.transitional.element"), REACT_PORTAL_TYPE = Symbol.for("react.portal"), REACT_FRAGMENT_TYPE = Symbol.for("react.fragment"), REACT_STRICT_MODE_TYPE = Symbol.for("react.strict_mode"), REACT_PROFILER_TYPE = Symbol.for("react.profiler"), REACT_CONSUMER_TYPE = Symbol.for("react.consumer"), REACT_CONTEXT_TYPE = Symbol.for("react.context"), REACT_FORWARD_REF_TYPE = Symbol.for("react.forward_ref"), REACT_SUSPENSE_TYPE = Symbol.for("react.suspense"), REACT_MEMO_TYPE = Symbol.for("react.memo"), REACT_LAZY_TYPE = Symbol.for("react.lazy"), REACT_ACTIVITY_TYPE = Symbol.for("react.activity"), MAYBE_ITERATOR_SYMBOL = Symbol.iterator;
486
+ var ReactNoopUpdateQueue = {
487
+ isMounted: function() {
488
+ return !1;
489
+ },
490
+ enqueueForceUpdate: function() {},
491
+ enqueueReplaceState: function() {},
492
+ enqueueSetState: function() {}
493
+ }, assign = Object.assign, emptyObject = {};
494
+ function Component(props, context, updater) {
495
+ this.props = props;
496
+ this.context = context;
497
+ this.refs = emptyObject;
498
+ this.updater = updater || ReactNoopUpdateQueue;
499
+ }
500
+ Component.prototype.isReactComponent = {};
501
+ Component.prototype.setState = function(partialState, callback) {
502
+ if ("object" !== typeof partialState && "function" !== typeof partialState && null != partialState) throw Error("takes an object of state variables to update or a function which returns an object of state variables.");
503
+ this.updater.enqueueSetState(this, partialState, callback, "setState");
504
+ };
505
+ Component.prototype.forceUpdate = function(callback) {
506
+ this.updater.enqueueForceUpdate(this, callback, "forceUpdate");
507
+ };
508
+ function ComponentDummy() {}
509
+ ComponentDummy.prototype = Component.prototype;
510
+ function PureComponent(props, context, updater) {
511
+ this.props = props;
512
+ this.context = context;
513
+ this.refs = emptyObject;
514
+ this.updater = updater || ReactNoopUpdateQueue;
515
+ }
516
+ var pureComponentPrototype = PureComponent.prototype = new ComponentDummy();
517
+ pureComponentPrototype.constructor = PureComponent;
518
+ assign(pureComponentPrototype, Component.prototype);
519
+ pureComponentPrototype.isPureReactComponent = !0;
520
+ var isArrayImpl = Array.isArray;
521
+ function isValidElement(object) {
522
+ return "object" === typeof object && null !== object && object.$$typeof === REACT_ELEMENT_TYPE;
523
+ }
524
+ exports.isValidElement = isValidElement;
525
+ }));
526
+
527
+ //#endregion
528
+ //#region ../../../node_modules/.pnpm/react@19.2.4/node_modules/react/cjs/react.development.js
529
+ /**
530
+ * @license React
531
+ * react.development.js
532
+ *
533
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
534
+ *
535
+ * This source code is licensed under the MIT license found in the
536
+ * LICENSE file in the root directory of this source tree.
537
+ */
538
+ var require_react_development = /* @__PURE__ */ __commonJSMin(((exports, module) => {
539
+ "production" !== process.env.NODE_ENV && (function() {
540
+ function defineDeprecationWarning(methodName, info) {
541
+ Object.defineProperty(Component.prototype, methodName, { get: function() {
542
+ console.warn("%s(...) is deprecated in plain JavaScript React classes. %s", info[0], info[1]);
543
+ } });
544
+ }
545
+ function getIteratorFn(maybeIterable) {
546
+ if (null === maybeIterable || "object" !== typeof maybeIterable) return null;
547
+ maybeIterable = MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL] || maybeIterable["@@iterator"];
548
+ return "function" === typeof maybeIterable ? maybeIterable : null;
549
+ }
550
+ function warnNoop(publicInstance, callerName) {
551
+ publicInstance = (publicInstance = publicInstance.constructor) && (publicInstance.displayName || publicInstance.name) || "ReactClass";
552
+ var warningKey = publicInstance + "." + callerName;
553
+ didWarnStateUpdateForUnmountedComponent[warningKey] || (console.error("Can't call %s on a component that is not yet mounted. This is a no-op, but it might indicate a bug in your application. Instead, assign to `this.state` directly or define a `state = {};` class property with the desired state in the %s component.", callerName, publicInstance), didWarnStateUpdateForUnmountedComponent[warningKey] = !0);
554
+ }
555
+ function Component(props, context, updater) {
556
+ this.props = props;
557
+ this.context = context;
558
+ this.refs = emptyObject;
559
+ this.updater = updater || ReactNoopUpdateQueue;
560
+ }
561
+ function ComponentDummy() {}
562
+ function PureComponent(props, context, updater) {
563
+ this.props = props;
564
+ this.context = context;
565
+ this.refs = emptyObject;
566
+ this.updater = updater || ReactNoopUpdateQueue;
567
+ }
568
+ function noop() {}
569
+ function testStringCoercion(value) {
570
+ return "" + value;
571
+ }
572
+ function checkKeyStringCoercion(value) {
573
+ try {
574
+ testStringCoercion(value);
575
+ var JSCompiler_inline_result = !1;
576
+ } catch (e) {
577
+ JSCompiler_inline_result = !0;
578
+ }
579
+ if (JSCompiler_inline_result) {
580
+ JSCompiler_inline_result = console;
581
+ var JSCompiler_temp_const = JSCompiler_inline_result.error;
582
+ var JSCompiler_inline_result$jscomp$0 = "function" === typeof Symbol && Symbol.toStringTag && value[Symbol.toStringTag] || value.constructor.name || "Object";
583
+ JSCompiler_temp_const.call(JSCompiler_inline_result, "The provided key is an unsupported type %s. This value must be coerced to a string before using it here.", JSCompiler_inline_result$jscomp$0);
584
+ return testStringCoercion(value);
585
+ }
586
+ }
587
+ function getComponentNameFromType(type) {
588
+ if (null == type) return null;
589
+ if ("function" === typeof type) return type.$$typeof === REACT_CLIENT_REFERENCE ? null : type.displayName || type.name || null;
590
+ if ("string" === typeof type) return type;
591
+ switch (type) {
592
+ case REACT_FRAGMENT_TYPE: return "Fragment";
593
+ case REACT_PROFILER_TYPE: return "Profiler";
594
+ case REACT_STRICT_MODE_TYPE: return "StrictMode";
595
+ case REACT_SUSPENSE_TYPE: return "Suspense";
596
+ case REACT_SUSPENSE_LIST_TYPE: return "SuspenseList";
597
+ case REACT_ACTIVITY_TYPE: return "Activity";
598
+ }
599
+ if ("object" === typeof type) switch ("number" === typeof type.tag && console.error("Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue."), type.$$typeof) {
600
+ case REACT_PORTAL_TYPE: return "Portal";
601
+ case REACT_CONTEXT_TYPE: return type.displayName || "Context";
602
+ case REACT_CONSUMER_TYPE: return (type._context.displayName || "Context") + ".Consumer";
603
+ case REACT_FORWARD_REF_TYPE:
604
+ var innerType = type.render;
605
+ type = type.displayName;
606
+ type || (type = innerType.displayName || innerType.name || "", type = "" !== type ? "ForwardRef(" + type + ")" : "ForwardRef");
607
+ return type;
608
+ case REACT_MEMO_TYPE: return innerType = type.displayName || null, null !== innerType ? innerType : getComponentNameFromType(type.type) || "Memo";
609
+ case REACT_LAZY_TYPE:
610
+ innerType = type._payload;
611
+ type = type._init;
612
+ try {
613
+ return getComponentNameFromType(type(innerType));
614
+ } catch (x) {}
615
+ }
616
+ return null;
617
+ }
618
+ function getTaskName(type) {
619
+ if (type === REACT_FRAGMENT_TYPE) return "<>";
620
+ if ("object" === typeof type && null !== type && type.$$typeof === REACT_LAZY_TYPE) return "<...>";
621
+ try {
622
+ var name = getComponentNameFromType(type);
623
+ return name ? "<" + name + ">" : "<...>";
624
+ } catch (x) {
625
+ return "<...>";
626
+ }
627
+ }
628
+ function getOwner() {
629
+ var dispatcher = ReactSharedInternals.A;
630
+ return null === dispatcher ? null : dispatcher.getOwner();
631
+ }
632
+ function UnknownOwner() {
633
+ return Error("react-stack-top-frame");
634
+ }
635
+ function hasValidKey(config) {
636
+ if (hasOwnProperty.call(config, "key")) {
637
+ var getter = Object.getOwnPropertyDescriptor(config, "key").get;
638
+ if (getter && getter.isReactWarning) return !1;
639
+ }
640
+ return void 0 !== config.key;
641
+ }
642
+ function defineKeyPropWarningGetter(props, displayName) {
643
+ function warnAboutAccessingKey() {
644
+ specialPropKeyWarningShown || (specialPropKeyWarningShown = !0, console.error("%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)", displayName));
645
+ }
646
+ warnAboutAccessingKey.isReactWarning = !0;
647
+ Object.defineProperty(props, "key", {
648
+ get: warnAboutAccessingKey,
649
+ configurable: !0
650
+ });
651
+ }
652
+ function elementRefGetterWithDeprecationWarning() {
653
+ var componentName = getComponentNameFromType(this.type);
654
+ didWarnAboutElementRef[componentName] || (didWarnAboutElementRef[componentName] = !0, console.error("Accessing element.ref was removed in React 19. ref is now a regular prop. It will be removed from the JSX Element type in a future release."));
655
+ componentName = this.props.ref;
656
+ return void 0 !== componentName ? componentName : null;
657
+ }
658
+ function ReactElement(type, key, props, owner, debugStack, debugTask) {
659
+ var refProp = props.ref;
660
+ type = {
661
+ $$typeof: REACT_ELEMENT_TYPE,
662
+ type,
663
+ key,
664
+ props,
665
+ _owner: owner
666
+ };
667
+ null !== (void 0 !== refProp ? refProp : null) ? Object.defineProperty(type, "ref", {
668
+ enumerable: !1,
669
+ get: elementRefGetterWithDeprecationWarning
670
+ }) : Object.defineProperty(type, "ref", {
671
+ enumerable: !1,
672
+ value: null
673
+ });
674
+ type._store = {};
675
+ Object.defineProperty(type._store, "validated", {
676
+ configurable: !1,
677
+ enumerable: !1,
678
+ writable: !0,
679
+ value: 0
680
+ });
681
+ Object.defineProperty(type, "_debugInfo", {
682
+ configurable: !1,
683
+ enumerable: !1,
684
+ writable: !0,
685
+ value: null
686
+ });
687
+ Object.defineProperty(type, "_debugStack", {
688
+ configurable: !1,
689
+ enumerable: !1,
690
+ writable: !0,
691
+ value: debugStack
692
+ });
693
+ Object.defineProperty(type, "_debugTask", {
694
+ configurable: !1,
695
+ enumerable: !1,
696
+ writable: !0,
697
+ value: debugTask
698
+ });
699
+ Object.freeze && (Object.freeze(type.props), Object.freeze(type));
700
+ return type;
701
+ }
702
+ function cloneAndReplaceKey(oldElement, newKey) {
703
+ newKey = ReactElement(oldElement.type, newKey, oldElement.props, oldElement._owner, oldElement._debugStack, oldElement._debugTask);
704
+ oldElement._store && (newKey._store.validated = oldElement._store.validated);
705
+ return newKey;
706
+ }
707
+ function validateChildKeys(node) {
708
+ isValidElement$1(node) ? node._store && (node._store.validated = 1) : "object" === typeof node && null !== node && node.$$typeof === REACT_LAZY_TYPE && ("fulfilled" === node._payload.status ? isValidElement$1(node._payload.value) && node._payload.value._store && (node._payload.value._store.validated = 1) : node._store && (node._store.validated = 1));
709
+ }
710
+ function isValidElement$1(object) {
711
+ return "object" === typeof object && null !== object && object.$$typeof === REACT_ELEMENT_TYPE;
712
+ }
713
+ function escape(key) {
714
+ var escaperLookup = {
715
+ "=": "=0",
716
+ ":": "=2"
717
+ };
718
+ return "$" + key.replace(/[=:]/g, function(match) {
719
+ return escaperLookup[match];
720
+ });
721
+ }
722
+ function getElementKey(element, index) {
723
+ return "object" === typeof element && null !== element && null != element.key ? (checkKeyStringCoercion(element.key), escape("" + element.key)) : index.toString(36);
724
+ }
725
+ function resolveThenable(thenable) {
726
+ switch (thenable.status) {
727
+ case "fulfilled": return thenable.value;
728
+ case "rejected": throw thenable.reason;
729
+ default: switch ("string" === typeof thenable.status ? thenable.then(noop, noop) : (thenable.status = "pending", thenable.then(function(fulfilledValue) {
730
+ "pending" === thenable.status && (thenable.status = "fulfilled", thenable.value = fulfilledValue);
731
+ }, function(error) {
732
+ "pending" === thenable.status && (thenable.status = "rejected", thenable.reason = error);
733
+ })), thenable.status) {
734
+ case "fulfilled": return thenable.value;
735
+ case "rejected": throw thenable.reason;
736
+ }
737
+ }
738
+ throw thenable;
739
+ }
740
+ function mapIntoArray(children, array, escapedPrefix, nameSoFar, callback) {
741
+ var type = typeof children;
742
+ if ("undefined" === type || "boolean" === type) children = null;
743
+ var invokeCallback = !1;
744
+ if (null === children) invokeCallback = !0;
745
+ else switch (type) {
746
+ case "bigint":
747
+ case "string":
748
+ case "number":
749
+ invokeCallback = !0;
750
+ break;
751
+ case "object": switch (children.$$typeof) {
752
+ case REACT_ELEMENT_TYPE:
753
+ case REACT_PORTAL_TYPE:
754
+ invokeCallback = !0;
755
+ break;
756
+ case REACT_LAZY_TYPE: return invokeCallback = children._init, mapIntoArray(invokeCallback(children._payload), array, escapedPrefix, nameSoFar, callback);
757
+ }
758
+ }
759
+ if (invokeCallback) {
760
+ invokeCallback = children;
761
+ callback = callback(invokeCallback);
762
+ var childKey = "" === nameSoFar ? "." + getElementKey(invokeCallback, 0) : nameSoFar;
763
+ isArrayImpl(callback) ? (escapedPrefix = "", null != childKey && (escapedPrefix = childKey.replace(userProvidedKeyEscapeRegex, "$&/") + "/"), mapIntoArray(callback, array, escapedPrefix, "", function(c) {
764
+ return c;
765
+ })) : null != callback && (isValidElement$1(callback) && (null != callback.key && (invokeCallback && invokeCallback.key === callback.key || checkKeyStringCoercion(callback.key)), escapedPrefix = cloneAndReplaceKey(callback, escapedPrefix + (null == callback.key || invokeCallback && invokeCallback.key === callback.key ? "" : ("" + callback.key).replace(userProvidedKeyEscapeRegex, "$&/") + "/") + childKey), "" !== nameSoFar && null != invokeCallback && isValidElement$1(invokeCallback) && null == invokeCallback.key && invokeCallback._store && !invokeCallback._store.validated && (escapedPrefix._store.validated = 2), callback = escapedPrefix), array.push(callback));
766
+ return 1;
767
+ }
768
+ invokeCallback = 0;
769
+ childKey = "" === nameSoFar ? "." : nameSoFar + ":";
770
+ if (isArrayImpl(children)) for (var i = 0; i < children.length; i++) nameSoFar = children[i], type = childKey + getElementKey(nameSoFar, i), invokeCallback += mapIntoArray(nameSoFar, array, escapedPrefix, type, callback);
771
+ else if (i = getIteratorFn(children), "function" === typeof i) for (i === children.entries && (didWarnAboutMaps || console.warn("Using Maps as children is not supported. Use an array of keyed ReactElements instead."), didWarnAboutMaps = !0), children = i.call(children), i = 0; !(nameSoFar = children.next()).done;) nameSoFar = nameSoFar.value, type = childKey + getElementKey(nameSoFar, i++), invokeCallback += mapIntoArray(nameSoFar, array, escapedPrefix, type, callback);
772
+ else if ("object" === type) {
773
+ if ("function" === typeof children.then) return mapIntoArray(resolveThenable(children), array, escapedPrefix, nameSoFar, callback);
774
+ array = String(children);
775
+ throw Error("Objects are not valid as a React child (found: " + ("[object Object]" === array ? "object with keys {" + Object.keys(children).join(", ") + "}" : array) + "). If you meant to render a collection of children, use an array instead.");
776
+ }
777
+ return invokeCallback;
778
+ }
779
+ function mapChildren(children, func, context) {
780
+ if (null == children) return children;
781
+ var result = [], count = 0;
782
+ mapIntoArray(children, result, "", "", function(child) {
783
+ return func.call(context, child, count++);
784
+ });
785
+ return result;
786
+ }
787
+ function lazyInitializer(payload) {
788
+ if (-1 === payload._status) {
789
+ var ioInfo = payload._ioInfo;
790
+ null != ioInfo && (ioInfo.start = ioInfo.end = performance.now());
791
+ ioInfo = payload._result;
792
+ var thenable = ioInfo();
793
+ thenable.then(function(moduleObject) {
794
+ if (0 === payload._status || -1 === payload._status) {
795
+ payload._status = 1;
796
+ payload._result = moduleObject;
797
+ var _ioInfo = payload._ioInfo;
798
+ null != _ioInfo && (_ioInfo.end = performance.now());
799
+ void 0 === thenable.status && (thenable.status = "fulfilled", thenable.value = moduleObject);
800
+ }
801
+ }, function(error) {
802
+ if (0 === payload._status || -1 === payload._status) {
803
+ payload._status = 2;
804
+ payload._result = error;
805
+ var _ioInfo2 = payload._ioInfo;
806
+ null != _ioInfo2 && (_ioInfo2.end = performance.now());
807
+ void 0 === thenable.status && (thenable.status = "rejected", thenable.reason = error);
808
+ }
809
+ });
810
+ ioInfo = payload._ioInfo;
811
+ if (null != ioInfo) {
812
+ ioInfo.value = thenable;
813
+ var displayName = thenable.displayName;
814
+ "string" === typeof displayName && (ioInfo.name = displayName);
815
+ }
816
+ -1 === payload._status && (payload._status = 0, payload._result = thenable);
817
+ }
818
+ if (1 === payload._status) return ioInfo = payload._result, void 0 === ioInfo && console.error("lazy: Expected the result of a dynamic import() call. Instead received: %s\n\nYour code should look like: \n const MyComponent = lazy(() => import('./MyComponent'))\n\nDid you accidentally put curly braces around the import?", ioInfo), "default" in ioInfo || console.error("lazy: Expected the result of a dynamic import() call. Instead received: %s\n\nYour code should look like: \n const MyComponent = lazy(() => import('./MyComponent'))", ioInfo), ioInfo.default;
819
+ throw payload._result;
820
+ }
821
+ function resolveDispatcher() {
822
+ var dispatcher = ReactSharedInternals.H;
823
+ null === dispatcher && console.error("Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:\n1. You might have mismatching versions of React and the renderer (such as React DOM)\n2. You might be breaking the Rules of Hooks\n3. You might have more than one copy of React in the same app\nSee https://react.dev/link/invalid-hook-call for tips about how to debug and fix this problem.");
824
+ return dispatcher;
825
+ }
826
+ function releaseAsyncTransition() {
827
+ ReactSharedInternals.asyncTransitions--;
828
+ }
829
+ function enqueueTask(task) {
830
+ if (null === enqueueTaskImpl) try {
831
+ var requireString = ("require" + Math.random()).slice(0, 7);
832
+ enqueueTaskImpl = (module && module[requireString]).call(module, "timers").setImmediate;
833
+ } catch (_err) {
834
+ enqueueTaskImpl = function(callback) {
835
+ !1 === didWarnAboutMessageChannel && (didWarnAboutMessageChannel = !0, "undefined" === typeof MessageChannel && console.error("This browser does not have a MessageChannel implementation, so enqueuing tasks via await act(async () => ...) will fail. Please file an issue at https://github.com/facebook/react/issues if you encounter this warning."));
836
+ var channel = new MessageChannel();
837
+ channel.port1.onmessage = callback;
838
+ channel.port2.postMessage(void 0);
839
+ };
840
+ }
841
+ return enqueueTaskImpl(task);
842
+ }
843
+ function aggregateErrors(errors) {
844
+ return 1 < errors.length && "function" === typeof AggregateError ? new AggregateError(errors) : errors[0];
845
+ }
846
+ function popActScope(prevActQueue, prevActScopeDepth) {
847
+ prevActScopeDepth !== actScopeDepth - 1 && console.error("You seem to have overlapping act() calls, this is not supported. Be sure to await previous act() calls before making a new one. ");
848
+ actScopeDepth = prevActScopeDepth;
849
+ }
850
+ function recursivelyFlushAsyncActWork(returnValue, resolve, reject) {
851
+ var queue = ReactSharedInternals.actQueue;
852
+ if (null !== queue) if (0 !== queue.length) try {
853
+ flushActQueue(queue);
854
+ enqueueTask(function() {
855
+ return recursivelyFlushAsyncActWork(returnValue, resolve, reject);
856
+ });
857
+ return;
858
+ } catch (error) {
859
+ ReactSharedInternals.thrownErrors.push(error);
860
+ }
861
+ else ReactSharedInternals.actQueue = null;
862
+ 0 < ReactSharedInternals.thrownErrors.length ? (queue = aggregateErrors(ReactSharedInternals.thrownErrors), ReactSharedInternals.thrownErrors.length = 0, reject(queue)) : resolve(returnValue);
863
+ }
864
+ function flushActQueue(queue) {
865
+ if (!isFlushing) {
866
+ isFlushing = !0;
867
+ var i = 0;
868
+ try {
869
+ for (; i < queue.length; i++) {
870
+ var callback = queue[i];
871
+ do {
872
+ ReactSharedInternals.didUsePromise = !1;
873
+ var continuation = callback(!1);
874
+ if (null !== continuation) {
875
+ if (ReactSharedInternals.didUsePromise) {
876
+ queue[i] = callback;
877
+ queue.splice(0, i);
878
+ return;
879
+ }
880
+ callback = continuation;
881
+ } else break;
882
+ } while (1);
883
+ }
884
+ queue.length = 0;
885
+ } catch (error) {
886
+ queue.splice(0, i + 1), ReactSharedInternals.thrownErrors.push(error);
887
+ } finally {
888
+ isFlushing = !1;
889
+ }
890
+ }
891
+ }
892
+ "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(Error());
893
+ var REACT_ELEMENT_TYPE = Symbol.for("react.transitional.element"), REACT_PORTAL_TYPE = Symbol.for("react.portal"), REACT_FRAGMENT_TYPE = Symbol.for("react.fragment"), REACT_STRICT_MODE_TYPE = Symbol.for("react.strict_mode"), REACT_PROFILER_TYPE = Symbol.for("react.profiler"), REACT_CONSUMER_TYPE = Symbol.for("react.consumer"), REACT_CONTEXT_TYPE = Symbol.for("react.context"), REACT_FORWARD_REF_TYPE = Symbol.for("react.forward_ref"), REACT_SUSPENSE_TYPE = Symbol.for("react.suspense"), REACT_SUSPENSE_LIST_TYPE = Symbol.for("react.suspense_list"), REACT_MEMO_TYPE = Symbol.for("react.memo"), REACT_LAZY_TYPE = Symbol.for("react.lazy"), REACT_ACTIVITY_TYPE = Symbol.for("react.activity"), MAYBE_ITERATOR_SYMBOL = Symbol.iterator, didWarnStateUpdateForUnmountedComponent = {}, ReactNoopUpdateQueue = {
894
+ isMounted: function() {
895
+ return !1;
896
+ },
897
+ enqueueForceUpdate: function(publicInstance) {
898
+ warnNoop(publicInstance, "forceUpdate");
899
+ },
900
+ enqueueReplaceState: function(publicInstance) {
901
+ warnNoop(publicInstance, "replaceState");
902
+ },
903
+ enqueueSetState: function(publicInstance) {
904
+ warnNoop(publicInstance, "setState");
905
+ }
906
+ }, assign = Object.assign, emptyObject = {};
907
+ Object.freeze(emptyObject);
908
+ Component.prototype.isReactComponent = {};
909
+ Component.prototype.setState = function(partialState, callback) {
910
+ if ("object" !== typeof partialState && "function" !== typeof partialState && null != partialState) throw Error("takes an object of state variables to update or a function which returns an object of state variables.");
911
+ this.updater.enqueueSetState(this, partialState, callback, "setState");
912
+ };
913
+ Component.prototype.forceUpdate = function(callback) {
914
+ this.updater.enqueueForceUpdate(this, callback, "forceUpdate");
915
+ };
916
+ var deprecatedAPIs = {
917
+ isMounted: ["isMounted", "Instead, make sure to clean up subscriptions and pending requests in componentWillUnmount to prevent memory leaks."],
918
+ replaceState: ["replaceState", "Refactor your code to use setState instead (see https://github.com/facebook/react/issues/3236)."]
919
+ };
920
+ for (fnName in deprecatedAPIs) deprecatedAPIs.hasOwnProperty(fnName) && defineDeprecationWarning(fnName, deprecatedAPIs[fnName]);
921
+ ComponentDummy.prototype = Component.prototype;
922
+ deprecatedAPIs = PureComponent.prototype = new ComponentDummy();
923
+ deprecatedAPIs.constructor = PureComponent;
924
+ assign(deprecatedAPIs, Component.prototype);
925
+ deprecatedAPIs.isPureReactComponent = !0;
926
+ var isArrayImpl = Array.isArray, REACT_CLIENT_REFERENCE = Symbol.for("react.client.reference"), ReactSharedInternals = {
927
+ H: null,
928
+ A: null,
929
+ T: null,
930
+ S: null,
931
+ actQueue: null,
932
+ asyncTransitions: 0,
933
+ isBatchingLegacy: !1,
934
+ didScheduleLegacyUpdate: !1,
935
+ didUsePromise: !1,
936
+ thrownErrors: [],
937
+ getCurrentStack: null,
938
+ recentlyCreatedOwnerStacks: 0
939
+ }, hasOwnProperty = Object.prototype.hasOwnProperty, createTask = console.createTask ? console.createTask : function() {
940
+ return null;
941
+ };
942
+ deprecatedAPIs = { react_stack_bottom_frame: function(callStackForError) {
943
+ return callStackForError();
944
+ } };
945
+ var specialPropKeyWarningShown, didWarnAboutOldJSXRuntime;
946
+ var didWarnAboutElementRef = {};
947
+ var unknownOwnerDebugStack = deprecatedAPIs.react_stack_bottom_frame.bind(deprecatedAPIs, UnknownOwner)();
948
+ var unknownOwnerDebugTask = createTask(getTaskName(UnknownOwner));
949
+ var didWarnAboutMaps = !1, userProvidedKeyEscapeRegex = /\/+/g, reportGlobalError = "function" === typeof reportError ? reportError : function(error) {
950
+ if ("object" === typeof window && "function" === typeof window.ErrorEvent) {
951
+ var event = new window.ErrorEvent("error", {
952
+ bubbles: !0,
953
+ cancelable: !0,
954
+ message: "object" === typeof error && null !== error && "string" === typeof error.message ? String(error.message) : String(error),
955
+ error
956
+ });
957
+ if (!window.dispatchEvent(event)) return;
958
+ } else if ("object" === typeof process && "function" === typeof process.emit) {
959
+ process.emit("uncaughtException", error);
960
+ return;
961
+ }
962
+ console.error(error);
963
+ }, didWarnAboutMessageChannel = !1, enqueueTaskImpl = null, actScopeDepth = 0, didWarnNoAwaitAct = !1, isFlushing = !1, queueSeveralMicrotasks = "function" === typeof queueMicrotask ? function(callback) {
964
+ queueMicrotask(function() {
965
+ return queueMicrotask(callback);
966
+ });
967
+ } : enqueueTask;
968
+ deprecatedAPIs = Object.freeze({
969
+ __proto__: null,
970
+ c: function(size) {
971
+ return resolveDispatcher().useMemoCache(size);
972
+ }
973
+ });
974
+ var fnName = {
975
+ map: mapChildren,
976
+ forEach: function(children, forEachFunc, forEachContext) {
977
+ mapChildren(children, function() {
978
+ forEachFunc.apply(this, arguments);
979
+ }, forEachContext);
980
+ },
981
+ count: function(children) {
982
+ var n = 0;
983
+ mapChildren(children, function() {
984
+ n++;
985
+ });
986
+ return n;
987
+ },
988
+ toArray: function(children) {
989
+ return mapChildren(children, function(child) {
990
+ return child;
991
+ }) || [];
992
+ },
993
+ only: function(children) {
994
+ if (!isValidElement$1(children)) throw Error("React.Children.only expected to receive a single React element child.");
995
+ return children;
996
+ }
997
+ };
998
+ exports.Activity = REACT_ACTIVITY_TYPE;
999
+ exports.Children = fnName;
1000
+ exports.Component = Component;
1001
+ exports.Fragment = REACT_FRAGMENT_TYPE;
1002
+ exports.Profiler = REACT_PROFILER_TYPE;
1003
+ exports.PureComponent = PureComponent;
1004
+ exports.StrictMode = REACT_STRICT_MODE_TYPE;
1005
+ exports.Suspense = REACT_SUSPENSE_TYPE;
1006
+ exports.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE = ReactSharedInternals;
1007
+ exports.__COMPILER_RUNTIME = deprecatedAPIs;
1008
+ exports.act = function(callback) {
1009
+ var prevActQueue = ReactSharedInternals.actQueue, prevActScopeDepth = actScopeDepth;
1010
+ actScopeDepth++;
1011
+ var queue = ReactSharedInternals.actQueue = null !== prevActQueue ? prevActQueue : [], didAwaitActCall = !1;
1012
+ try {
1013
+ var result = callback();
1014
+ } catch (error) {
1015
+ ReactSharedInternals.thrownErrors.push(error);
1016
+ }
1017
+ if (0 < ReactSharedInternals.thrownErrors.length) throw popActScope(prevActQueue, prevActScopeDepth), callback = aggregateErrors(ReactSharedInternals.thrownErrors), ReactSharedInternals.thrownErrors.length = 0, callback;
1018
+ if (null !== result && "object" === typeof result && "function" === typeof result.then) {
1019
+ var thenable = result;
1020
+ queueSeveralMicrotasks(function() {
1021
+ didAwaitActCall || didWarnNoAwaitAct || (didWarnNoAwaitAct = !0, console.error("You called act(async () => ...) without await. This could lead to unexpected testing behaviour, interleaving multiple act calls and mixing their scopes. You should - await act(async () => ...);"));
1022
+ });
1023
+ return { then: function(resolve, reject) {
1024
+ didAwaitActCall = !0;
1025
+ thenable.then(function(returnValue) {
1026
+ popActScope(prevActQueue, prevActScopeDepth);
1027
+ if (0 === prevActScopeDepth) {
1028
+ try {
1029
+ flushActQueue(queue), enqueueTask(function() {
1030
+ return recursivelyFlushAsyncActWork(returnValue, resolve, reject);
1031
+ });
1032
+ } catch (error$0) {
1033
+ ReactSharedInternals.thrownErrors.push(error$0);
1034
+ }
1035
+ if (0 < ReactSharedInternals.thrownErrors.length) {
1036
+ var _thrownError = aggregateErrors(ReactSharedInternals.thrownErrors);
1037
+ ReactSharedInternals.thrownErrors.length = 0;
1038
+ reject(_thrownError);
1039
+ }
1040
+ } else resolve(returnValue);
1041
+ }, function(error) {
1042
+ popActScope(prevActQueue, prevActScopeDepth);
1043
+ 0 < ReactSharedInternals.thrownErrors.length ? (error = aggregateErrors(ReactSharedInternals.thrownErrors), ReactSharedInternals.thrownErrors.length = 0, reject(error)) : reject(error);
1044
+ });
1045
+ } };
1046
+ }
1047
+ var returnValue$jscomp$0 = result;
1048
+ popActScope(prevActQueue, prevActScopeDepth);
1049
+ 0 === prevActScopeDepth && (flushActQueue(queue), 0 !== queue.length && queueSeveralMicrotasks(function() {
1050
+ didAwaitActCall || didWarnNoAwaitAct || (didWarnNoAwaitAct = !0, console.error("A component suspended inside an `act` scope, but the `act` call was not awaited. When testing React components that depend on asynchronous data, you must await the result:\n\nawait act(() => ...)"));
1051
+ }), ReactSharedInternals.actQueue = null);
1052
+ if (0 < ReactSharedInternals.thrownErrors.length) throw callback = aggregateErrors(ReactSharedInternals.thrownErrors), ReactSharedInternals.thrownErrors.length = 0, callback;
1053
+ return { then: function(resolve, reject) {
1054
+ didAwaitActCall = !0;
1055
+ 0 === prevActScopeDepth ? (ReactSharedInternals.actQueue = queue, enqueueTask(function() {
1056
+ return recursivelyFlushAsyncActWork(returnValue$jscomp$0, resolve, reject);
1057
+ })) : resolve(returnValue$jscomp$0);
1058
+ } };
1059
+ };
1060
+ exports.cache = function(fn) {
1061
+ return function() {
1062
+ return fn.apply(null, arguments);
1063
+ };
1064
+ };
1065
+ exports.cacheSignal = function() {
1066
+ return null;
1067
+ };
1068
+ exports.captureOwnerStack = function() {
1069
+ var getCurrentStack = ReactSharedInternals.getCurrentStack;
1070
+ return null === getCurrentStack ? null : getCurrentStack();
1071
+ };
1072
+ exports.cloneElement = function(element, config, children) {
1073
+ if (null === element || void 0 === element) throw Error("The argument must be a React element, but you passed " + element + ".");
1074
+ var props = assign({}, element.props), key = element.key, owner = element._owner;
1075
+ if (null != config) {
1076
+ var JSCompiler_inline_result;
1077
+ a: {
1078
+ if (hasOwnProperty.call(config, "ref") && (JSCompiler_inline_result = Object.getOwnPropertyDescriptor(config, "ref").get) && JSCompiler_inline_result.isReactWarning) {
1079
+ JSCompiler_inline_result = !1;
1080
+ break a;
1081
+ }
1082
+ JSCompiler_inline_result = void 0 !== config.ref;
1083
+ }
1084
+ JSCompiler_inline_result && (owner = getOwner());
1085
+ hasValidKey(config) && (checkKeyStringCoercion(config.key), key = "" + config.key);
1086
+ for (propName in config) !hasOwnProperty.call(config, propName) || "key" === propName || "__self" === propName || "__source" === propName || "ref" === propName && void 0 === config.ref || (props[propName] = config[propName]);
1087
+ }
1088
+ var propName = arguments.length - 2;
1089
+ if (1 === propName) props.children = children;
1090
+ else if (1 < propName) {
1091
+ JSCompiler_inline_result = Array(propName);
1092
+ for (var i = 0; i < propName; i++) JSCompiler_inline_result[i] = arguments[i + 2];
1093
+ props.children = JSCompiler_inline_result;
1094
+ }
1095
+ props = ReactElement(element.type, key, props, owner, element._debugStack, element._debugTask);
1096
+ for (key = 2; key < arguments.length; key++) validateChildKeys(arguments[key]);
1097
+ return props;
1098
+ };
1099
+ exports.createContext = function(defaultValue) {
1100
+ defaultValue = {
1101
+ $$typeof: REACT_CONTEXT_TYPE,
1102
+ _currentValue: defaultValue,
1103
+ _currentValue2: defaultValue,
1104
+ _threadCount: 0,
1105
+ Provider: null,
1106
+ Consumer: null
1107
+ };
1108
+ defaultValue.Provider = defaultValue;
1109
+ defaultValue.Consumer = {
1110
+ $$typeof: REACT_CONSUMER_TYPE,
1111
+ _context: defaultValue
1112
+ };
1113
+ defaultValue._currentRenderer = null;
1114
+ defaultValue._currentRenderer2 = null;
1115
+ return defaultValue;
1116
+ };
1117
+ exports.createElement = function(type, config, children) {
1118
+ for (var i = 2; i < arguments.length; i++) validateChildKeys(arguments[i]);
1119
+ i = {};
1120
+ var key = null;
1121
+ if (null != config) for (propName in didWarnAboutOldJSXRuntime || !("__self" in config) || "key" in config || (didWarnAboutOldJSXRuntime = !0, console.warn("Your app (or one of its dependencies) is using an outdated JSX transform. Update to the modern JSX transform for faster performance: https://react.dev/link/new-jsx-transform")), hasValidKey(config) && (checkKeyStringCoercion(config.key), key = "" + config.key), config) hasOwnProperty.call(config, propName) && "key" !== propName && "__self" !== propName && "__source" !== propName && (i[propName] = config[propName]);
1122
+ var childrenLength = arguments.length - 2;
1123
+ if (1 === childrenLength) i.children = children;
1124
+ else if (1 < childrenLength) {
1125
+ for (var childArray = Array(childrenLength), _i = 0; _i < childrenLength; _i++) childArray[_i] = arguments[_i + 2];
1126
+ Object.freeze && Object.freeze(childArray);
1127
+ i.children = childArray;
1128
+ }
1129
+ if (type && type.defaultProps) for (propName in childrenLength = type.defaultProps, childrenLength) void 0 === i[propName] && (i[propName] = childrenLength[propName]);
1130
+ key && defineKeyPropWarningGetter(i, "function" === typeof type ? type.displayName || type.name || "Unknown" : type);
1131
+ var propName = 1e4 > ReactSharedInternals.recentlyCreatedOwnerStacks++;
1132
+ return ReactElement(type, key, i, getOwner(), propName ? Error("react-stack-top-frame") : unknownOwnerDebugStack, propName ? createTask(getTaskName(type)) : unknownOwnerDebugTask);
1133
+ };
1134
+ exports.createRef = function() {
1135
+ var refObject = { current: null };
1136
+ Object.seal(refObject);
1137
+ return refObject;
1138
+ };
1139
+ exports.forwardRef = function(render) {
1140
+ null != render && render.$$typeof === REACT_MEMO_TYPE ? console.error("forwardRef requires a render function but received a `memo` component. Instead of forwardRef(memo(...)), use memo(forwardRef(...)).") : "function" !== typeof render ? console.error("forwardRef requires a render function but was given %s.", null === render ? "null" : typeof render) : 0 !== render.length && 2 !== render.length && console.error("forwardRef render functions accept exactly two parameters: props and ref. %s", 1 === render.length ? "Did you forget to use the ref parameter?" : "Any additional parameter will be undefined.");
1141
+ null != render && null != render.defaultProps && console.error("forwardRef render functions do not support defaultProps. Did you accidentally pass a React component?");
1142
+ var elementType = {
1143
+ $$typeof: REACT_FORWARD_REF_TYPE,
1144
+ render
1145
+ }, ownName;
1146
+ Object.defineProperty(elementType, "displayName", {
1147
+ enumerable: !1,
1148
+ configurable: !0,
1149
+ get: function() {
1150
+ return ownName;
1151
+ },
1152
+ set: function(name) {
1153
+ ownName = name;
1154
+ render.name || render.displayName || (Object.defineProperty(render, "name", { value: name }), render.displayName = name);
1155
+ }
1156
+ });
1157
+ return elementType;
1158
+ };
1159
+ exports.isValidElement = isValidElement$1;
1160
+ exports.lazy = function(ctor) {
1161
+ ctor = {
1162
+ _status: -1,
1163
+ _result: ctor
1164
+ };
1165
+ var lazyType = {
1166
+ $$typeof: REACT_LAZY_TYPE,
1167
+ _payload: ctor,
1168
+ _init: lazyInitializer
1169
+ }, ioInfo = {
1170
+ name: "lazy",
1171
+ start: -1,
1172
+ end: -1,
1173
+ value: null,
1174
+ owner: null,
1175
+ debugStack: Error("react-stack-top-frame"),
1176
+ debugTask: console.createTask ? console.createTask("lazy()") : null
1177
+ };
1178
+ ctor._ioInfo = ioInfo;
1179
+ lazyType._debugInfo = [{ awaited: ioInfo }];
1180
+ return lazyType;
1181
+ };
1182
+ exports.memo = function(type, compare) {
1183
+ type ?? console.error("memo: The first argument must be a component. Instead received: %s", null === type ? "null" : typeof type);
1184
+ compare = {
1185
+ $$typeof: REACT_MEMO_TYPE,
1186
+ type,
1187
+ compare: void 0 === compare ? null : compare
1188
+ };
1189
+ var ownName;
1190
+ Object.defineProperty(compare, "displayName", {
1191
+ enumerable: !1,
1192
+ configurable: !0,
1193
+ get: function() {
1194
+ return ownName;
1195
+ },
1196
+ set: function(name) {
1197
+ ownName = name;
1198
+ type.name || type.displayName || (Object.defineProperty(type, "name", { value: name }), type.displayName = name);
1199
+ }
1200
+ });
1201
+ return compare;
1202
+ };
1203
+ exports.startTransition = function(scope) {
1204
+ var prevTransition = ReactSharedInternals.T, currentTransition = {};
1205
+ currentTransition._updatedFibers = /* @__PURE__ */ new Set();
1206
+ ReactSharedInternals.T = currentTransition;
1207
+ try {
1208
+ var returnValue = scope(), onStartTransitionFinish = ReactSharedInternals.S;
1209
+ null !== onStartTransitionFinish && onStartTransitionFinish(currentTransition, returnValue);
1210
+ "object" === typeof returnValue && null !== returnValue && "function" === typeof returnValue.then && (ReactSharedInternals.asyncTransitions++, returnValue.then(releaseAsyncTransition, releaseAsyncTransition), returnValue.then(noop, reportGlobalError));
1211
+ } catch (error) {
1212
+ reportGlobalError(error);
1213
+ } finally {
1214
+ null === prevTransition && currentTransition._updatedFibers && (scope = currentTransition._updatedFibers.size, currentTransition._updatedFibers.clear(), 10 < scope && console.warn("Detected a large number of updates inside startTransition. If this is due to a subscription please re-write it to use React provided hooks. Otherwise concurrent mode guarantees are off the table.")), null !== prevTransition && null !== currentTransition.types && (null !== prevTransition.types && prevTransition.types !== currentTransition.types && console.error("We expected inner Transitions to have transferred the outer types set and that you cannot add to the outer Transition while inside the inner.This is a bug in React."), prevTransition.types = currentTransition.types), ReactSharedInternals.T = prevTransition;
1215
+ }
1216
+ };
1217
+ exports.unstable_useCacheRefresh = function() {
1218
+ return resolveDispatcher().useCacheRefresh();
1219
+ };
1220
+ exports.use = function(usable) {
1221
+ return resolveDispatcher().use(usable);
1222
+ };
1223
+ exports.useActionState = function(action, initialState, permalink) {
1224
+ return resolveDispatcher().useActionState(action, initialState, permalink);
1225
+ };
1226
+ exports.useCallback = function(callback, deps) {
1227
+ return resolveDispatcher().useCallback(callback, deps);
1228
+ };
1229
+ exports.useContext = function(Context) {
1230
+ var dispatcher = resolveDispatcher();
1231
+ Context.$$typeof === REACT_CONSUMER_TYPE && console.error("Calling useContext(Context.Consumer) is not supported and will cause bugs. Did you mean to call useContext(Context) instead?");
1232
+ return dispatcher.useContext(Context);
1233
+ };
1234
+ exports.useDebugValue = function(value, formatterFn) {
1235
+ return resolveDispatcher().useDebugValue(value, formatterFn);
1236
+ };
1237
+ exports.useDeferredValue = function(value, initialValue) {
1238
+ return resolveDispatcher().useDeferredValue(value, initialValue);
1239
+ };
1240
+ exports.useEffect = function(create, deps) {
1241
+ create ?? console.warn("React Hook useEffect requires an effect callback. Did you forget to pass a callback to the hook?");
1242
+ return resolveDispatcher().useEffect(create, deps);
1243
+ };
1244
+ exports.useEffectEvent = function(callback) {
1245
+ return resolveDispatcher().useEffectEvent(callback);
1246
+ };
1247
+ exports.useId = function() {
1248
+ return resolveDispatcher().useId();
1249
+ };
1250
+ exports.useImperativeHandle = function(ref, create, deps) {
1251
+ return resolveDispatcher().useImperativeHandle(ref, create, deps);
1252
+ };
1253
+ exports.useInsertionEffect = function(create, deps) {
1254
+ create ?? console.warn("React Hook useInsertionEffect requires an effect callback. Did you forget to pass a callback to the hook?");
1255
+ return resolveDispatcher().useInsertionEffect(create, deps);
1256
+ };
1257
+ exports.useLayoutEffect = function(create, deps) {
1258
+ create ?? console.warn("React Hook useLayoutEffect requires an effect callback. Did you forget to pass a callback to the hook?");
1259
+ return resolveDispatcher().useLayoutEffect(create, deps);
1260
+ };
1261
+ exports.useMemo = function(create, deps) {
1262
+ return resolveDispatcher().useMemo(create, deps);
1263
+ };
1264
+ exports.useOptimistic = function(passthrough, reducer) {
1265
+ return resolveDispatcher().useOptimistic(passthrough, reducer);
1266
+ };
1267
+ exports.useReducer = function(reducer, initialArg, init) {
1268
+ return resolveDispatcher().useReducer(reducer, initialArg, init);
1269
+ };
1270
+ exports.useRef = function(initialValue) {
1271
+ return resolveDispatcher().useRef(initialValue);
1272
+ };
1273
+ exports.useState = function(initialState) {
1274
+ return resolveDispatcher().useState(initialState);
1275
+ };
1276
+ exports.useSyncExternalStore = function(subscribe, getSnapshot, getServerSnapshot) {
1277
+ return resolveDispatcher().useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
1278
+ };
1279
+ exports.useTransition = function() {
1280
+ return resolveDispatcher().useTransition();
1281
+ };
1282
+ exports.version = "19.2.4";
1283
+ "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(Error());
1284
+ })();
1285
+ }));
1286
+
1287
+ //#endregion
1288
+ //#region ../../../node_modules/.pnpm/react@19.2.4/node_modules/react/index.js
1289
+ var require_react = /* @__PURE__ */ __commonJSMin(((exports, module) => {
1290
+ if (process.env.NODE_ENV === "production") module.exports = require_react_production();
1291
+ else module.exports = require_react_development();
1292
+ }));
1293
+
1294
+ //#endregion
1295
+ //#region src/commands/generate/utils/intl.ts
1296
+ var import_react = require_react();
1297
+ function isFormattedMessageElement(node) {
1298
+ return (0, import_react.isValidElement)(node) && node.type === FormattedMessage;
1299
+ }
1300
+ /**
1301
+ * Generates a <FormattedMessage> JSX element or an intl.formatMessage call string supporting <FormattedMessage> config objects.
1302
+ *
1303
+ * either config or defaultMessage is required
1304
+ */
1305
+ const generateFormattedMessage = (options) => {
1306
+ let id = options.id;
1307
+ let defaultMessage = "";
1308
+ if ("defaultMessage" in options) defaultMessage = options.defaultMessage;
1309
+ if (isFormattedMessageElement(options.config)) {
1310
+ if (!options.config.props.id) throw new Error("FormattedMessage requires an id");
1311
+ id = options.config.props.id;
1312
+ if (!options.config.props.defaultMessage) throw new Error("FormattedMessage requires an defaultMessage");
1313
+ if (typeof options.config.props.defaultMessage !== "string") throw new Error("FormattedMessage requires a string defaultMessage");
1314
+ defaultMessage = options.config.props.defaultMessage;
1315
+ } else if (typeof options.config === "string") defaultMessage = options.config;
1316
+ if (options.type === "jsx") return `<FormattedMessage id=${JSON.stringify(id)} defaultMessage=${JSON.stringify(defaultMessage)} />`;
1317
+ else return `intl.formatMessage({ id: ${JSON.stringify(id)}, defaultMessage: ${JSON.stringify(defaultMessage)} })`;
1318
+ };
1319
+
1320
+ //#endregion
1321
+ //#region src/commands/generate/utils/isFieldOptional.ts
1322
+ const isFieldOptional = ({ config, gqlIntrospection, gqlType }) => {
1323
+ if (config.required !== void 0) return !config.required;
1324
+ if (config.readOnly) return true;
1325
+ const schemaEntity = gqlIntrospection.__schema.types.find((type) => type.kind === "OBJECT" && type.name === gqlType);
1326
+ if (!schemaEntity) throw new Error(`didn't find entity ${gqlType} in schema types`);
1327
+ if (schemaEntity.kind !== "OBJECT") throw new Error(`kind of ${gqlType} is not object, but should be.`);
1328
+ const fieldDef = schemaEntity.fields.find((field) => field.name === String(config.name));
1329
+ if (!fieldDef) return false;
1330
+ return fieldDef.type.kind !== "NON_NULL";
1331
+ };
1332
+
1333
+ //#endregion
1334
+ //#region src/commands/generate/utils/findQueryType.ts
1335
+ function findQueryType(queryName, schema) {
1336
+ const queryType = schema.__schema.types.find((type) => type.name === schema.__schema.queryType.name);
1337
+ if (!queryType) throw new Error("Can't find Query type in gql schema");
1338
+ const ret = queryType.fields.find((field) => field.name === queryName);
1339
+ if (!ret) throw new Error(`Can't find query ${queryName} in gql schema`);
1340
+ return ret;
1341
+ }
1342
+ function findQueryTypeOrThrow(queryName, schema) {
1343
+ const ret = findQueryType(queryName, schema);
1344
+ if (!ret) throw new Error(`Can't find query ${queryName} in gql schema`);
1345
+ return ret;
1346
+ }
1347
+
1348
+ //#endregion
1349
+ //#region src/commands/generate/generateForm/formField/options.ts
1350
+ const buildAdornmentData = ({ adornmentData }) => {
1351
+ let adornmentString = "";
1352
+ let adornmentImport = {
1353
+ name: "",
1354
+ importPath: ""
1355
+ };
1356
+ if (typeof adornmentData === "string") return { adornmentString: adornmentData };
1357
+ if (typeof adornmentData.icon === "string") {
1358
+ adornmentString = `<${adornmentData.icon}Icon />`;
1359
+ adornmentImport = {
1360
+ name: `${adornmentData.icon} as ${adornmentData.icon}Icon`,
1361
+ importPath: "@comet/admin-icons"
1362
+ };
1363
+ } else if (typeof adornmentData.icon === "object") if (isGeneratorConfigImport(adornmentData.icon)) {
1364
+ adornmentString = `<${adornmentData.icon.name} />`;
1365
+ adornmentImport = convertConfigImport(adornmentData.icon);
1366
+ } else {
1367
+ const { name, ...iconProps } = adornmentData.icon;
1368
+ adornmentString = `<${name}Icon
1369
+ ${Object.entries(iconProps).map(([key, value]) => `${key}="${value}"`).join("\n")}
1370
+ />`;
1371
+ adornmentImport = {
1372
+ name: `${adornmentData.icon.name} as ${adornmentData.icon.name}Icon`,
1373
+ importPath: "@comet/admin-icons"
1374
+ };
1375
+ }
1376
+ return {
1377
+ adornmentString,
1378
+ adornmentImport
1379
+ };
1380
+ };
1381
+ /**
1382
+ * Helper function that builds various options needed for generating form fields.
1383
+ */
1384
+ function buildFormFieldOptions({ config, formConfig }) {
1385
+ const rootGqlType = formConfig.gqlType;
1386
+ const name = String(config.name);
1387
+ const formattedMessageRootId = rootGqlType[0].toLowerCase() + rootGqlType.substring(1);
1388
+ const fieldLabel = generateFormattedMessage({
1389
+ config: config.label,
1390
+ id: `${formattedMessageRootId}.${name}`,
1391
+ defaultMessage: camelCaseToHumanReadable(name),
1392
+ type: "jsx"
1393
+ });
1394
+ const imports = [];
1395
+ let startAdornment = { adornmentString: "" };
1396
+ let endAdornment = { adornmentString: "" };
1397
+ if ("startAdornment" in config && config.startAdornment) {
1398
+ startAdornment = buildAdornmentData({ adornmentData: config.startAdornment });
1399
+ if (startAdornment.adornmentImport) imports.push(startAdornment.adornmentImport);
1400
+ }
1401
+ if ("endAdornment" in config && config.endAdornment) {
1402
+ endAdornment = buildAdornmentData({ adornmentData: config.endAdornment });
1403
+ if (endAdornment.adornmentImport) imports.push(endAdornment.adornmentImport);
1404
+ }
1405
+ return {
1406
+ name,
1407
+ formattedMessageRootId,
1408
+ fieldLabel,
1409
+ startAdornment,
1410
+ endAdornment,
1411
+ imports
1412
+ };
1413
+ }
1414
+
1415
+ //#endregion
1416
+ //#region src/commands/generate/generateForm/asyncSelect/generateAsyncSelect.ts
1417
+ function gqlScalarToTypescriptType(scalarName) {
1418
+ if (scalarName === "String" || scalarName === "ID" || scalarName === "DateTime" || scalarName === "LocalDate" || scalarName === "Date") return "string";
1419
+ else if (scalarName === "Boolean") return "boolean";
1420
+ else if (scalarName === "Int" || scalarName === "Float") return "number";
1421
+ else if (scalarName === "JSONObject") return "unknown";
1422
+ else return "unknown";
1423
+ }
1424
+ function buildTypeInfo(arg, gqlIntrospection) {
1425
+ let typeKind = void 0;
1426
+ let typeClass = "unknown";
1427
+ let required = false;
1428
+ let type = arg.type;
1429
+ let inputType = void 0;
1430
+ if (type.kind === "NON_NULL") {
1431
+ required = true;
1432
+ type = type.ofType;
1433
+ }
1434
+ if (type.kind === "INPUT_OBJECT") {
1435
+ typeClass = type.name;
1436
+ typeKind = type.kind;
1437
+ inputType = gqlIntrospection.__schema.types.find((type$1) => type$1.name === typeClass);
1438
+ } else if (type.kind === "ENUM") {
1439
+ typeClass = type.name;
1440
+ typeKind = type.kind;
1441
+ } else if (type.kind === "SCALAR") {
1442
+ typeClass = type.name;
1443
+ typeKind = type.kind;
1444
+ } else throw new Error(`getTypeInfo: Resolving kind ${type.kind} currently not supported.`);
1445
+ return {
1446
+ required,
1447
+ typeKind,
1448
+ typeClass,
1449
+ inputType
1450
+ };
1451
+ }
1452
+ /**
1453
+ * Helper that returns the introspection object type for a given form field config, supporting the special case for asyncSelectFilter
1454
+ */
1455
+ function findIntrospectionObjectType({ config, gqlIntrospection, gqlType }) {
1456
+ const name = String(config.name);
1457
+ const introspectionObject = gqlIntrospection.__schema.types.find((type) => type.kind === "OBJECT" && type.name === gqlType);
1458
+ if (!introspectionObject) throw new Error(`didn't find object ${gqlType} in gql introspection`);
1459
+ function findIntrospectionField(introspectionObject$1, name$1) {
1460
+ const introspectionField = introspectionObject$1.fields.find((field) => field.name === name$1);
1461
+ if (!introspectionField) throw new Error(`didn't find field ${name$1} in gql introspection type ${gqlType}`);
1462
+ let introspectionFieldType = introspectionField.type.kind === "NON_NULL" ? introspectionField.type.ofType : introspectionField.type;
1463
+ const multiple = introspectionFieldType?.kind === "LIST";
1464
+ if (introspectionFieldType?.kind === "LIST") introspectionFieldType = introspectionFieldType.ofType.kind === "NON_NULL" ? introspectionFieldType.ofType.ofType : introspectionFieldType.ofType;
1465
+ if (introspectionFieldType.kind !== "OBJECT") throw new Error(`asyncSelect only supports OBJECT types`);
1466
+ const objectType = gqlIntrospection.__schema.types.find((t) => t.kind === "OBJECT" && t.name === introspectionFieldType.name);
1467
+ if (!objectType) throw new Error(`Object type ${introspectionFieldType.name} not found for field ${name$1}`);
1468
+ return {
1469
+ multiple,
1470
+ objectType
1471
+ };
1472
+ }
1473
+ if (config.type === "asyncSelectFilter") return {
1474
+ multiple: false,
1475
+ objectType: config.loadValueQueryField.split(".").reduce((acc, fieldName) => {
1476
+ const introspectionField = findIntrospectionField(acc, fieldName);
1477
+ if (introspectionField.multiple) throw new Error(`asyncSelectFilter does not support list fields in loadValueQueryField`);
1478
+ return introspectionField.objectType;
1479
+ }, introspectionObject)
1480
+ };
1481
+ else return findIntrospectionField(introspectionObject, name);
1482
+ }
1483
+ function generateAsyncSelect({ gqlIntrospection, baseOutputFilename, config, formConfig, gqlType, namePrefix }) {
1484
+ const imports = [];
1485
+ const formProps = [];
1486
+ const { name, fieldLabel, startAdornment, imports: optionsImports } = buildFormFieldOptions({
1487
+ config,
1488
+ formConfig
1489
+ });
1490
+ imports.push(...optionsImports);
1491
+ const nameWithPrefix = `${namePrefix ? `${namePrefix}.` : ``}${name}`;
1492
+ const required = !isFieldOptional({
1493
+ config,
1494
+ gqlIntrospection,
1495
+ gqlType
1496
+ });
1497
+ const formValueConfig = {
1498
+ fieldName: name,
1499
+ destructFromFormValues: config.type == "asyncSelectFilter"
1500
+ };
1501
+ let finalFormConfig;
1502
+ let code = "";
1503
+ const { objectType, multiple } = findIntrospectionObjectType({
1504
+ config,
1505
+ gqlIntrospection,
1506
+ gqlType
1507
+ });
1508
+ let labelField = config.labelField;
1509
+ if (!labelField) labelField = objectType.fields.find((field) => {
1510
+ let type = field.type;
1511
+ if (type.kind == "NON_NULL") type = type.ofType;
1512
+ if ((field.name == "name" || field.name == "title") && type.kind == "SCALAR" && type.name == "String") return true;
1513
+ })?.name;
1514
+ if (!labelField) labelField = objectType.fields.find((field) => {
1515
+ let type = field.type;
1516
+ if (type.kind == "NON_NULL") type = type.ofType;
1517
+ if (field.type.kind == "SCALAR" && field.type.name == "String") return true;
1518
+ })?.name;
1519
+ const rootQuery = config.rootQuery;
1520
+ const queryName = `${rootQuery[0].toUpperCase() + rootQuery.substring(1)}Select`;
1521
+ const rootQueryType = findQueryTypeOrThrow(rootQuery, gqlIntrospection);
1522
+ let formFragmentFields;
1523
+ if (config.type == "asyncSelectFilter") formFragmentFields = [`${config.loadValueQueryField}.id`, `${config.loadValueQueryField}.${labelField}`];
1524
+ else formFragmentFields = [`${name}.id`, `${name}.${labelField}`];
1525
+ const rootQueryHasSearchArg = rootQueryType.args.find((arg) => arg.name === "search");
1526
+ const useAutocomplete = config.autocomplete ?? !!rootQueryHasSearchArg;
1527
+ if (useAutocomplete) {
1528
+ if (!rootQueryHasSearchArg) throw new Error(`Field ${String(config.name)}: Autocomplete is enabled but root query "${rootQuery}" has no search argument.`);
1529
+ if (rootQueryHasSearchArg.type.kind !== "SCALAR" || rootQueryHasSearchArg.type.name !== "String") throw new Error(`Field ${String(config.name)}: Autocomplete is enabled but root query "${rootQuery}" has search argument that is not a string.`);
1530
+ }
1531
+ const filterConfig = config.filter ? (() => {
1532
+ let filterField;
1533
+ let rootQueryArg = config.filter.rootQueryArg;
1534
+ let filterVar = "";
1535
+ if (config.filter.type === "field") {
1536
+ filterField = findFieldByName(config.filter.formFieldName, formConfig.fields);
1537
+ if (!filterField) throw new Error(`Field ${String(config.name)}: No field with name "${config.filter.formFieldName}" referenced as filter.formFieldName found in form-config.`);
1538
+ if (!isFormFieldConfig(filterField)) throw new Error(`Field ${String(config.name)}: Field with name "${config.filter.formFieldName}" referenced as filter.formFieldName is no FormField.`);
1539
+ filterVar = `values.${filterField.type === "asyncSelect" || filterField.type === "asyncSelectFilter" ? `${String(filterField.name)}?.id` : String(filterField.name)}`;
1540
+ if (!rootQueryArg) rootQueryArg = config.filter.formFieldName;
1541
+ } else if (config.filter.type === "formProp") {
1542
+ filterVar = config.filter.propName;
1543
+ if (!rootQueryArg) rootQueryArg = config.filter.propName;
1544
+ } else throw new Error("unsupported filter type");
1545
+ const rootArgForName = rootQueryType.args.find((arg) => arg.name === rootQueryArg);
1546
+ let filterType = rootArgForName ? buildTypeInfo(rootArgForName, gqlIntrospection) : void 0;
1547
+ let filterVarName = void 0;
1548
+ let filterVarValue = void 0;
1549
+ let filterVarType = "unknown";
1550
+ if (filterType) {
1551
+ filterVarName = rootQueryArg;
1552
+ filterVarValue = filterVar;
1553
+ if (filterType.typeKind === "INPUT_OBJECT" || filterType.typeKind === "ENUM") {
1554
+ filterVarType = `GQL${filterType.typeClass}`;
1555
+ imports.push({
1556
+ name: filterVarType,
1557
+ importPath: "@src/graphql.generated"
1558
+ });
1559
+ } else if (filterType.typeKind === "SCALAR") filterVarType = gqlScalarToTypescriptType(filterType.typeClass);
1560
+ } else {
1561
+ const rootArgFilter = rootQueryType.args.find((arg) => arg.name === "filter");
1562
+ filterType = rootArgFilter ? buildTypeInfo(rootArgFilter, gqlIntrospection) : void 0;
1563
+ if (filterType) {
1564
+ filterVarName = "filter";
1565
+ filterVarValue = `{ ${rootQueryArg}: { equal: ${filterVar} } }`;
1566
+ if (filterType.inputType?.kind !== "INPUT_OBJECT") throw new Error(`Field ${String(config.name)}: Type of filter is no object-type.`);
1567
+ const nestedFilterInput = filterType.inputType.inputFields.find((inputField) => inputField.name === rootQueryArg);
1568
+ if (!nestedFilterInput) throw new Error(`Field ${String(config.name)}: Field filter.${rootQueryArg} does not exist`);
1569
+ const gqlFilterInputType = buildTypeInfo(nestedFilterInput, gqlIntrospection);
1570
+ if (!gqlFilterInputType?.inputType || gqlFilterInputType.inputType.kind !== "INPUT_OBJECT") throw new Error(`Field ${String(config.name)}: Type of filter.${rootQueryArg} is no object-type, but needs to be e.g. StringFilter-type.`);
1571
+ const gqlFilterEqualInputType = gqlFilterInputType.inputType.inputFields.find((inputField) => inputField.name === "equal");
1572
+ if (!gqlFilterEqualInputType) throw new Error(`Field ${String(config.name)}: Field filter.${rootQueryArg}.equal does not exist`);
1573
+ const equalFieldType = buildTypeInfo(gqlFilterEqualInputType, gqlIntrospection);
1574
+ if (!equalFieldType) throw new Error(`Field ${String(config.name)}: Field filter.${rootQueryArg}.equal does not exist but is required for filtering.`);
1575
+ if (equalFieldType.typeKind === "INPUT_OBJECT" || equalFieldType.typeKind === "ENUM") {
1576
+ filterVarType = `GQL${equalFieldType.typeClass}`;
1577
+ imports.push({
1578
+ name: filterVarType,
1579
+ importPath: "@src/graphql.generated"
1580
+ });
1581
+ } else if (equalFieldType.typeKind === "SCALAR") filterVarType = gqlScalarToTypescriptType(equalFieldType.typeClass);
1582
+ } else throw new Error(`Neither filter-prop nor root-prop with name: ${rootQueryArg} for asyncSelect-query not found. Consider setting filterField.gqlVarName explicitly.`);
1583
+ }
1584
+ if (config.filter.type === "formProp") formProps.push({
1585
+ name: config.filter.propName,
1586
+ optional: false,
1587
+ type: filterVarType
1588
+ });
1589
+ return {
1590
+ filterField,
1591
+ filterType,
1592
+ filterVarName,
1593
+ filterVarValue
1594
+ };
1595
+ })() : void 0;
1596
+ if (filterConfig) {
1597
+ imports.push({
1598
+ name: "OnChangeField",
1599
+ importPath: "@comet/admin"
1600
+ });
1601
+ finalFormConfig = {
1602
+ subscription: { values: true },
1603
+ renderProps: {
1604
+ values: true,
1605
+ form: true
1606
+ }
1607
+ };
1608
+ }
1609
+ if (config.type != "asyncSelectFilter") if (!multiple) if (!required) formValueConfig.formValueToGqlInputCode = `$fieldName ? $fieldName.id : null`;
1610
+ else formValueConfig.formValueToGqlInputCode = `$fieldName?.id`;
1611
+ else formValueConfig.formValueToGqlInputCode = `$fieldName.map((item) => item.id)`;
1612
+ imports.push({
1613
+ name: `GQL${queryName}Query`,
1614
+ importPath: `./${baseOutputFilename}.generated`
1615
+ });
1616
+ imports.push({
1617
+ name: `GQL${queryName}QueryVariables`,
1618
+ importPath: `./${baseOutputFilename}.generated`
1619
+ });
1620
+ if (useAutocomplete) imports.push({
1621
+ name: "AsyncAutocompleteField",
1622
+ importPath: "@comet/admin"
1623
+ });
1624
+ else imports.push({
1625
+ name: "AsyncSelectField",
1626
+ importPath: "@comet/admin"
1627
+ });
1628
+ const instanceGqlType = gqlType[0].toLowerCase() + gqlType.substring(1);
1629
+ if (config.type == "asyncSelectFilter") {
1630
+ formValueConfig.typeCode = {
1631
+ nullable: true,
1632
+ type: `{ id: string; ${labelField}: string }`
1633
+ };
1634
+ formValueConfig.initializationCode = `data.${instanceGqlType}.${config.loadValueQueryField.replace(/\./g, "?.")}`;
1635
+ }
1636
+ code = `<${useAutocomplete ? "AsyncAutocompleteField" : "AsyncSelectField"}
1637
+ ${required ? "required" : ""}
1638
+ variant="horizontal"
1639
+ fullWidth
1640
+ ${config.readOnly ? "readOnly disabled" : ""}
1641
+ ${multiple ? "multiple" : ""}
1642
+ name="${nameWithPrefix}"
1643
+ label={${fieldLabel}}
1644
+ ${config.startAdornment ? `startAdornment={<InputAdornment position="start">${startAdornment.adornmentString}</InputAdornment>}` : ""}
1645
+ loadOptions={async (${useAutocomplete ? `search?: string` : ""}) => {
1646
+ const { data } = await client.query<GQL${queryName}Query, GQL${queryName}QueryVariables>({
1647
+ query: gql\`${generateGqlOperation({
1648
+ type: "query",
1649
+ operationName: queryName,
1650
+ rootOperation: rootQuery,
1651
+ fields: ["nodes.id", `nodes.${labelField}`],
1652
+ variables: [useAutocomplete ? {
1653
+ name: "search",
1654
+ type: "String"
1655
+ } : void 0, filterConfig ? {
1656
+ name: filterConfig.filterVarName,
1657
+ type: filterConfig.filterType.typeClass + (filterConfig.filterType.required ? `!` : ``)
1658
+ } : void 0].filter((v) => v !== void 0)
1659
+ })}\`${filterConfig || useAutocomplete ? ", variables: { " : ""}
1660
+ ${filterConfig ? `${filterConfig.filterVarName}: ${filterConfig.filterVarValue},` : ``}
1661
+ ${useAutocomplete ? `search,` : ``}
1662
+ ${filterConfig || useAutocomplete ? " }" : ""}
1663
+ });
1664
+ return data.${rootQuery}.nodes;
1665
+ }}
1666
+ getOptionLabel={(option) => option.${labelField}}
1667
+ ${filterConfig?.filterField ? `disabled={!values?.${String(filterConfig.filterField.name)}}` : ``}
1668
+ />${filterConfig?.filterField ? `<OnChangeField name="${String(filterConfig.filterField.name)}">
1669
+ {(value, previousValue) => {
1670
+ if (value.id !== previousValue.id) {
1671
+ form.change("${String(config.name)}", undefined);
1672
+ }
1673
+ }}
1674
+ </OnChangeField>` : ``}`;
1675
+ return {
1676
+ code,
1677
+ hooksCode: "",
1678
+ formFragmentFields,
1679
+ gqlDocuments: {},
1680
+ imports,
1681
+ formProps,
1682
+ formValuesConfig: [formValueConfig],
1683
+ finalFormConfig
1684
+ };
1685
+ }
1686
+
1687
+ //#endregion
1688
+ //#region src/commands/generate/generateForm/formField/findIntrospectionFieldType.ts
1689
+ function findIntrospectionFieldType({ name, gqlType, gqlIntrospection }) {
1690
+ let introspectionFieldType;
1691
+ for (const namePart of name.split(".")) {
1692
+ const introspectionObject = gqlIntrospection.__schema.types.find((type) => type.kind === "OBJECT" && type.name === gqlType);
1693
+ if (!introspectionObject) throw new Error(`didn't find object ${gqlType} in gql introspection`);
1694
+ const introspectionField = introspectionObject.fields.find((field) => field.name === namePart);
1695
+ introspectionFieldType = introspectionField ? introspectionField.type.kind === "NON_NULL" ? introspectionField.type.ofType : introspectionField.type : void 0;
1696
+ if (introspectionFieldType?.kind === "OBJECT") gqlType = introspectionFieldType.name;
1697
+ }
1698
+ return introspectionFieldType;
1699
+ }
1700
+
1701
+ //#endregion
1702
+ //#region src/commands/generate/generateForm/generateFormField.ts
1703
+ function generateFormField({ gqlIntrospection, baseOutputFilename, config, formConfig, gqlType, namePrefix }) {
1704
+ if (config.type == "asyncSelect" || config.type == "asyncSelectFilter") return generateAsyncSelect({
1705
+ gqlIntrospection,
1706
+ baseOutputFilename,
1707
+ config,
1708
+ formConfig,
1709
+ gqlType,
1710
+ namePrefix
1711
+ });
1712
+ const imports = [];
1713
+ const formProps = [];
1714
+ const { name, formattedMessageRootId, fieldLabel, startAdornment, endAdornment, imports: optionsImports } = buildFormFieldOptions({
1715
+ config,
1716
+ formConfig
1717
+ });
1718
+ imports.push(...optionsImports);
1719
+ let introspectionFieldType = findIntrospectionFieldType({
1720
+ name,
1721
+ gqlIntrospection,
1722
+ gqlType
1723
+ });
1724
+ const nameWithPrefix = `${namePrefix ? `${namePrefix}.` : ``}${name}`;
1725
+ const rootGqlType = formConfig.gqlType;
1726
+ const dataRootName = rootGqlType[0].toLowerCase() + rootGqlType.substring(1);
1727
+ const required = !isFieldOptional({
1728
+ config,
1729
+ gqlIntrospection,
1730
+ gqlType
1731
+ });
1732
+ const endAdornmentWithLockIconProp = `endAdornment={<InputAdornment position="end"><Lock /></InputAdornment>}`;
1733
+ const readOnlyProps = `readOnly disabled`;
1734
+ const readOnlyPropsWithLock = `${readOnlyProps} ${endAdornmentWithLockIconProp}`;
1735
+ const formValueConfig = { fieldName: nameWithPrefix };
1736
+ const gqlDocuments = {};
1737
+ const hooksCode = "";
1738
+ let finalFormConfig;
1739
+ let validateCode = "";
1740
+ if (config.validate) {
1741
+ if (isGeneratorConfigImport(config.validate)) {
1742
+ imports.push(convertConfigImport(config.validate));
1743
+ validateCode = `validate={${config.validate.name}}`;
1744
+ } else if (isGeneratorConfigCode(config.validate)) {
1745
+ validateCode = `validate={${config.validate.code}}`;
1746
+ imports.push(...config.validate.imports.map((imprt) => convertConfigImport(imprt)));
1747
+ }
1748
+ }
1749
+ let code = "";
1750
+ let formFragmentFields = [name];
1751
+ if (config.type == "text") {
1752
+ code = `
1753
+ <${config.multiline ? "TextAreaField" : "TextField"}
1754
+ ${required ? "required" : ""}
1755
+ ${config.readOnly ? readOnlyPropsWithLock : ""}
1756
+ variant="horizontal"
1757
+ fullWidth
1758
+ name="${nameWithPrefix}"
1759
+ label={${fieldLabel}}
1760
+ ${config.startAdornment ? `startAdornment={<InputAdornment position="start">${startAdornment.adornmentString}</InputAdornment>}` : ""}
1761
+ ${config.endAdornment ? `endAdornment={<InputAdornment position="end">${endAdornment.adornmentString}</InputAdornment>}` : ""}
1762
+ ${config.helperText ? `helperText={${generateFormattedMessage({
1763
+ config: config.helperText,
1764
+ id: `${formattedMessageRootId}.${name}.helperText`,
1765
+ type: "jsx"
1766
+ })}}` : ""}
1767
+ ${validateCode}
1768
+ />`;
1769
+ if (!required && !config.readOnly) formValueConfig.formValueToGqlInputCode = `$fieldName ?? null`;
1770
+ if (config.initialValue !== void 0) formValueConfig.defaultInitializationCode = JSON.stringify(config.initialValue);
1771
+ } else if (config.type == "number") {
1772
+ code = `
1773
+ <NumberField
1774
+ ${required ? "required" : ""}
1775
+ ${config.readOnly ? readOnlyPropsWithLock : ""}
1776
+ variant="horizontal"
1777
+ fullWidth
1778
+ name="${nameWithPrefix}"
1779
+ label={${fieldLabel}}
1780
+ ${config.decimals ? `decimals={${config.decimals}}` : ""}
1781
+ ${config.startAdornment ? `startAdornment={<InputAdornment position="start">${startAdornment.adornmentString}</InputAdornment>}` : ""}
1782
+ ${config.endAdornment ? `endAdornment={<InputAdornment position="end">${endAdornment.adornmentString}</InputAdornment>}` : ""}
1783
+ ${config.helperText ? `helperText={<FormattedMessage id="${formattedMessageRootId}.${name}.helperText" defaultMessage="${config.helperText}" />}` : ""}
1784
+ ${validateCode}
1785
+ />`;
1786
+ if (!required && !config.readOnly) formValueConfig.formValueToGqlInputCode = `$fieldName ?? null`;
1787
+ if (config.initialValue !== void 0) formValueConfig.defaultInitializationCode = JSON.stringify(config.initialValue);
1788
+ } else if (config.type === "numberRange") {
1789
+ code = `
1790
+ <Field
1791
+ ${required ? "required" : ""}
1792
+ ${config.readOnly ? readOnlyPropsWithLock : ""}
1793
+ variant="horizontal"
1794
+ fullWidth
1795
+ name="${nameWithPrefix}"
1796
+ component={FinalFormRangeInput}
1797
+ label={${fieldLabel}}
1798
+ min={${config.minValue}}
1799
+ max={${config.maxValue}}
1800
+ ${config.disableSlider ? "disableSlider" : ""}
1801
+ ${config.startAdornment ? `startAdornment={<InputAdornment position="start">${startAdornment.adornmentString}</InputAdornment>}` : ""}
1802
+ ${config.endAdornment ? `endAdornment={<InputAdornment position="end">${endAdornment.adornmentString}</InputAdornment>}` : ""}
1803
+ ${config.helperText ? `helperText={<FormattedMessage id="${formattedMessageRootId}.${name}.helperText" defaultMessage="${config.helperText}" />}` : ""}
1804
+ ${validateCode}
1805
+ />`;
1806
+ formFragmentFields = [`${name}.min`, `${name}.max`];
1807
+ if (config.initialValue !== void 0) formValueConfig.defaultInitializationCode = JSON.stringify(config.initialValue);
1808
+ } else if (config.type == "boolean") {
1809
+ const checkboxLabel = config.checkboxLabel ? generateFormattedMessage({
1810
+ config: config.checkboxLabel,
1811
+ id: `${formattedMessageRootId}.${name}.checkboxLabel`,
1812
+ type: "jsx"
1813
+ }) : "";
1814
+ code = `<CheckboxField
1815
+ fieldLabel={${fieldLabel}}
1816
+ ${config.checkboxLabel ? `label={${checkboxLabel}}` : ""}
1817
+ name="${nameWithPrefix}"
1818
+ fullWidth
1819
+ variant="horizontal"
1820
+ ${config.readOnly ? readOnlyProps : ""}
1821
+ ${config.helperText ? `helperText={<FormattedMessage id="${formattedMessageRootId}.${name}.helperText" defaultMessage="${config.helperText}" />}` : ""}
1822
+ ${validateCode}
1823
+ />`;
1824
+ formValueConfig.defaultInitializationCode = config.initialValue ? "true" : "false";
1825
+ } else if (config.type == "date") {
1826
+ imports.push({
1827
+ name: "DatePickerField",
1828
+ importPath: "@comet/admin"
1829
+ });
1830
+ code = `
1831
+ <DatePickerField
1832
+ ${required ? "required" : ""}
1833
+ ${config.readOnly ? readOnlyPropsWithLock : ""}
1834
+ variant="horizontal"
1835
+ fullWidth
1836
+ name="${nameWithPrefix}"
1837
+ label={${fieldLabel}}
1838
+ ${config.startAdornment ? `startAdornment={<InputAdornment position="start">${startAdornment.adornmentString}</InputAdornment>}` : ""}
1839
+ ${config.endAdornment ? `endAdornment={<InputAdornment position="end">${endAdornment.adornmentString}</InputAdornment>}` : ""}
1840
+ ${config.helperText ? `helperText={<FormattedMessage id="${formattedMessageRootId}.${name}.helperText" defaultMessage="${config.helperText}" />}` : ""}
1841
+ ${validateCode}
1842
+ />`;
1843
+ if (!required && !config.readOnly) formValueConfig.formValueToGqlInputCode = `$fieldName ?? null`;
1844
+ if (config.initialValue !== void 0) formValueConfig.defaultInitializationCode = JSON.stringify(config.initialValue);
1845
+ } else if (config.type == "dateTime") {
1846
+ imports.push({
1847
+ name: "DateTimePickerField",
1848
+ importPath: "@comet/admin"
1849
+ });
1850
+ code = `<DateTimePickerField
1851
+ ${required ? "required" : ""}
1852
+ ${config.readOnly ? readOnlyPropsWithLock : ""}
1853
+ variant="horizontal"
1854
+ fullWidth
1855
+ name="${nameWithPrefix}"
1856
+ label={${fieldLabel}}
1857
+ ${config.startAdornment ? `startAdornment={<InputAdornment position="start">${startAdornment.adornmentString}</InputAdornment>}` : ""}
1858
+ ${config.endAdornment ? `endAdornment={<InputAdornment position="end">${endAdornment.adornmentString}</InputAdornment>}` : ""}
1859
+ ${config.helperText ? `helperText={<FormattedMessage id="${formattedMessageRootId}.${name}.helperText" defaultMessage="${config.helperText}" />}` : ""}
1860
+ ${validateCode}
1861
+ />`;
1862
+ formValueConfig.initializationCode = `data.${dataRootName}.${nameWithPrefix} ? new Date(data.${dataRootName}.${nameWithPrefix}) : undefined`;
1863
+ formValueConfig.omitFromFragmentType = true;
1864
+ formValueConfig.typeCode = {
1865
+ nullable: !required,
1866
+ type: `Date${!required ? " | null" : ""}`
1867
+ };
1868
+ if (!config.readOnly) formValueConfig.formValueToGqlInputCode = required ? `$fieldName.toISOString()` : `$fieldName ? $fieldName.toISOString() : null`;
1869
+ if (config.initialValue !== void 0) formValueConfig.defaultInitializationCode = `new Date("${config.initialValue.toISOString()}")`;
1870
+ } else if (config.type == "block") {
1871
+ code = `<Field name="${nameWithPrefix}" isEqual={isEqual} label={${fieldLabel}} variant="horizontal" fullWidth>
1872
+ {createFinalFormBlock(rootBlocks.${String(config.name)})}
1873
+ </Field>`;
1874
+ formValueConfig.formValueToGqlInputCode = `rootBlocks.${name}.state2Output($fieldName)`;
1875
+ formValueConfig.omitFromFragmentType = true;
1876
+ formValueConfig.typeCode = {
1877
+ nullable: false,
1878
+ type: `BlockState<typeof rootBlocks.${name}>`
1879
+ };
1880
+ formValueConfig.initializationCode = `rootBlocks.${name}.input2State(data.${dataRootName}.${nameWithPrefix})`;
1881
+ formValueConfig.defaultInitializationCode = `rootBlocks.${name}.defaultValues()`;
1882
+ } else if (config.type === "fileUpload") {
1883
+ const multiple = config.multiple || typeof config.maxFiles === "number" && config.maxFiles > 1;
1884
+ code = `<FileUploadField name="${name}" label={${fieldLabel}}
1885
+ variant="horizontal"
1886
+ ${config.multiple ? "multiple" : ""}
1887
+ ${config.maxFiles ? `maxFiles={${config.maxFiles}}` : ""}
1888
+ ${config.maxFileSize ? `maxFileSize={${config.maxFileSize}}` : ""}
1889
+ ${config.readOnly ? `readOnly` : ""}
1890
+ ${config.layout ? `layout="${config.layout}"` : ""}
1891
+ ${config.accept ? `accept="${config.accept}"` : ""}
1892
+ />`;
1893
+ if (multiple) formValueConfig.formValueToGqlInputCode = `$fieldName?.map(({ id }) => id)`;
1894
+ else formValueConfig.formValueToGqlInputCode = `$fieldName ? $fieldName.id : null`;
1895
+ formFragmentFields = [`${name}...${config.download ? "FinalFormFileUploadDownloadable" : "FinalFormFileUpload"}`];
1896
+ } else if (config.type == "staticSelect") {
1897
+ const multiple = introspectionFieldType?.kind === "LIST";
1898
+ if (introspectionFieldType?.kind === "LIST") introspectionFieldType = introspectionFieldType.ofType.kind === "NON_NULL" ? introspectionFieldType.ofType.ofType : introspectionFieldType.ofType;
1899
+ const enumType = gqlIntrospection.__schema.types.find((t) => t.kind === "ENUM" && t.name === introspectionFieldType.name);
1900
+ if (!enumType) throw new Error(`Enum type ${introspectionFieldType.name} not found for field ${name}`);
1901
+ const values = (config.values ? config.values : enumType.enumValues.map((i) => i.name)).map((value) => {
1902
+ if (typeof value === "string") {
1903
+ const messageId = `${formattedMessageRootId}.${name}.${value.charAt(0).toLowerCase() + value.slice(1)}`;
1904
+ return {
1905
+ value,
1906
+ labelCode: generateFormattedMessage({
1907
+ config: void 0,
1908
+ defaultMessage: camelCaseToHumanReadable(value),
1909
+ id: messageId,
1910
+ type: "jsx"
1911
+ })
1912
+ };
1913
+ } else {
1914
+ const messageId = `${formattedMessageRootId}.${name}.${value.value.charAt(0).toLowerCase() + value.value.slice(1)}`;
1915
+ const valueLabel = generateFormattedMessage({
1916
+ config: value.label,
1917
+ id: messageId,
1918
+ type: "jsx"
1919
+ });
1920
+ return {
1921
+ value: value.value,
1922
+ labelCode: valueLabel
1923
+ };
1924
+ }
1925
+ });
1926
+ let inputType = config.inputType;
1927
+ if (!inputType) if (!required || multiple) inputType = "select";
1928
+ else if (values.length <= 5) inputType = "radio";
1929
+ else inputType = "select";
1930
+ if (inputType === "radio" && multiple) throw new Error(`${name}: inputType=radio doesn't support multiple`);
1931
+ if (inputType === "radio" && !required) throw new Error(`${name}: inputType=radio must be required as it doesn't support clearable`);
1932
+ if (inputType === "radio") code = `<RadioGroupField
1933
+ ${required ? "required" : ""}
1934
+ variant="horizontal"
1935
+ fullWidth
1936
+ name="${nameWithPrefix}"
1937
+ label={${fieldLabel}}
1938
+ options={[
1939
+ ${values.map((value) => {
1940
+ return `{
1941
+ label: ${value.labelCode},
1942
+ value: "${value.value}",
1943
+ }`;
1944
+ }).join(",")}
1945
+ ]}/>`;
1946
+ else {
1947
+ imports.push({
1948
+ name: "SelectField",
1949
+ importPath: "@comet/admin"
1950
+ });
1951
+ code = `<SelectField
1952
+ ${required ? "required" : ""}
1953
+ fullWidth
1954
+ variant={"horizontal"}
1955
+ name="${nameWithPrefix}"
1956
+ label={${fieldLabel}}
1957
+ ${config.startAdornment ? `startAdornment={<InputAdornment position="start">${startAdornment.adornmentString}</InputAdornment>}` : ""}
1958
+ ${config.helperText ? `helperText={<FormattedMessage id="${formattedMessageRootId}.${name}.helperText" defaultMessage="${config.helperText}" />}` : ""}
1959
+ ${validateCode}
1960
+ ${config.readOnly ? readOnlyPropsWithLock : ""}
1961
+ ${multiple ? "multiple" : ""}
1962
+ options={[${values.map((value) => {
1963
+ return `{
1964
+ value: "${value.value}",
1965
+ label: ${value.labelCode}
1966
+ }`;
1967
+ })}]}
1968
+ />`;
1969
+ }
1970
+ if (config.initialValue !== void 0) formValueConfig.defaultInitializationCode = JSON.stringify(config.initialValue);
1971
+ } else throw new Error(`Unsupported type`);
1972
+ return {
1973
+ code,
1974
+ hooksCode,
1975
+ formFragmentFields,
1976
+ gqlDocuments,
1977
+ imports,
1978
+ formProps,
1979
+ formValuesConfig: [formValueConfig],
1980
+ finalFormConfig
1981
+ };
1982
+ }
1983
+
1984
+ //#endregion
1985
+ //#region src/commands/generate/generateForm/generateFormLayout.ts
1986
+ function generateFormLayout({ gqlIntrospection, baseOutputFilename, config, formFragmentName, formConfig, gqlType, namePrefix }) {
1987
+ const rootGqlType = formConfig.gqlType;
1988
+ const formattedMessageRootId = rootGqlType[0].toLowerCase() + rootGqlType.substring(1);
1989
+ const dataRootName = rootGqlType[0].toLowerCase() + rootGqlType.substring(1);
1990
+ let code = "";
1991
+ let hooksCode = "";
1992
+ const formFragmentFields = [];
1993
+ const gqlDocuments = {};
1994
+ const imports = [];
1995
+ const formProps = [];
1996
+ const formValuesConfig = [];
1997
+ const finalFormConfig = {
1998
+ subscription: {},
1999
+ renderProps: {}
2000
+ };
2001
+ if (config.type === "fieldSet") {
2002
+ const generatedFields = generateFields({
2003
+ gqlIntrospection,
2004
+ baseOutputFilename,
2005
+ fields: config.fields,
2006
+ formFragmentName,
2007
+ formConfig,
2008
+ gqlType,
2009
+ namePrefix
2010
+ });
2011
+ hooksCode += generatedFields.hooksCode;
2012
+ formFragmentFields.push(...generatedFields.formFragmentFields);
2013
+ for (const name in generatedFields.gqlDocuments) gqlDocuments[name] = generatedFields.gqlDocuments[name];
2014
+ imports.push(...generatedFields.imports);
2015
+ formProps.push(...generatedFields.formProps);
2016
+ formValuesConfig.push(...generatedFields.formValuesConfig);
2017
+ finalFormConfig.subscription = {
2018
+ ...finalFormConfig.subscription,
2019
+ ...generatedFields.finalFormConfig?.subscription
2020
+ };
2021
+ finalFormConfig.renderProps = {
2022
+ ...finalFormConfig.renderProps,
2023
+ ...generatedFields.finalFormConfig?.renderProps
2024
+ };
2025
+ imports.push({
2026
+ name: "FieldSet",
2027
+ importPath: "@comet/admin"
2028
+ });
2029
+ const supportPlaceholder = config.supportText?.includes("{");
2030
+ if (supportPlaceholder) imports.push({
2031
+ name: "FormSpy",
2032
+ importPath: "react-final-form"
2033
+ });
2034
+ code = `
2035
+ <FieldSet
2036
+ ${config.collapsible === void 0 || config.collapsible ? `collapsible` : ``}
2037
+ ${config.initiallyExpanded != null ? `initiallyExpanded={${config.initiallyExpanded}}` : ``}
2038
+ title={${generateFormattedMessage({
2039
+ config: config.title,
2040
+ id: `${formattedMessageRootId}.${config.name}.title`,
2041
+ defaultMessage: camelCaseToHumanReadable(config.name),
2042
+ type: "jsx"
2043
+ })}}
2044
+ ${config.supportText ? `supportText={
2045
+ ${supportPlaceholder ? `mode === "edit" && (<FormSpy subscription={{ values: true }}>{({ values }) => (` : ``}
2046
+ <FormattedMessage
2047
+ id="${formattedMessageRootId}.${config.name}.supportText"
2048
+ defaultMessage="${config.supportText}"
2049
+ ${supportPlaceholder ? `values={{ ...values }}` : ``}
2050
+ />
2051
+ ${supportPlaceholder ? `)}</FormSpy>)` : ``}
2052
+ }` : ``}
2053
+ >
2054
+ ${generatedFields.code}
2055
+ </FieldSet>`;
2056
+ } else if (config.type === "optionalNestedFields") {
2057
+ const name = String(config.name);
2058
+ const introspectionFieldType = findIntrospectionFieldType({
2059
+ name,
2060
+ gqlType,
2061
+ gqlIntrospection
2062
+ });
2063
+ if (!introspectionFieldType) throw new Error(`field ${name} in gql introspection type ${gqlType} not found`);
2064
+ if (introspectionFieldType.kind !== "OBJECT") throw new Error(`field ${name} in gql introspection type ${gqlType} has to be OBJECT`);
2065
+ const generatedFields = generateFields({
2066
+ gqlIntrospection,
2067
+ baseOutputFilename,
2068
+ fields: config.fields,
2069
+ formFragmentName,
2070
+ formConfig,
2071
+ gqlType: introspectionFieldType.name,
2072
+ namePrefix: name
2073
+ });
2074
+ hooksCode += generatedFields.hooksCode;
2075
+ formFragmentFields.push(...generatedFields.formFragmentFields.map((field) => `${name}.${field}`));
2076
+ for (const name$1 in generatedFields.gqlDocuments) gqlDocuments[name$1] = generatedFields.gqlDocuments[name$1];
2077
+ imports.push(...generatedFields.imports);
2078
+ formValuesConfig.push(...generatedFields.formValuesConfig);
2079
+ formValuesConfig.push({
2080
+ fieldName: `${name}Enabled`,
2081
+ omitFromFragmentType: false,
2082
+ destructFromFormValues: true,
2083
+ typeCode: {
2084
+ nullable: false,
2085
+ type: "boolean"
2086
+ },
2087
+ initializationCode: `!!data.${dataRootName}.${name}`
2088
+ });
2089
+ formValuesConfig.push({
2090
+ fieldName: `${name}`,
2091
+ wrapFormValueToGqlInputCode: `${name.split(".").pop()}Enabled && $fieldName ? $inner : null`
2092
+ });
2093
+ imports.push({
2094
+ name: "FinalFormSwitch",
2095
+ importPath: "@comet/admin"
2096
+ });
2097
+ imports.push({
2098
+ name: "messages",
2099
+ importPath: "@comet/admin"
2100
+ });
2101
+ imports.push({
2102
+ name: "FormControlLabel",
2103
+ importPath: "@mui/material"
2104
+ });
2105
+ code = `<Field
2106
+ fullWidth
2107
+ name="${String(config.name)}Enabled"
2108
+ type="checkbox"
2109
+ label={${generateFormattedMessage({
2110
+ config: config.checkboxLabel,
2111
+ id: `${formattedMessageRootId}.${String(config.name)}.${String(config.name)}Enabled`,
2112
+ defaultMessage: `Enable ${camelCaseToHumanReadable(String(config.name))}`,
2113
+ type: "jsx"
2114
+ })}}
2115
+ >
2116
+ {(props) => (
2117
+ <FormControlLabel
2118
+ control={<FinalFormSwitch {...props} />}
2119
+ label={props.input.checked ? <FormattedMessage {...messages.yes} /> : <FormattedMessage {...messages.no} />}
2120
+ />
2121
+ )}
2122
+ </Field>
2123
+ <Field name="${String(config.name)}Enabled" fullWidth subscription={{ value: true }}>
2124
+ {({ input: { value } }) =>
2125
+ value ? (
2126
+ <>
2127
+ ${generatedFields.code}
2128
+ </>
2129
+ ) : null
2130
+ }
2131
+ </Field>`;
2132
+ } else throw new Error(`Unsupported type`);
2133
+ return {
2134
+ code,
2135
+ hooksCode,
2136
+ formFragmentFields,
2137
+ gqlDocuments,
2138
+ imports,
2139
+ formProps,
2140
+ formValuesConfig,
2141
+ finalFormConfig
2142
+ };
2143
+ }
2144
+
2145
+ //#endregion
2146
+ //#region src/commands/generate/generateForm/generateFields.ts
2147
+ function findFieldByName(name, fields) {
2148
+ return fields.reduce((acc, field) => {
2149
+ return acc ? acc : "name" in field && field.name === name ? field : isFormLayoutConfig(field) ? findFieldByName(name, field.fields) : void 0;
2150
+ }, void 0);
2151
+ }
2152
+ function generateFields({ gqlIntrospection, baseOutputFilename, fields, formFragmentName, formConfig, gqlType, namePrefix }) {
2153
+ const gqlDocuments = {};
2154
+ let hooksCode = "";
2155
+ const formFragmentFields = [];
2156
+ const imports = [];
2157
+ const formProps = [];
2158
+ const formValuesConfig = [];
2159
+ const finalFormConfig = {
2160
+ subscription: {},
2161
+ renderProps: {}
2162
+ };
2163
+ return {
2164
+ code: fields.map((field) => {
2165
+ let generated;
2166
+ if (field.type === "component") generated = generateComponentFormField({ config: field });
2167
+ else if (isFormFieldConfig(field)) generated = generateFormField({
2168
+ gqlIntrospection,
2169
+ baseOutputFilename,
2170
+ formFragmentName,
2171
+ config: field,
2172
+ formConfig,
2173
+ gqlType,
2174
+ namePrefix
2175
+ });
2176
+ else if (isFormLayoutConfig(field)) generated = generateFormLayout({
2177
+ gqlIntrospection,
2178
+ baseOutputFilename,
2179
+ formFragmentName,
2180
+ config: field,
2181
+ formConfig,
2182
+ gqlType,
2183
+ namePrefix
2184
+ });
2185
+ else throw new Error("Not supported config");
2186
+ for (const name in generated.gqlDocuments) gqlDocuments[name] = generated.gqlDocuments[name];
2187
+ imports.push(...generated.imports);
2188
+ formProps.push(...generated.formProps);
2189
+ hooksCode += generated.hooksCode;
2190
+ formFragmentFields.push(...generated.formFragmentFields);
2191
+ formValuesConfig.push(...generated.formValuesConfig);
2192
+ finalFormConfig.subscription = {
2193
+ ...finalFormConfig.subscription,
2194
+ ...generated.finalFormConfig?.subscription
2195
+ };
2196
+ finalFormConfig.renderProps = {
2197
+ ...finalFormConfig.renderProps,
2198
+ ...generated.finalFormConfig?.renderProps
2199
+ };
2200
+ return generated.code;
2201
+ }).join("\n"),
2202
+ hooksCode,
2203
+ formFragmentFields,
2204
+ gqlDocuments,
2205
+ imports,
2206
+ formProps,
2207
+ formValuesConfig,
2208
+ finalFormConfig
2209
+ };
2210
+ }
2211
+
2212
+ //#endregion
2213
+ //#region src/commands/generate/generateForm/generateFormValues.ts
2214
+ function formValuesConfigToTree({ formValuesConfig, gqlIntrospection, gqlType }) {
2215
+ const treeRoot = { children: {} };
2216
+ for (const formValueConfig of formValuesConfig) {
2217
+ const fieldName = formValueConfig.fieldName;
2218
+ let currentTreeNode = treeRoot;
2219
+ let currentGqlType = gqlType;
2220
+ for (const part of fieldName.split(".")) {
2221
+ const introspectionObject = gqlIntrospection.__schema.types.find((type) => type.kind === "OBJECT" && type.name === currentGqlType);
2222
+ if (!introspectionObject) throw new Error(`didn't find object ${gqlType} in gql introspection`);
2223
+ const introspectionField = introspectionObject.fields.find((field) => field.name === part);
2224
+ const introspectionFieldType = introspectionField ? introspectionField.type.kind === "NON_NULL" ? introspectionField.type.ofType : introspectionField.type : void 0;
2225
+ if (introspectionFieldType?.kind === "OBJECT") currentGqlType = introspectionFieldType.name;
2226
+ if (!currentTreeNode.children[part]) currentTreeNode.children[part] = { children: {} };
2227
+ currentTreeNode.children[part].nullable = introspectionField?.type.kind !== "NON_NULL";
2228
+ currentTreeNode = currentTreeNode.children[part];
2229
+ }
2230
+ currentTreeNode.config = formValueConfig;
2231
+ }
2232
+ return treeRoot.children;
2233
+ }
2234
+ function generateFormValuesTypeFromTree(tree, currentTypeName, currentIsNullable) {
2235
+ const omitKeys = [];
2236
+ let appendCode = "";
2237
+ for (const [key, value] of Object.entries(tree)) if (Object.keys(value.children).length > 0) {
2238
+ let childRootType = `${currentTypeName}["${key}"]`;
2239
+ if (currentIsNullable) childRootType = `NonNullable<${currentTypeName}>["${key}"]`;
2240
+ const childOmit = generateFormValuesTypeFromTree(value.children, childRootType, value.nullable ?? false);
2241
+ if (childOmit !== childRootType) {
2242
+ appendCode += `${key}: ${childOmit}`;
2243
+ omitKeys.push(key);
2244
+ }
2245
+ if (value.config?.typeCode) throw new Error("Field has both subfields and direct typeCode, which is not supported.");
2246
+ if (value.config?.omitFromFragmentType) throw new Error("Field has both subfields and direct omitFromFragmentType, which is not supported.");
2247
+ } else if (value.config) {
2248
+ if (value.config.typeCode) appendCode += `${key}${value.config.typeCode.nullable ? "?" : ""}: ${value.config.typeCode.type}; `;
2249
+ if (value.config.omitFromFragmentType) omitKeys.push(key);
2250
+ }
2251
+ let code = omitKeys.length ? `Omit<${currentIsNullable ? `NonNullable<` : ""}${currentTypeName}${currentIsNullable ? `>` : ""}, ${omitKeys.map((k) => `"${k}"`).join(" | ")}>` : currentTypeName;
2252
+ if (appendCode.length) code += ` & { ${appendCode} }`;
2253
+ return code;
2254
+ }
2255
+ function generateFormValuesType({ formValuesConfig, filterByFragmentType, gqlIntrospection, gqlType }) {
2256
+ return `type FormValues = ${generateFormValuesTypeFromTree(formValuesConfigToTree({
2257
+ formValuesConfig,
2258
+ gqlIntrospection,
2259
+ gqlType
2260
+ }), filterByFragmentType, false)};`;
2261
+ }
2262
+ function generateInitialValuesFromTree(tree, dataObject, generationType) {
2263
+ let code = "";
2264
+ for (const [key, value] of Object.entries(tree)) if (Object.keys(value.children).length > 0) {
2265
+ let childCode = generateInitialValuesFromTree(value.children, dataObject ? `${dataObject}.${key}` : null, generationType);
2266
+ if (childCode.length) if (dataObject) {
2267
+ childCode = `{ ...${dataObject}.${key}, ${childCode} }`;
2268
+ if (value.nullable) code += `${key}: ${dataObject}.${key} ? ${childCode} : undefined, `;
2269
+ else code += `${key}: ${childCode}, `;
2270
+ } else code += `${key}: { ${childCode} }, `;
2271
+ if (value.config?.[generationType]) throw new Error("Field has both subfields and direct initialization code, which is not supported.");
2272
+ } else if (value.config) {
2273
+ if (value.config[generationType]) code += `${key}: ${value.config[generationType]}, `;
2274
+ }
2275
+ return code;
2276
+ }
2277
+ function generateInitialValues({ mode, formValuesConfig, filterByFragmentType, gqlIntrospection, gqlType, initialValuesAsProp }) {
2278
+ const instanceGqlType = gqlType[0].toLowerCase() + gqlType.substring(1);
2279
+ const editMode = mode === "edit" || mode == "all";
2280
+ const tree = formValuesConfigToTree({
2281
+ formValuesConfig,
2282
+ gqlIntrospection,
2283
+ gqlType
2284
+ });
2285
+ if (editMode) return `const initialValues = useMemo<Partial<FormValues>>(() => data?.${instanceGqlType}
2286
+ ? {
2287
+ ...filterByFragment<${filterByFragmentType}>(${instanceGqlType}FormFragment, data.${instanceGqlType}),
2288
+ ${generateInitialValuesFromTree(tree, `data.${instanceGqlType}`, "initializationCode")}
2289
+ }
2290
+ : {
2291
+ ${generateInitialValuesFromTree(tree, initialValuesAsProp ? `passedInitialValues` : null, "defaultInitializationCode")}
2292
+ ${initialValuesAsProp ? `...passedInitialValues,` : ""}
2293
+ }
2294
+ , [data]);`;
2295
+ else return `const initialValues = {
2296
+ ${generateInitialValuesFromTree(tree, initialValuesAsProp ? `passedInitialValues` : null, "defaultInitializationCode")}
2297
+ ${initialValuesAsProp ? `...passedInitialValues,` : ""}
2298
+ };`;
2299
+ }
2300
+ function generateDestructFormValueForInputFromTree(tree, restObject) {
2301
+ let code = "";
2302
+ for (const [key, value] of Object.entries(tree)) if (Object.keys(value.children).length > 0) {
2303
+ const childCode = generateDestructFormValueForInputFromTree(value.children, `${restObject}${key.substring(0, 1).toUpperCase()}${key.substring(1)}`);
2304
+ if (childCode.length) code += `${key}: { ${childCode} }, `;
2305
+ } else if (value.config) {
2306
+ if (value.config.destructFromFormValues) code += `${key}, `;
2307
+ }
2308
+ if (code.length) {
2309
+ code += `...${restObject}Rest`;
2310
+ return code;
2311
+ } else return "";
2312
+ }
2313
+ function generateDestructFormValueForInput({ formValuesConfig, gqlIntrospection, gqlType }) {
2314
+ const code = generateDestructFormValueForInputFromTree(formValuesConfigToTree({
2315
+ formValuesConfig,
2316
+ gqlIntrospection,
2317
+ gqlType
2318
+ }), "formValues");
2319
+ return code.length ? `{ ${code} }` : "formValues";
2320
+ }
2321
+ function generateFormValuesToGqlInputFromTree(tree, dataObject, restObject) {
2322
+ let code = "";
2323
+ for (const [key, value] of Object.entries(tree)) if (Object.keys(value.children).length > 0) {
2324
+ const childRestObject = `${restObject.replace(/Rest$/, "")}${key.substring(0, 1).toUpperCase()}${key.substring(1)}Rest`;
2325
+ const hasChildDestruct = hasChildDestructTree(value.children);
2326
+ let childCode = generateFormValuesToGqlInputFromTree(value.children, hasChildDestruct ? childRestObject : `${dataObject}.${key}`, childRestObject);
2327
+ if (childCode.length || hasChildDestruct) {
2328
+ childCode = `{ ...${hasChildDestruct ? childRestObject : `${dataObject}.${key}`}, ${childCode} }`;
2329
+ if (value.config?.wrapFormValueToGqlInputCode) childCode = value.config.wrapFormValueToGqlInputCode.replaceAll("$fieldName", `${dataObject}.${key}`).replaceAll("$inner", childCode);
2330
+ code += `${key}: ${childCode}, `;
2331
+ }
2332
+ if (value.config?.formValueToGqlInputCode) throw new Error("Field has both subfields and direct formValueToGqlInputCode, which is not supported.");
2333
+ } else if (value.config) {
2334
+ if (value.config.formValueToGqlInputCode) code += `${key}: ${value.config.formValueToGqlInputCode.replaceAll("$fieldName", `${dataObject}.${key}`)}, `;
2335
+ }
2336
+ return code;
2337
+ }
2338
+ function hasChildDestructTree(tree) {
2339
+ return Object.values(tree).some((childValue) => {
2340
+ if (childValue.config?.destructFromFormValues) return true;
2341
+ if (Object.keys(childValue.children).length > 0) return hasChildDestructTree(childValue.children);
2342
+ return false;
2343
+ });
2344
+ }
2345
+ function generateFormValuesToGqlInput({ formValuesConfig, gqlIntrospection, gqlType }) {
2346
+ const tree = formValuesConfigToTree({
2347
+ formValuesConfig,
2348
+ gqlIntrospection,
2349
+ gqlType
2350
+ });
2351
+ const hasChildDestruct = hasChildDestructTree(tree);
2352
+ const code = generateFormValuesToGqlInputFromTree(tree, hasChildDestruct ? "formValuesRest" : "formValues", hasChildDestruct ? "formValuesRest" : "formValues");
2353
+ if (code.length) return `const output = { ...${hasChildDestruct ? "formValuesRest" : "formValues"}, ${code} };`;
2354
+ else if (hasChildDestruct) return `const output = formValuesRest;`;
2355
+ else return `const output = formValues;`;
2356
+ }
2357
+
2358
+ //#endregion
2359
+ //#region src/commands/generate/generateForm/generateFragmentByFormFragmentFields.ts
2360
+ /**
2361
+ * Helper function that generates a GraphQL fragment from form fragment fields (array of dot.separated.fields).
2362
+ *
2363
+ * - Fragments are supported as "foo...FragmentName"
2364
+ * - for FinalFormFileUpload and FinalFormFileUploadDownloadable the needed variable is added automatically
2365
+ */
2366
+ function generateFragmentByFormFragmentFields({ formFragmentName, gqlType, formFragmentFields }) {
2367
+ let fragmentCode = `
2368
+ fragment ${formFragmentName} on ${gqlType} {
2369
+ ${generateGqlQueryTreeFromFields(formFragmentFields)}
2370
+ }
2371
+ `;
2372
+ for (const [fragmentName, fragmentVar] of Object.entries({
2373
+ "...FinalFormFileUpload": "${finalFormFileUploadFragment}",
2374
+ "...FinalFormFileUploadDownloadable": "${finalFormFileUploadDownloadableFragment}"
2375
+ })) if (fragmentCode.match(`${fragmentName.replace(".", "\\.")}\\b`) && !fragmentCode.includes(fragmentVar)) fragmentCode += `\n${fragmentVar}`;
2376
+ return fragmentCode;
2377
+ }
2378
+
2379
+ //#endregion
2380
+ //#region src/commands/generate/generateForm/getForwardedGqlArgs.ts
2381
+ function getForwardedGqlArgs$1({ fields, gqlOperation, gqlIntrospection }) {
2382
+ const ret = [];
2383
+ getArgsIncludingInputArgSubfields(gqlOperation, gqlIntrospection).forEach((arg) => {
2384
+ if (arg.isInputArgSubfield) {
2385
+ if (fields.some((field) => {
2386
+ return field.name === arg.name || field.name.startsWith(`${arg.name}.`);
2387
+ })) return;
2388
+ }
2389
+ let prop;
2390
+ const imports = [];
2391
+ if (arg.type === "ID" || arg.type === "String" || arg.type === "DateTime") prop = {
2392
+ name: arg.name,
2393
+ optional: false,
2394
+ type: "string"
2395
+ };
2396
+ else if (arg.type === "Boolean") prop = {
2397
+ name: arg.name,
2398
+ optional: false,
2399
+ type: "boolean"
2400
+ };
2401
+ else if (arg.type === "Int" || arg.type === "Float") prop = {
2402
+ name: arg.name,
2403
+ optional: false,
2404
+ type: "number"
2405
+ };
2406
+ else if (arg.type === "JSONObject") prop = {
2407
+ name: arg.name,
2408
+ optional: false,
2409
+ type: "unknown"
2410
+ };
2411
+ else {
2412
+ prop = {
2413
+ name: arg.name,
2414
+ optional: false,
2415
+ type: `GQL${arg.type}`
2416
+ };
2417
+ imports.push({
2418
+ name: `GQL${arg.type}`,
2419
+ importPath: "@src/graphql.generated"
2420
+ });
2421
+ }
2422
+ ret.push({
2423
+ gqlArg: arg,
2424
+ prop,
2425
+ imports
2426
+ });
2427
+ });
2428
+ return ret;
2429
+ }
2430
+ function getArgsIncludingInputArgSubfields(gqlOperation, gqlIntrospection) {
2431
+ const nativeScalars = [
2432
+ "ID",
2433
+ "String",
2434
+ "Boolean",
2435
+ "Int",
2436
+ "Float",
2437
+ "DateTime",
2438
+ "JSONObject"
2439
+ ];
2440
+ function reducer(acc, inputField) {
2441
+ if (inputField.type.kind !== "NON_NULL" || inputField.defaultValue) return acc;
2442
+ const gqlType = inputField.type.ofType;
2443
+ if (gqlType.kind === "INPUT_OBJECT") if (inputField.name === "input") {
2444
+ const typeDef = gqlIntrospection.__schema.types.find((type) => type.kind === "INPUT_OBJECT" && type.name === gqlType.name);
2445
+ if (typeDef && typeDef.kind === "INPUT_OBJECT") {
2446
+ const inputArgSubfields = typeDef.inputFields.reduce(reducer, []).map((inputArgSubfield) => {
2447
+ return {
2448
+ ...inputArgSubfield,
2449
+ isInputArgSubfield: true
2450
+ };
2451
+ });
2452
+ acc.push(...inputArgSubfields);
2453
+ } else console.warn(`IntrospectionType for ${gqlType.name} not found or no INPUT_OBJECT`);
2454
+ } else acc.push({
2455
+ name: inputField.name,
2456
+ type: gqlType.name,
2457
+ isInputArgSubfield: false
2458
+ });
2459
+ else if (gqlType.kind === "SCALAR") if (!nativeScalars.includes(gqlType.name)) console.warn(`Currently not supported special SCALAR of type ${gqlType.name} in arg/field ${inputField.name}`);
2460
+ else acc.push({
2461
+ name: inputField.name,
2462
+ type: gqlType.name,
2463
+ isInputArgSubfield: false
2464
+ });
2465
+ else if (gqlType.kind === "ENUM") acc.push({
2466
+ name: inputField.name,
2467
+ type: gqlType.name,
2468
+ isInputArgSubfield: false
2469
+ });
2470
+ else if (gqlType.kind === "LIST") throw new Error(`Not supported kind ${gqlType.kind}, arg: input.${inputField.name}`);
2471
+ return acc;
2472
+ }
2473
+ return gqlOperation.args.reduce(reducer, []);
2474
+ }
2475
+
2476
+ //#endregion
2477
+ //#region src/commands/generate/generateForm/generateForm.ts
2478
+ /**
2479
+ * Detects if a mutation has a wrapped payload response type (e.g., CreateProductPayload with product and errors fields)
2480
+ * vs returning the entity directly.
2481
+ */
2482
+ function hasPayloadResponseType(mutationField, gqlType) {
2483
+ let returnType = mutationField.type;
2484
+ if (returnType.kind === "NON_NULL") returnType = returnType.ofType;
2485
+ if (returnType.kind === "OBJECT" && returnType.name === gqlType) return false;
2486
+ else return true;
2487
+ }
2488
+ function generateFormPropsCode(props) {
2489
+ if (!props.length) return {
2490
+ formPropsTypeCode: "",
2491
+ formPropsParamsCode: ""
2492
+ };
2493
+ const uniqueProps = props.reduce((acc, item) => {
2494
+ const propWithSameName = acc.find((prop) => prop.name == item.name);
2495
+ if (!propWithSameName) return [item, ...acc];
2496
+ if (propWithSameName.type != item.type || propWithSameName.optional != item.optional) return [item, ...acc];
2497
+ return acc;
2498
+ }, []);
2499
+ return {
2500
+ formPropsTypeCode: `interface FormProps {
2501
+ ${uniqueProps.map((prop) => `${prop.name}${prop.optional ? `?` : ``}: ${prop.type};`).join("\n")}
2502
+ }`,
2503
+ formPropsParamsCode: `{${uniqueProps.map((prop) => prop.name + (prop.localAliasName ? `: ${prop.localAliasName}` : "")).join(", ")}}: FormProps`
2504
+ };
2505
+ }
2506
+ function generateForm({ exportName, baseOutputFilename, targetDirectory, gqlIntrospection }, config) {
2507
+ assertValidConfig(config);
2508
+ const gqlType = config.gqlType;
2509
+ const instanceGqlType = gqlType[0].toLowerCase() + gqlType.substring(1);
2510
+ const formFragmentName = config.fragmentName ?? `${gqlType}Form`;
2511
+ const gqlDocuments = {};
2512
+ const imports = [
2513
+ {
2514
+ name: "FormattedMessage",
2515
+ importPath: "react-intl"
2516
+ },
2517
+ {
2518
+ name: "useApolloClient",
2519
+ importPath: "@apollo/client"
2520
+ },
2521
+ {
2522
+ name: "useQuery",
2523
+ importPath: "@apollo/client"
2524
+ },
2525
+ {
2526
+ name: "gql",
2527
+ importPath: "@apollo/client"
2528
+ },
2529
+ {
2530
+ name: "CheckboxField",
2531
+ importPath: "@comet/admin"
2532
+ },
2533
+ {
2534
+ name: "Field",
2535
+ importPath: "@comet/admin"
2536
+ },
2537
+ {
2538
+ name: "filterByFragment",
2539
+ importPath: "@comet/admin"
2540
+ },
2541
+ {
2542
+ name: "FinalForm",
2543
+ importPath: "@comet/admin"
2544
+ },
2545
+ {
2546
+ name: "FinalFormInput",
2547
+ importPath: "@comet/admin"
2548
+ },
2549
+ {
2550
+ name: "FinalFormRangeInput",
2551
+ importPath: "@comet/admin"
2552
+ },
2553
+ {
2554
+ name: "FinalFormSelect",
2555
+ importPath: "@comet/admin"
2556
+ },
2557
+ {
2558
+ name: "FinalFormSubmitEvent",
2559
+ importPath: "@comet/admin"
2560
+ },
2561
+ {
2562
+ name: "Loading",
2563
+ importPath: "@comet/admin"
2564
+ },
2565
+ {
2566
+ name: "NumberField",
2567
+ importPath: "@comet/admin"
2568
+ },
2569
+ {
2570
+ name: "RadioGroupField",
2571
+ importPath: "@comet/admin"
2572
+ },
2573
+ {
2574
+ name: "TextAreaField",
2575
+ importPath: "@comet/admin"
2576
+ },
2577
+ {
2578
+ name: "TextField",
2579
+ importPath: "@comet/admin"
2580
+ },
2581
+ {
2582
+ name: "useFormApiRef",
2583
+ importPath: "@comet/admin"
2584
+ },
2585
+ {
2586
+ name: "useStackSwitchApi",
2587
+ importPath: "@comet/admin"
2588
+ },
2589
+ {
2590
+ name: "ArrowLeft",
2591
+ importPath: "@comet/admin-icons"
2592
+ },
2593
+ {
2594
+ name: "Lock",
2595
+ importPath: "@comet/admin-icons"
2596
+ },
2597
+ {
2598
+ name: "DateTimeField",
2599
+ importPath: "@comet/admin-date-time"
2600
+ },
2601
+ {
2602
+ name: "FinalFormDatePicker",
2603
+ importPath: "@comet/admin-date-time"
2604
+ },
2605
+ {
2606
+ name: "BlockState",
2607
+ importPath: "@comet/cms-admin"
2608
+ },
2609
+ {
2610
+ name: "createFinalFormBlock",
2611
+ importPath: "@comet/cms-admin"
2612
+ },
2613
+ {
2614
+ name: "queryUpdatedAt",
2615
+ importPath: "@comet/cms-admin"
2616
+ },
2617
+ {
2618
+ name: "resolveHasSaveConflict",
2619
+ importPath: "@comet/cms-admin"
2620
+ },
2621
+ {
2622
+ name: "useFormSaveConflict",
2623
+ importPath: "@comet/cms-admin"
2624
+ },
2625
+ {
2626
+ name: "FileUploadField",
2627
+ importPath: "@comet/cms-admin"
2628
+ },
2629
+ {
2630
+ name: "IconButton",
2631
+ importPath: "@mui/material"
2632
+ },
2633
+ {
2634
+ name: "MenuItem",
2635
+ importPath: "@mui/material"
2636
+ },
2637
+ {
2638
+ name: "InputAdornment",
2639
+ importPath: "@mui/material"
2640
+ },
2641
+ {
2642
+ name: "FormApi",
2643
+ importPath: "final-form"
2644
+ },
2645
+ {
2646
+ name: "useMemo",
2647
+ importPath: "react"
2648
+ }
2649
+ ];
2650
+ const formProps = [];
2651
+ const mode = config.mode ?? "all";
2652
+ const editMode = mode === "edit" || mode == "all";
2653
+ const addMode = mode === "add" || mode == "all";
2654
+ const createMutationType = addMode && findMutationTypeOrThrow(config.createMutation ?? `create${gqlType}`, gqlIntrospection);
2655
+ const updateMutationType = editMode && findMutationTypeOrThrow(`update${gqlType}`, gqlIntrospection);
2656
+ const createMutationHasPayloadResponse = createMutationType && hasPayloadResponseType(createMutationType, gqlType);
2657
+ const updateMutationHasPayloadResponse = updateMutationType && hasPayloadResponseType(updateMutationType, gqlType);
2658
+ const errorEnums = extractErrorEnumsFromMutations({
2659
+ createMutationType: createMutationHasPayloadResponse ? createMutationType : null,
2660
+ updateMutationType: updateMutationHasPayloadResponse ? updateMutationType : null,
2661
+ gqlIntrospection
2662
+ });
2663
+ if (errorEnums.createErrorEnum || errorEnums.updateErrorEnum) {
2664
+ imports.push({
2665
+ name: "ReactNode",
2666
+ importPath: "react"
2667
+ });
2668
+ imports.push({
2669
+ name: "FORM_ERROR",
2670
+ importPath: "final-form"
2671
+ });
2672
+ imports.push({
2673
+ name: "FormattedMessage",
2674
+ importPath: "react-intl"
2675
+ });
2676
+ }
2677
+ const formFields = flatFormFieldsFromFormConfig(config);
2678
+ let useScopeFromContext = false;
2679
+ const gqlArgs = [];
2680
+ if (createMutationType) {
2681
+ const forwardedArgs = getForwardedGqlArgs$1({
2682
+ fields: formFields,
2683
+ gqlOperation: createMutationType,
2684
+ gqlIntrospection
2685
+ });
2686
+ for (const forwardedArg of forwardedArgs) {
2687
+ imports.push(...forwardedArg.imports);
2688
+ if (forwardedArg.gqlArg.name === "scope" && !forwardedArg.gqlArg.isInputArgSubfield && !config.scopeAsProp) {
2689
+ useScopeFromContext = true;
2690
+ gqlArgs.push(forwardedArg.gqlArg);
2691
+ } else {
2692
+ formProps.push(forwardedArg.prop);
2693
+ gqlArgs.push(forwardedArg.gqlArg);
2694
+ }
2695
+ }
2696
+ }
2697
+ if (useScopeFromContext) imports.push({
2698
+ name: "useContentScope",
2699
+ importPath: "@comet/cms-admin"
2700
+ });
2701
+ if (editMode) {
2702
+ if (mode === "all") formProps.push({
2703
+ name: "id",
2704
+ optional: true,
2705
+ type: "string"
2706
+ });
2707
+ else if (mode === "edit") formProps.push({
2708
+ name: "id",
2709
+ optional: false,
2710
+ type: "string"
2711
+ });
2712
+ }
2713
+ const rootBlockFields = formFields.filter((field) => field.type == "block").map((field) => {
2714
+ if (field.type !== "block") throw new Error("Field is not a block field");
2715
+ return field;
2716
+ });
2717
+ rootBlockFields.forEach((field) => {
2718
+ if (isGeneratorConfigImport(field.block)) imports.push(convertConfigImport(field.block));
2719
+ });
2720
+ const readOnlyFields = formFields.filter((field) => field.readOnly);
2721
+ const fileFields = formFields.filter((field) => field.type == "fileUpload");
2722
+ if (fileFields.length > 0) {
2723
+ imports.push({
2724
+ name: "GQLFinalFormFileUploadFragment",
2725
+ importPath: "@comet/cms-admin"
2726
+ });
2727
+ imports.push({
2728
+ name: "GQLFinalFormFileUploadDownloadableFragment",
2729
+ importPath: "@comet/cms-admin"
2730
+ });
2731
+ }
2732
+ let hooksCode = "";
2733
+ const formFragmentFields = [];
2734
+ const formValuesConfig = [];
2735
+ const generatedFields = generateFields({
2736
+ gqlIntrospection,
2737
+ baseOutputFilename,
2738
+ fields: config.fields,
2739
+ formFragmentName,
2740
+ formConfig: config,
2741
+ gqlType: config.gqlType
2742
+ });
2743
+ const fieldsCode = generatedFields.code;
2744
+ for (const name in generatedFields.gqlDocuments) gqlDocuments[name] = {
2745
+ document: generatedFields.gqlDocuments[name].document,
2746
+ export: true
2747
+ };
2748
+ imports.push(...generatedFields.imports);
2749
+ formProps.push(...generatedFields.formProps);
2750
+ hooksCode += generatedFields.hooksCode;
2751
+ formFragmentFields.push(...generatedFields.formFragmentFields);
2752
+ formValuesConfig.push(...generatedFields.formValuesConfig);
2753
+ formProps.push({
2754
+ name: "onCreate",
2755
+ optional: true,
2756
+ type: `(id: string) => void`
2757
+ });
2758
+ if (config.initialValuesAsProp) formProps.push({
2759
+ name: "initialValues",
2760
+ localAliasName: "passedInitialValues",
2761
+ optional: true,
2762
+ type: `Partial<FormValues>`
2763
+ });
2764
+ const { formPropsTypeCode, formPropsParamsCode } = generateFormPropsCode(formProps);
2765
+ gqlDocuments[`${instanceGqlType}FormFragment`] = {
2766
+ document: generateFragmentByFormFragmentFields({
2767
+ formFragmentName,
2768
+ gqlType,
2769
+ formFragmentFields
2770
+ }),
2771
+ export: editMode
2772
+ };
2773
+ if (editMode) gqlDocuments[`${instanceGqlType}Query`] = {
2774
+ document: generateGqlOperation({
2775
+ type: "query",
2776
+ operationName: gqlType,
2777
+ rootOperation: instanceGqlType,
2778
+ fields: [
2779
+ "id",
2780
+ "updatedAt",
2781
+ `...${formFragmentName}`
2782
+ ],
2783
+ variables: [{
2784
+ name: "id",
2785
+ type: "ID!"
2786
+ }],
2787
+ fragmentVariables: [`\${${`${instanceGqlType}FormFragment`}}`]
2788
+ }),
2789
+ export: true
2790
+ };
2791
+ if (addMode && createMutationType) gqlDocuments[`create${gqlType}Mutation`] = {
2792
+ document: generateGqlOperation({
2793
+ type: "mutation",
2794
+ operationName: `Create${gqlType}`,
2795
+ rootOperation: createMutationType.name,
2796
+ fields: createMutationHasPayloadResponse ? [
2797
+ `${instanceGqlType}.id`,
2798
+ `${instanceGqlType}.updatedAt`,
2799
+ `${instanceGqlType}...${formFragmentName}`,
2800
+ "errors.code",
2801
+ "errors.field"
2802
+ ] : [
2803
+ "id",
2804
+ "updatedAt",
2805
+ `...${formFragmentName}`
2806
+ ],
2807
+ fragmentVariables: [`\${${`${instanceGqlType}FormFragment`}}`],
2808
+ variables: [...gqlArgs.filter((gqlArg) => !gqlArg.isInputArgSubfield).map((gqlArg) => ({
2809
+ name: gqlArg.name,
2810
+ type: `${gqlArg.type}!`
2811
+ })), {
2812
+ name: "input",
2813
+ type: `${gqlType}Input!`
2814
+ }]
2815
+ }),
2816
+ export: true
2817
+ };
2818
+ if (editMode) gqlDocuments[`update${gqlType}Mutation`] = {
2819
+ document: generateGqlOperation({
2820
+ type: "mutation",
2821
+ operationName: `Update${gqlType}`,
2822
+ rootOperation: `update${gqlType}`,
2823
+ fields: updateMutationHasPayloadResponse ? [
2824
+ `${instanceGqlType}.id`,
2825
+ `${instanceGqlType}.updatedAt`,
2826
+ `${instanceGqlType}...${formFragmentName}`,
2827
+ "errors.code",
2828
+ "errors.field"
2829
+ ] : [
2830
+ "id",
2831
+ "updatedAt",
2832
+ `...${formFragmentName}`
2833
+ ],
2834
+ fragmentVariables: [`\${${`${instanceGqlType}FormFragment`}}`],
2835
+ variables: [{
2836
+ name: "id",
2837
+ type: "ID!"
2838
+ }, {
2839
+ name: "input",
2840
+ type: `${gqlType}UpdateInput!`
2841
+ }]
2842
+ }),
2843
+ export: true
2844
+ };
2845
+ for (const name in gqlDocuments) {
2846
+ const gqlDocument = gqlDocuments[name];
2847
+ imports.push({
2848
+ name,
2849
+ importPath: `./${baseOutputFilename}.gql`
2850
+ });
2851
+ const match = gqlDocument.document.match(/^\s*(query|mutation|fragment)\s+(\w+)/);
2852
+ if (!match) throw new Error(`Could not find query or mutation name in ${gqlDocument}`);
2853
+ const type = match[1];
2854
+ const documentName = match[2];
2855
+ imports.push({
2856
+ name: `GQL${documentName}${type[0].toUpperCase() + type.substring(1)}`,
2857
+ importPath: `./${baseOutputFilename}.gql.generated`
2858
+ });
2859
+ if (type !== "fragment") imports.push({
2860
+ name: `GQL${documentName}${type[0].toUpperCase() + type.substring(1)}Variables`,
2861
+ importPath: `./${baseOutputFilename}.gql.generated`
2862
+ });
2863
+ }
2864
+ const finalFormSubscription = Object.keys(generatedFields.finalFormConfig?.subscription ?? {});
2865
+ const finalFormRenderProps = Object.keys(generatedFields.finalFormConfig?.renderProps ?? {});
2866
+ let filterByFragmentType = `GQL${formFragmentName}Fragment`;
2867
+ let customFilterByFragment = "";
2868
+ if (fileFields.length > 0) {
2869
+ const keysToOverride = fileFields.map((field) => field.name);
2870
+ customFilterByFragment = `type ${formFragmentName}Fragment = Omit<${filterByFragmentType}, ${keysToOverride.map((key) => `"${String(key)}"`).join(" | ")}> & {
2871
+ ${fileFields.map((field) => {
2872
+ if (field.type !== "fileUpload") throw new Error("Field is not a file upload field");
2873
+ if ("multiple" in field && field.multiple || "maxFiles" in field && typeof field.maxFiles === "number" && field.maxFiles > 1) return `${String(field.name)}: ${field.download ? "GQLFinalFormFileUploadDownloadableFragment" : "GQLFinalFormFileUploadFragment"}[];`;
2874
+ return `${String(field.name)}: ${field.download ? "GQLFinalFormFileUploadDownloadableFragment" : "GQLFinalFormFileUploadFragment"} | null;`;
2875
+ }).join("\n")}
2876
+ }`;
2877
+ filterByFragmentType = `${formFragmentName}Fragment`;
2878
+ }
2879
+ if (errorEnums.createErrorEnum) {
2880
+ const typeName = `GQL${errorEnums.createErrorEnum}`;
2881
+ imports.push({
2882
+ name: typeName,
2883
+ importPath: `@src/graphql.generated`
2884
+ });
2885
+ }
2886
+ if (errorEnums.useDifferentEnums && errorEnums.updateErrorEnum) {
2887
+ const typeName = `GQL${errorEnums.updateErrorEnum}`;
2888
+ imports.push({
2889
+ name: typeName,
2890
+ importPath: `@src/graphql.generated`
2891
+ });
2892
+ }
2893
+ let errorMessagesCode = "";
2894
+ if (errorEnums.useDifferentEnums) {
2895
+ if (errorEnums.createErrorEnum) {
2896
+ errorMessagesCode += generateErrorMessagesCode({
2897
+ enumName: errorEnums.createErrorEnum,
2898
+ gqlType,
2899
+ variableName: "createErrorMessages",
2900
+ gqlIntrospection
2901
+ });
2902
+ errorMessagesCode += "\n\n";
2903
+ }
2904
+ if (errorEnums.updateErrorEnum) errorMessagesCode += generateErrorMessagesCode({
2905
+ enumName: errorEnums.updateErrorEnum,
2906
+ gqlType,
2907
+ variableName: "updateErrorMessages",
2908
+ gqlIntrospection
2909
+ });
2910
+ } else if (errorEnums.createErrorEnum || errorEnums.updateErrorEnum) errorMessagesCode = generateErrorMessagesCode({
2911
+ enumName: errorEnums.createErrorEnum || errorEnums.updateErrorEnum,
2912
+ gqlType,
2913
+ variableName: "submissionErrorMessages",
2914
+ gqlIntrospection
2915
+ });
2916
+ return {
2917
+ code: `
2918
+ ${generateImportsCode(imports)}
2919
+ import isEqual from "lodash.isequal";
2920
+
2921
+ ${rootBlockFields.length > 0 ? `const rootBlocks = {
2922
+ ${rootBlockFields.map((field) => `${String(field.name)}: ${field.block.name}`)}
2923
+ };` : ""}
2924
+
2925
+ ${customFilterByFragment}
2926
+
2927
+ ${generateFormValuesType({
2928
+ formValuesConfig,
2929
+ filterByFragmentType,
2930
+ gqlIntrospection,
2931
+ gqlType
2932
+ })}
2933
+
2934
+ ${formPropsTypeCode}
2935
+
2936
+ ${errorMessagesCode}
2937
+
2938
+ export function ${exportName}(${formPropsParamsCode}) {
2939
+ const client = useApolloClient();
2940
+ ${mode == "all" ? `const mode = id ? "edit" : "add";` : ""}
2941
+ const formApiRef = useFormApiRef<FormValues>();
2942
+ ${addMode ? `const stackSwitchApi = useStackSwitchApi();` : ""}
2943
+ ${useScopeFromContext ? `const { scope } = useContentScope();` : ""}
2944
+
2945
+ ${editMode ? `
2946
+ const { data, error, loading, refetch } = useQuery<GQL${gqlType}Query, GQL${gqlType}QueryVariables>(
2947
+ ${instanceGqlType}Query,
2948
+ ${mode == "edit" ? `{ variables: { id } }` : `id ? { variables: { id } } : { skip: true }`},
2949
+ );
2950
+ ` : ""}
2951
+
2952
+ ${generateInitialValues({
2953
+ mode,
2954
+ formValuesConfig,
2955
+ filterByFragmentType,
2956
+ gqlIntrospection,
2957
+ gqlType,
2958
+ initialValuesAsProp: !!config.initialValuesAsProp
2959
+ })}
2960
+
2961
+
2962
+ ${editMode ? `
2963
+ const saveConflict = useFormSaveConflict({
2964
+ checkConflict: async () => {
2965
+ const updatedAt = await queryUpdatedAt(client, "${instanceGqlType}", id);
2966
+ return resolveHasSaveConflict(data?.${instanceGqlType}.updatedAt, updatedAt);
2967
+ },
2968
+ formApiRef,
2969
+ loadLatestVersion: async () => {
2970
+ await refetch();
2971
+ },
2972
+ });
2973
+ ` : ""}
2974
+
2975
+ const handleSubmit = async (${generateDestructFormValueForInput({
2976
+ formValuesConfig,
2977
+ gqlIntrospection,
2978
+ gqlType
2979
+ })}: FormValues, form: FormApi<FormValues>${addMode ? `, event: FinalFormSubmitEvent` : ""}) => {
2980
+ ${editMode ? `if (await saveConflict.checkForConflicts()) throw new Error("Conflicts detected");` : ""}
2981
+ ${generateFormValuesToGqlInput({
2982
+ formValuesConfig,
2983
+ gqlIntrospection,
2984
+ gqlType
2985
+ })}
2986
+
2987
+ ${mode == "all" ? `if (mode === "edit") {` : ""}
2988
+ ${editMode ? `
2989
+ ${readOnlyFields.some((field) => field.name === "id") ? "" : "if (!id) throw new Error();"}
2990
+ const { ${readOnlyFields.map((field) => `${String(field.name)},`).join("")} ...updateInput } = output;
2991
+ ${updateMutationHasPayloadResponse ? `const { data: mutationResponse } = ` : ""}await client.mutate<GQLUpdate${gqlType}Mutation, GQLUpdate${gqlType}MutationVariables>({
2992
+ mutation: update${gqlType}Mutation,
2993
+ variables: { id, input: updateInput },
2994
+ });
2995
+ ${updateMutationHasPayloadResponse && updateMutationType && errorEnums.updateErrorEnum ? `
2996
+ ${generateErrorHandlingCode({
2997
+ mutationResponsePath: `mutationResponse?.${updateMutationType.name}`,
2998
+ errorMessagesVariable: errorEnums.useDifferentEnums ? "updateErrorMessages" : "submissionErrorMessages"
2999
+ })}
3000
+ ` : ""}
3001
+ ` : ""}
3002
+ ${mode == "all" ? `} else {` : ""}
3003
+ ${addMode && createMutationType ? `
3004
+ const { data: mutationResponse } = await client.mutate<GQLCreate${gqlType}Mutation, GQLCreate${gqlType}MutationVariables>({
3005
+ mutation: create${gqlType}Mutation,
3006
+ variables: {
3007
+ input: ${gqlArgs.filter((prop) => prop.isInputArgSubfield).length ? `{ ...output, ${gqlArgs.filter((prop) => prop.isInputArgSubfield).map((prop) => prop.name).join(",")} }` : "output"}${gqlArgs.filter((prop) => !prop.isInputArgSubfield).length ? `, ${gqlArgs.filter((prop) => !prop.isInputArgSubfield).map((arg) => arg.name).join(",")}` : ""} },
3008
+ });
3009
+ ${createMutationHasPayloadResponse && errorEnums.createErrorEnum ? `
3010
+ ${generateErrorHandlingCode({
3011
+ mutationResponsePath: `mutationResponse?.${createMutationType.name}`,
3012
+ errorMessagesVariable: errorEnums.useDifferentEnums ? "createErrorMessages" : "submissionErrorMessages"
3013
+ })}
3014
+ ` : ""}
3015
+
3016
+ const id = mutationResponse?.${createMutationType.name}${createMutationHasPayloadResponse ? `.${instanceGqlType}?` : ""}.id;
3017
+ if (id) {
3018
+ setTimeout(() => {
3019
+ onCreate?.(id);
3020
+ ${config.navigateOnCreate === true || config.navigateOnCreate === void 0 ? `if (!event.navigatingBack) { stackSwitchApi.activatePage(\`edit\`, id);` : ``}
3021
+ });
3022
+ }
3023
+ ` : ""}
3024
+ ${mode == "all" ? `}` : ""}
3025
+ };
3026
+
3027
+ ${hooksCode}
3028
+
3029
+ ${editMode ? ` if (error) throw error;
3030
+
3031
+ if (loading) {
3032
+ return <Loading behavior="fillPageHeight" />;
3033
+ }` : ``}
3034
+
3035
+ return (
3036
+ <FinalForm<FormValues>
3037
+ apiRef={formApiRef}
3038
+ onSubmit={handleSubmit}
3039
+ mode=${mode == "all" ? `{mode}` : editMode ? `"edit"` : `"add"`}
3040
+ initialValues={initialValues}
3041
+ initialValuesEqual={isEqual} //required to compare block data correctly
3042
+ subscription={{ ${finalFormSubscription.length ? finalFormSubscription.map((field) => `${field}: true`).join(", ") : ``} }}
3043
+ >
3044
+ {(${finalFormRenderProps.length ? `{${finalFormRenderProps.join(", ")}}` : ``}) => (
3045
+ ${editMode ? `<>` : ``}
3046
+ ${editMode ? `{saveConflict.dialogs}` : ``}
3047
+ <>
3048
+ ${fieldsCode}
3049
+ </>
3050
+ ${editMode ? `</>` : ``}
3051
+ )}
3052
+ </FinalForm>
3053
+ );
3054
+ }
3055
+
3056
+ `,
3057
+ gqlDocuments
3058
+ };
3059
+ }
3060
+ /**
3061
+ * Checks if the provided form config is valid.
3062
+ *
3063
+ * Examples of invalid configs:
3064
+ * - The "id" field is not read-only
3065
+ *
3066
+ * @param config The form config to check.
3067
+ * @throws Will throw an error if the provided config is invalid.
3068
+ */
3069
+ function assertValidConfig(config) {
3070
+ function validateFields(fields) {
3071
+ for (const field of fields) if (isFormFieldConfig(field)) {
3072
+ if (field.name === "id" && !field.readOnly) throw new Error(`Invalid form config: the "id" field must be read-only`);
3073
+ } else if (isFormLayoutConfig(field)) validateFields(field.fields);
3074
+ }
3075
+ validateFields(config.fields);
3076
+ }
3077
+
3078
+ //#endregion
3079
+ //#region src/commands/generate/utils/findRootBlocks.ts
3080
+ const fallbackLibraryBlocks = {
3081
+ AnchorBlock: "@comet/cms-admin",
3082
+ DamImageBlock: "@comet/cms-admin",
3083
+ DamVideoBlock: "@comet/cms-admin",
3084
+ ExternalLinkBlock: "@comet/cms-admin",
3085
+ InternalLinkBlock: "@comet/cms-admin",
3086
+ PixelImageBlock: "@comet/cms-admin",
3087
+ SpaceBlock: "@comet/cms-admin",
3088
+ SvgImageBlock: "@comet/cms-admin",
3089
+ YouTubeVideoBlock: "@comet/cms-admin"
3090
+ };
3091
+ function findRootBlocks({ gqlType, targetDirectory }, schema) {
3092
+ const ret = {};
3093
+ const schemaEntity = schema.__schema.types.find((type) => type.kind === "OBJECT" && type.name === gqlType);
3094
+ if (!schemaEntity) throw new Error("didn't find entity in schema types");
3095
+ schemaEntity.fields.forEach((field) => {
3096
+ if (ret[field.name]) return;
3097
+ let type = field.type;
3098
+ if (type.kind == "NON_NULL") type = type.ofType;
3099
+ if (type.kind == "SCALAR" && type.name.endsWith("BlockData")) {
3100
+ let match = false;
3101
+ const blockName = `${type.name.replace(/BlockData$/, "")}Block`;
3102
+ const checkNames = [{
3103
+ folderName: `${targetDirectory.replace(/\/generated$/, "")}/blocks`,
3104
+ import: `../blocks/${blockName}`
3105
+ }, {
3106
+ folderName: `src/common/blocks`,
3107
+ import: `@src/common/blocks/${blockName}`
3108
+ }];
3109
+ for (const checkName of checkNames) if (existsSync(`${checkName.folderName}/${blockName}.tsx`)) {
3110
+ match = true;
3111
+ ret[field.name] = {
3112
+ import: checkName.import,
3113
+ name: blockName
3114
+ };
3115
+ break;
3116
+ }
3117
+ if (!match) {
3118
+ const fallback = fallbackLibraryBlocks[blockName];
3119
+ if (fallback) {
3120
+ ret[field.name] = {
3121
+ import: fallback,
3122
+ name: blockName
3123
+ };
3124
+ match = true;
3125
+ }
3126
+ }
3127
+ if (!match) throw new Error(`Didn't find admin block for ${blockName} in ${checkNames.map((c) => c.folderName).join(" or ")}`);
3128
+ }
3129
+ });
3130
+ return ret;
3131
+ }
3132
+
3133
+ //#endregion
3134
+ //#region src/commands/generate/generateGrid/detectMuiXVersion.ts
3135
+ function detectMuiXGridVariant() {
3136
+ const packageJson = JSON.parse(fs.readFileSync("package.json", "utf-8"));
3137
+ const packages = Object.keys(packageJson.dependencies);
3138
+ if (packages.includes("@mui/x-data-grid-premium")) return {
3139
+ variant: "premium",
3140
+ package: "@mui/x-data-grid-premium",
3141
+ gridComponent: "DataGridPremium"
3142
+ };
3143
+ else if (packages.includes("@mui/x-data-grid-pro")) return {
3144
+ variant: "pro",
3145
+ package: "@mui/x-data-grid-pro",
3146
+ gridComponent: "DataGridPro"
3147
+ };
3148
+ else return {
3149
+ variant: "community",
3150
+ package: "@mui/x-data-grid",
3151
+ gridComponent: "DataGrid"
3152
+ };
3153
+ }
3154
+
3155
+ //#endregion
3156
+ //#region src/commands/generate/generateGrid/findInputObjectType.ts
3157
+ function findInputObjectType(input, schema) {
3158
+ let type = input.type;
3159
+ if (type.kind == "NON_NULL") type = type.ofType;
3160
+ if (type.kind !== "INPUT_OBJECT") throw new Error("must be INPUT_OBJECT");
3161
+ const typeName = type.name;
3162
+ return schema.__schema.types.find((type$1) => type$1.kind === "INPUT_OBJECT" && type$1.name === typeName);
3163
+ }
3164
+
3165
+ //#endregion
3166
+ //#region src/commands/generate/generateGrid/generateGqlFieldList.ts
3167
+ const recursiveStringify = (obj) => {
3168
+ let ret = "";
3169
+ let prefixField = "";
3170
+ for (const key in obj) {
3171
+ const valueForKey = obj[key];
3172
+ if (typeof valueForKey === "boolean") ret += `${prefixField}${key}`;
3173
+ else if (typeof valueForKey === "string") ret += `${prefixField}${key}${valueForKey}`;
3174
+ else ret += `${prefixField}${key} { ${recursiveStringify(valueForKey)} }`;
3175
+ prefixField = " ";
3176
+ }
3177
+ return ret;
3178
+ };
3179
+ function generateGqlFieldList({ columns }) {
3180
+ return recursiveStringify(columns.reduce((acc, field) => {
3181
+ if (field.type === "actions") field.queryFields?.forEach((queryField) => {
3182
+ objectPath.set(acc, queryField, true);
3183
+ });
3184
+ else if (field.name === "id") {} else {
3185
+ let hasCustomFields = false;
3186
+ if ("labelField" in field && field.labelField) {
3187
+ objectPath.set(acc, `${field.name}.${field.labelField}`, true);
3188
+ hasCustomFields = true;
3189
+ }
3190
+ if ("queryFields" in field) {
3191
+ field.queryFields?.forEach((queryField) => {
3192
+ objectPath.set(acc, queryField, true);
3193
+ });
3194
+ hasCustomFields = true;
3195
+ }
3196
+ if (!hasCustomFields) objectPath.set(acc, field.name, true);
3197
+ }
3198
+ return acc;
3199
+ }, {}));
3200
+ }
3201
+
3202
+ //#endregion
3203
+ //#region src/commands/generate/generateGrid/generateGridToolbar.ts
3204
+ const generateGridToolbar = ({ componentName, forwardToolbarAction, hasSearch, hasFilter, excelExport, allowAdding, instanceGqlType, gqlType, newEntryText, fragmentName }) => {
3205
+ return `${renderToolbarProps(componentName, !!forwardToolbarAction, !!excelExport)}
3206
+ function ${componentName}(${getGridToolbarProps(componentName, !!forwardToolbarAction, !!excelExport)}) {
3207
+ return (
3208
+ <DataGridToolbar>
3209
+ ${hasSearch ? "<GridToolbarQuickFilter />" : ""}
3210
+ ${hasFilter ? "<GridFilterButton />" : ""}
3211
+ <FillSpace />
3212
+ ${renderToolbarActions({
3213
+ forwardToolbarAction,
3214
+ addItemText: generateFormattedMessage({
3215
+ config: newEntryText,
3216
+ id: `${instanceGqlType}.${camelCase(fragmentName)}.newEntry`,
3217
+ defaultMessage: `New ${camelCaseToHumanReadable(gqlType)}`,
3218
+ type: "jsx"
3219
+ }),
3220
+ excelExport,
3221
+ allowAdding
3222
+ })}
3223
+ </DataGridToolbar>
3224
+ );
3225
+ }`.replace(/^\s+\n/gm, "");
3226
+ };
3227
+ const getGridToolbarProps = (componentName, toolbarAction, exportApi) => {
3228
+ const props = [];
3229
+ if (toolbarAction) props.push({
3230
+ destructured: "toolbarAction",
3231
+ typeDefinition: "toolbarAction?: ReactNode"
3232
+ });
3233
+ if (exportApi) props.push({
3234
+ destructured: "exportApi",
3235
+ typeDefinition: "exportApi: ExportApi"
3236
+ });
3237
+ if (!props.length) return "";
3238
+ return `{
3239
+ ${props.map((prop) => `${prop.destructured}`).join(",")}
3240
+ }: ${componentName}ToolbarProps`;
3241
+ };
3242
+ const renderToolbarActions = ({ forwardToolbarAction, addItemText, excelExport, allowAdding }) => {
3243
+ const showMoreActionsMenu = excelExport;
3244
+ if (!showMoreActionsMenu && !allowAdding) return "";
3245
+ const moreActionsMenu = `<CrudMoreActionsMenu
3246
+ slotProps={{
3247
+ button: {
3248
+ responsive: true
3249
+ }
3250
+ }}
3251
+ overallActions={[
3252
+ ${excelExport ? `{
3253
+ label: <FormattedMessage {...messages.downloadAsExcel} />,
3254
+ icon: exportApi.loading ? <CircularProgress size={20} /> : <ExcelIcon />,
3255
+ onClick: () => exportApi.exportGrid(),
3256
+ disabled: exportApi.loading,
3257
+ }` : ""}
3258
+ ]}
3259
+ />`;
3260
+ const defaultAddItemButton = `<Button responsive startIcon={<AddIcon />} component={StackLink} pageName="add" payload="add">
3261
+ ${addItemText}
3262
+ </Button>`;
3263
+ return `
3264
+ ${showMoreActionsMenu ? moreActionsMenu : ""}
3265
+ ${allowAdding ? forwardToolbarAction ? "{toolbarAction}" : defaultAddItemButton : ""}`;
3266
+ };
3267
+ const renderToolbarProps = (componentName, forwardToolbarAction, exportApi) => {
3268
+ if (forwardToolbarAction || exportApi) return `interface ${componentName}ToolbarProps extends GridToolbarProps {
3269
+ ${forwardToolbarAction ? "toolbarAction: ReactNode;" : ""}
3270
+ ${exportApi ? "exportApi: ExportApi;" : ""}
3271
+ }`;
3272
+ return "";
3273
+ };
3274
+
3275
+ //#endregion
3276
+ //#region src/commands/generate/generateGrid/getForwardedGqlArgs.ts
3277
+ function getForwardedGqlArgs(gqlFields) {
3278
+ const ret = [];
3279
+ getArgs(gqlFields, [
3280
+ "offset",
3281
+ "limit",
3282
+ "sort",
3283
+ "search",
3284
+ "filter",
3285
+ "input"
3286
+ ]).forEach((arg) => {
3287
+ let prop;
3288
+ const imports = [];
3289
+ if (arg.type === "ID" || arg.type === "String" || arg.type === "DateTime") prop = {
3290
+ name: arg.name,
3291
+ optional: false,
3292
+ type: "string"
3293
+ };
3294
+ else if (arg.type === "Boolean") prop = {
3295
+ name: arg.name,
3296
+ optional: false,
3297
+ type: "boolean"
3298
+ };
3299
+ else if (arg.type === "Int" || arg.type === "Float") prop = {
3300
+ name: arg.name,
3301
+ optional: false,
3302
+ type: "number"
3303
+ };
3304
+ else if (arg.type === "JSONObject") prop = {
3305
+ name: arg.name,
3306
+ optional: false,
3307
+ type: "unknown"
3308
+ };
3309
+ else {
3310
+ prop = {
3311
+ name: arg.name,
3312
+ optional: false,
3313
+ type: `GQL${arg.type}`
3314
+ };
3315
+ imports.push({
3316
+ name: `GQL${arg.type}`,
3317
+ importPath: "@src/graphql.generated"
3318
+ });
3319
+ }
3320
+ ret.push({
3321
+ gqlArg: {
3322
+ name: arg.name,
3323
+ type: arg.type,
3324
+ queryOrMutationName: arg.gqlField.name
3325
+ },
3326
+ prop,
3327
+ imports
3328
+ });
3329
+ });
3330
+ return ret;
3331
+ }
3332
+ function getArgs(gqlFields, skipGqlArgs) {
3333
+ return gqlFields.reduce((acc, gqlField) => {
3334
+ gqlField.args.forEach((gqlArg) => {
3335
+ if (skipGqlArgs.includes(gqlArg.name)) return acc;
3336
+ if (gqlArg.type.kind !== "NON_NULL" || gqlArg.defaultValue) return acc;
3337
+ const gqlType = gqlArg.type.ofType;
3338
+ let type = "unknown";
3339
+ if (gqlType.kind === "SCALAR") if (![
3340
+ "ID",
3341
+ "String",
3342
+ "Boolean",
3343
+ "Int",
3344
+ "Float",
3345
+ "DateTime",
3346
+ "JSONObject"
3347
+ ].includes(gqlType.name)) console.warn(`Currently not supported special SCALAR of type ${gqlType.name} in param ${gqlArg.name} of ${gqlField.name}`);
3348
+ else type = gqlType.name;
3349
+ else if (gqlType.kind === "INPUT_OBJECT") type = gqlType.name;
3350
+ else throw new Error(`Not supported kind ${gqlType.kind}, arg: ${gqlArg.name}`);
3351
+ acc.push({
3352
+ name: gqlArg.name,
3353
+ type,
3354
+ gqlArg,
3355
+ gqlField
3356
+ });
3357
+ });
3358
+ return acc;
3359
+ }, []);
3360
+ }
3361
+
3362
+ //#endregion
3363
+ //#region src/commands/generate/generateGrid/getPropsForFilterProp.ts
3364
+ function getPropsForFilterProp({ config, filterType }) {
3365
+ if (!config.filterProp) return {
3366
+ hasFilterProp: false,
3367
+ imports: [],
3368
+ props: []
3369
+ };
3370
+ const filterTypeName = `GQL${filterType.name}`;
3371
+ return {
3372
+ hasFilterProp: true,
3373
+ imports: [{
3374
+ name: filterTypeName,
3375
+ importPath: "@src/graphql.generated"
3376
+ }],
3377
+ props: [{
3378
+ name: "filter",
3379
+ optional: true,
3380
+ type: filterTypeName
3381
+ }]
3382
+ };
3383
+ }
3384
+
3385
+ //#endregion
3386
+ //#region src/commands/generate/generateGrid/generateGrid.ts
3387
+ const { plural, singular } = pluralize;
3388
+ function tsCodeRecordToString(object, spreadAbove) {
3389
+ return `{${spreadAbove ? `${spreadAbove}` : ""}${Object.entries(object).filter(([key, value]) => value !== void 0).map(([key, value]) => `${key}: ${value},`).join("\n")}}`;
3390
+ }
3391
+ function generateGridPropsCode(props) {
3392
+ if (!props.length) return {
3393
+ gridPropsTypeCode: "",
3394
+ gridPropsParamsCode: ""
3395
+ };
3396
+ const uniqueProps = props.reduce((acc, prop) => {
3397
+ const propWithSameName = acc.find((filteredProps) => filteredProps.name === prop.name);
3398
+ if (propWithSameName) if (propWithSameName.type === prop.type) {} else throw new Error(`Prop ${prop.name} with same name but different types (${propWithSameName.type} and ${prop.type}) detected.`);
3399
+ else acc.push(prop);
3400
+ return acc;
3401
+ }, []);
3402
+ return {
3403
+ gridPropsTypeCode: `type Props = {
3404
+ ${uniqueProps.map((prop) => `${prop.type.includes("any") ? `// eslint-disable-next-line @typescript-eslint/no-explicit-any
3405
+ ` : ``}${prop.name}${prop.optional ? `?` : ``}: ${prop.type};`).join("\n")}
3406
+ };`,
3407
+ gridPropsParamsCode: `{${uniqueProps.map((prop) => `${prop.name} ${prop.defaultValue ? `= ${prop.defaultValue}` : ""}`).join(", ")}}: Props`
3408
+ };
3409
+ }
3410
+ const getSortByValue = (sortBy) => {
3411
+ if (Array.isArray(sortBy)) return `[${sortBy.map((i) => `"${i}"`).join(", ")}]`;
3412
+ if (typeof sortBy === "string") return `"${sortBy}"`;
3413
+ return sortBy;
3414
+ };
3415
+ const getValueOptionsLabelData = (messageId, label) => {
3416
+ if (typeof label === "string" || isFormattedMessageElement(label)) return { textLabel: generateFormattedMessage({
3417
+ config: label,
3418
+ id: messageId,
3419
+ type: "intlCall"
3420
+ }) };
3421
+ const textLabelParts = [];
3422
+ const gridCellContentProps = {};
3423
+ if ("primaryText" in label && label.primaryText) {
3424
+ const primaryMessageId = `${messageId}.primary`;
3425
+ textLabelParts.push(generateFormattedMessage({
3426
+ config: label.primaryText,
3427
+ id: primaryMessageId,
3428
+ type: "intlCall"
3429
+ }));
3430
+ gridCellContentProps.primaryText = generateFormattedMessage({
3431
+ config: label.primaryText,
3432
+ id: primaryMessageId,
3433
+ type: "jsx"
3434
+ });
3435
+ }
3436
+ if ("secondaryText" in label && label.secondaryText) {
3437
+ const secondaryMessageId = `${messageId}.secondary`;
3438
+ textLabelParts.push(generateFormattedMessage({
3439
+ config: label.secondaryText,
3440
+ id: secondaryMessageId,
3441
+ type: "intlCall"
3442
+ }));
3443
+ gridCellContentProps.secondaryText = generateFormattedMessage({
3444
+ config: label.secondaryText,
3445
+ id: secondaryMessageId,
3446
+ type: "jsx"
3447
+ });
3448
+ }
3449
+ if ("icon" in label) {
3450
+ if (typeof label.icon === "string") gridCellContentProps.icon = `<${label.icon}Icon />`;
3451
+ else if (typeof label.icon === "object") if ("import" in label.icon) gridCellContentProps.icon = `<${label.icon.name} />`;
3452
+ else {
3453
+ const { name, ...iconProps } = label.icon;
3454
+ gridCellContentProps.icon = `<${name}Icon
3455
+ ${Object.entries(iconProps).map(([key, value]) => `${key}="${value}"`).join("\n")}
3456
+ />`;
3457
+ }
3458
+ }
3459
+ const gridCellContent = `<GridCellContent
3460
+ ${Object.entries(gridCellContentProps).map(([key, value]) => `${key}={${value}}`).join("\n")}
3461
+ />`;
3462
+ return {
3463
+ textLabel: textLabelParts.join(" + ' ' + "),
3464
+ gridCellContent
3465
+ };
3466
+ };
3467
+ function queryHasPaging(gridQueryType, gqlIntrospection) {
3468
+ let returnType = gridQueryType.type;
3469
+ if (returnType.kind === "NON_NULL") returnType = returnType.ofType;
3470
+ if (returnType.kind === "LIST") return false;
3471
+ if (returnType.kind === "OBJECT") {
3472
+ const typeName = returnType.name;
3473
+ const objectType = gqlIntrospection.__schema.types.find((type) => type.kind === "OBJECT" && type.name === typeName);
3474
+ if (objectType) {
3475
+ const hasNodes = objectType.fields.some((f) => f.name === "nodes");
3476
+ const hasTotalCount = objectType.fields.some((f) => f.name === "totalCount");
3477
+ return hasNodes && hasTotalCount;
3478
+ }
3479
+ }
3480
+ return false;
3481
+ }
3482
+ function generateGrid({ exportName, baseOutputFilename, targetDirectory, gqlIntrospection }, config) {
3483
+ const gqlType = config.gqlType;
3484
+ if (!gqlType) throw new Error("gqlType is required in grid config");
3485
+ const muiXGridVariant = detectMuiXGridVariant();
3486
+ const gqlTypePlural = plural(gqlType);
3487
+ const instanceGqlType = gqlType[0].toLowerCase() + gqlType.substring(1);
3488
+ const instanceGqlTypePlural = gqlTypePlural[0].toLowerCase() + gqlTypePlural.substring(1);
3489
+ const gridQuery = config.query ? config.query : instanceGqlType != instanceGqlTypePlural ? instanceGqlTypePlural : `${instanceGqlTypePlural}List`;
3490
+ const gqlDocuments = {};
3491
+ const imports = [
3492
+ {
3493
+ name: "FormattedMessage",
3494
+ importPath: "react-intl"
3495
+ },
3496
+ {
3497
+ name: "FormattedNumber",
3498
+ importPath: "react-intl"
3499
+ },
3500
+ {
3501
+ name: "useIntl",
3502
+ importPath: "react-intl"
3503
+ },
3504
+ {
3505
+ name: "ReactNode",
3506
+ importPath: "react"
3507
+ },
3508
+ {
3509
+ name: "gql",
3510
+ importPath: "@apollo/client"
3511
+ },
3512
+ {
3513
+ name: "useApolloClient",
3514
+ importPath: "@apollo/client"
3515
+ },
3516
+ {
3517
+ name: "useQuery",
3518
+ importPath: "@apollo/client"
3519
+ },
3520
+ {
3521
+ name: "Button",
3522
+ importPath: "@comet/admin"
3523
+ },
3524
+ {
3525
+ name: "CrudContextMenu",
3526
+ importPath: "@comet/admin"
3527
+ },
3528
+ {
3529
+ name: "CrudMoreActionsMenu",
3530
+ importPath: "@comet/admin"
3531
+ },
3532
+ {
3533
+ name: "DataGridToolbar",
3534
+ importPath: "@comet/admin"
3535
+ },
3536
+ {
3537
+ name: "ExportApi",
3538
+ importPath: "@comet/admin"
3539
+ },
3540
+ {
3541
+ name: "filterByFragment",
3542
+ importPath: "@comet/admin"
3543
+ },
3544
+ {
3545
+ name: "GridFilterButton",
3546
+ importPath: "@comet/admin"
3547
+ },
3548
+ {
3549
+ name: "GridCellContent",
3550
+ importPath: "@comet/admin"
3551
+ },
3552
+ {
3553
+ name: "GridColDef",
3554
+ importPath: "@comet/admin"
3555
+ },
3556
+ {
3557
+ name: "dataGridDateTimeColumn",
3558
+ importPath: "@comet/admin"
3559
+ },
3560
+ {
3561
+ name: "dataGridDateColumn",
3562
+ importPath: "@comet/admin"
3563
+ },
3564
+ {
3565
+ name: "dataGridIdColumn",
3566
+ importPath: "@comet/admin"
3567
+ },
3568
+ {
3569
+ name: "dataGridManyToManyColumn",
3570
+ importPath: "@comet/admin"
3571
+ },
3572
+ {
3573
+ name: "dataGridOneToManyColumn",
3574
+ importPath: "@comet/admin"
3575
+ },
3576
+ {
3577
+ name: "renderStaticSelectCell",
3578
+ importPath: "@comet/admin"
3579
+ },
3580
+ {
3581
+ name: "messages",
3582
+ importPath: "@comet/admin"
3583
+ },
3584
+ {
3585
+ name: "muiGridFilterToGql",
3586
+ importPath: "@comet/admin"
3587
+ },
3588
+ {
3589
+ name: "StackLink",
3590
+ importPath: "@comet/admin"
3591
+ },
3592
+ {
3593
+ name: "useStackSwitchApi",
3594
+ importPath: "@comet/admin"
3595
+ },
3596
+ {
3597
+ name: "FillSpace",
3598
+ importPath: "@comet/admin"
3599
+ },
3600
+ {
3601
+ name: "Tooltip",
3602
+ importPath: "@comet/admin"
3603
+ },
3604
+ {
3605
+ name: "useBufferedRowCount",
3606
+ importPath: "@comet/admin"
3607
+ },
3608
+ {
3609
+ name: "useDataGridExcelExport",
3610
+ importPath: "@comet/admin"
3611
+ },
3612
+ {
3613
+ name: "usePersistentColumnState",
3614
+ importPath: "@comet/admin"
3615
+ },
3616
+ {
3617
+ name: "BlockPreviewContent",
3618
+ importPath: "@comet/cms-admin"
3619
+ },
3620
+ {
3621
+ name: "Alert",
3622
+ importPath: "@mui/material"
3623
+ },
3624
+ {
3625
+ name: "Box",
3626
+ importPath: "@mui/material"
3627
+ },
3628
+ {
3629
+ name: "IconButton",
3630
+ importPath: "@mui/material"
3631
+ },
3632
+ {
3633
+ name: "Typography",
3634
+ importPath: "@mui/material"
3635
+ },
3636
+ {
3637
+ name: "useTheme",
3638
+ importPath: "@mui/material"
3639
+ },
3640
+ {
3641
+ name: "Menu",
3642
+ importPath: "@mui/material"
3643
+ },
3644
+ {
3645
+ name: "MenuItem",
3646
+ importPath: "@mui/material"
3647
+ },
3648
+ {
3649
+ name: "ListItemIcon",
3650
+ importPath: "@mui/material"
3651
+ },
3652
+ {
3653
+ name: "ListItemText",
3654
+ importPath: "@mui/material"
3655
+ },
3656
+ {
3657
+ name: "CircularProgress",
3658
+ importPath: "@mui/material"
3659
+ },
3660
+ {
3661
+ name: muiXGridVariant.gridComponent,
3662
+ importPath: muiXGridVariant.package
3663
+ },
3664
+ {
3665
+ name: `${muiXGridVariant.gridComponent}Props`,
3666
+ importPath: muiXGridVariant.package
3667
+ },
3668
+ {
3669
+ name: "GridLogicOperator",
3670
+ importPath: muiXGridVariant.package
3671
+ },
3672
+ {
3673
+ name: "GridRenderCellParams",
3674
+ importPath: muiXGridVariant.package
3675
+ },
3676
+ {
3677
+ name: "GridSlotsComponent",
3678
+ importPath: muiXGridVariant.package
3679
+ },
3680
+ {
3681
+ name: "GridToolbarProps",
3682
+ importPath: muiXGridVariant.package
3683
+ },
3684
+ {
3685
+ name: "GridColumnHeaderTitle",
3686
+ importPath: muiXGridVariant.package
3687
+ },
3688
+ {
3689
+ name: "GridToolbarQuickFilter",
3690
+ importPath: muiXGridVariant.package
3691
+ },
3692
+ {
3693
+ name: "GridRowOrderChangeParams",
3694
+ importPath: muiXGridVariant.package
3695
+ },
3696
+ {
3697
+ name: "useMemo",
3698
+ importPath: "react"
3699
+ }
3700
+ ];
3701
+ const iconsToImport = [
3702
+ "Add",
3703
+ "Edit",
3704
+ "Info",
3705
+ "Excel"
3706
+ ];
3707
+ const props = [];
3708
+ const fieldList = generateGqlFieldList({ columns: config.columns });
3709
+ const rootBlocks = findRootBlocks({
3710
+ gqlType,
3711
+ targetDirectory
3712
+ }, gqlIntrospection);
3713
+ config.columns.filter((column) => column.type == "block").forEach((field) => {
3714
+ if (rootBlocks[String(field.name)]) {
3715
+ const block = field.block;
3716
+ if (isGeneratorConfigImport(block)) {
3717
+ rootBlocks[String(field.name)].import = block.import;
3718
+ rootBlocks[String(field.name)].name = block.name;
3719
+ }
3720
+ }
3721
+ });
3722
+ Object.values(rootBlocks).forEach((block) => {
3723
+ if (isGeneratorConfigImport(block)) imports.push(convertConfigImport(block));
3724
+ });
3725
+ const gridQueryType = findQueryTypeOrThrow(gridQuery, gqlIntrospection);
3726
+ const hasPaging = queryHasPaging(gridQueryType, gqlIntrospection);
3727
+ if (hasPaging) imports.push({
3728
+ name: "useDataGridRemote",
3729
+ importPath: "@comet/admin"
3730
+ });
3731
+ else imports.push({
3732
+ name: "useDataGridUrlState",
3733
+ importPath: "@comet/admin"
3734
+ });
3735
+ const updateMutationType = findMutationType(`update${gqlType}`, gqlIntrospection);
3736
+ const hasDeleteMutation = !!findMutationType(`delete${gqlType}`, gqlIntrospection);
3737
+ const hasUpdateMutation = !!updateMutationType;
3738
+ const allowAdding = (typeof config.add === "undefined" || config.add === true) && !config.readOnly;
3739
+ const allowEditing = (typeof config.edit === "undefined" || config.edit === true) && !config.readOnly;
3740
+ const allowDeleting = (typeof config.delete === "undefined" || config.delete === true) && !config.readOnly && hasDeleteMutation;
3741
+ const allowRowReordering = typeof config.rowReordering?.enabled !== "undefined" && config.rowReordering?.enabled && hasUpdateMutation;
3742
+ const updateInputArg = updateMutationType?.args.find((arg) => arg.name === "input");
3743
+ if (allowRowReordering && updateInputArg) {
3744
+ const inputType = findInputObjectType(updateInputArg, gqlIntrospection);
3745
+ if (!inputType) throw new Error("Can't find update input type");
3746
+ if (!inputType.inputFields?.find((field) => field.name === "position")) throw new Error("Position field is needed when using 'rowReordering'");
3747
+ }
3748
+ if (allowRowReordering && typeof config.rowReordering?.dragPreviewField !== "undefined" && !config.columns.find((column) => column.type !== "actions" && column?.name === config.rowReordering?.dragPreviewField)) throw new Error(`rowReorderingOnDragField '${config.rowReordering?.dragPreviewField}' must exist in columns`);
3749
+ const forwardRowAction = allowEditing && config.rowActionProp;
3750
+ const showActionsColumn = allowEditing || allowDeleting;
3751
+ const showCrudContextMenuInActionsColumn = allowDeleting;
3752
+ const showEditInActionsColumn = allowEditing && !forwardRowAction;
3753
+ const defaultActionsColumnWidth = getDefaultActionsColumnWidth(showCrudContextMenuInActionsColumn, showEditInActionsColumn);
3754
+ let useScopeFromContext = false;
3755
+ const gqlArgs = [];
3756
+ {
3757
+ const forwardedArgs = getForwardedGqlArgs([gridQueryType]);
3758
+ for (const forwardedArg of forwardedArgs) {
3759
+ imports.push(...forwardedArg.imports);
3760
+ if (forwardedArg.gqlArg.name === "scope" && !config.scopeAsProp) {
3761
+ useScopeFromContext = true;
3762
+ gqlArgs.push(forwardedArg.gqlArg);
3763
+ } else {
3764
+ props.push(forwardedArg.prop);
3765
+ gqlArgs.push(forwardedArg.gqlArg);
3766
+ }
3767
+ }
3768
+ }
3769
+ if (useScopeFromContext) imports.push({
3770
+ name: "useContentScope",
3771
+ importPath: "@comet/cms-admin"
3772
+ });
3773
+ const renderToolbar = config.toolbar ?? true;
3774
+ const filterArg = gridQueryType.args.find((arg) => arg.name === "filter");
3775
+ const hasFilter = !!filterArg && renderToolbar && !allowRowReordering;
3776
+ let hasFilterProp = false;
3777
+ let filterFields = [];
3778
+ if (filterArg) {
3779
+ const filterType = findInputObjectType(filterArg, gqlIntrospection);
3780
+ if (!filterType) throw new Error("Can't find filter type");
3781
+ filterFields = filterType.inputFields.map((f) => f.name.replace(/_/g, "."));
3782
+ const { hasFilterProp: tempHasFilterProp, imports: filterPropImports, props: filterPropProps } = getPropsForFilterProp({
3783
+ config,
3784
+ filterType
3785
+ });
3786
+ hasFilterProp = tempHasFilterProp;
3787
+ imports.push(...filterPropImports);
3788
+ props.push(...filterPropProps);
3789
+ }
3790
+ const forwardToolbarAction = allowAdding && renderToolbar && config.toolbarActionProp;
3791
+ if (forwardToolbarAction) props.push({
3792
+ name: "toolbarAction",
3793
+ type: "ReactNode",
3794
+ optional: true
3795
+ });
3796
+ const sortArg = gridQueryType.args.find((arg) => arg.name === "sort");
3797
+ const hasSort = !!sortArg;
3798
+ let sortFields = [];
3799
+ if (sortArg) {
3800
+ imports.push({
3801
+ name: "muiGridSortToGql",
3802
+ importPath: "@comet/admin"
3803
+ });
3804
+ let sortArgType = sortArg.type;
3805
+ if (sortArgType.kind === "NON_NULL") sortArgType = sortArgType.ofType;
3806
+ if (sortArgType.kind !== "LIST") throw new Error("Sort argument must be LIST");
3807
+ if (sortArgType.ofType.kind !== "NON_NULL") throw new Error("Sort argument must be LIST->NON_NULL");
3808
+ if (sortArgType.ofType.ofType.kind !== "INPUT_OBJECT") throw new Error("Sort argument must be LIST->NON_NULL->INPUT_OBJECT");
3809
+ const sortTypeName = sortArgType.ofType.ofType.name;
3810
+ const sortType = gqlIntrospection.__schema.types.find((type) => type.kind === "INPUT_OBJECT" && type.name === sortTypeName);
3811
+ if (!sortType) throw new Error("Can't find sort type");
3812
+ const sortField = sortType.inputFields.find((i) => i.name == "field");
3813
+ if (!sortField) throw new Error("Can't find sortFieldName");
3814
+ if (sortField.type.kind !== "NON_NULL") throw new Error("sortField must be NON_NULL");
3815
+ if (sortField.type.ofType.kind != "ENUM") throw new Error("sortField must be NON_NULL->ENUM");
3816
+ const sortFieldEnumName = sortField.type.ofType.name;
3817
+ const sortInputEnum = gqlIntrospection.__schema.types.find((type) => type.kind === "ENUM" && type.name === sortFieldEnumName);
3818
+ if (!sortInputEnum) throw new Error("Can't find sortInputEnum");
3819
+ sortFields = sortInputEnum.enumValues.map((v) => v.name.replace(/_/g, "."));
3820
+ if (allowRowReordering && !sortFields.includes("position")) throw new Error("Sort argument must include 'position' field for row reordering");
3821
+ }
3822
+ const hasSearch = gridQueryType.args.some((arg) => arg.name === "search") && !allowRowReordering;
3823
+ const schemaEntity = gqlIntrospection.__schema.types.find((type) => type.kind === "OBJECT" && type.name === gqlType);
3824
+ if (!schemaEntity) throw new Error("didn't find entity in schema types");
3825
+ const { component: actionsColumnComponent, type: actionsColumnType, headerName: actionsColumnHeaderName, pinned: actionsColumnPinned = "right", width: actionsColumnWidth = defaultActionsColumnWidth, visible: actionsColumnVisible = void 0, queryFields: actionsColumnQueryFields = [], ...restActionsColumnConfig } = config.columns.find((column) => column.type === "actions") ?? {};
3826
+ if (actionsColumnComponent) {
3827
+ if (!isGeneratorConfigImport(actionsColumnComponent)) throw new Error("Unsupported actionsColumnComponent, only imports are supported");
3828
+ imports.push(convertConfigImport(actionsColumnComponent));
3829
+ }
3830
+ const gridNeedsTheme = config.columns.some((column) => typeof column.visible === "string");
3831
+ const gridColumnFields = config.columns.filter((column) => column.type !== "actions").map((column) => {
3832
+ const type = column.type;
3833
+ const name = String(column.name);
3834
+ let gridColumnType = void 0;
3835
+ let renderCell = void 0;
3836
+ let valueFormatter = void 0;
3837
+ let valueGetter = name.includes(".") ? `(params, row) => row.${name.replace(/\./g, "?.")}` : void 0;
3838
+ let gridType;
3839
+ let filterOperators;
3840
+ if (column.type != "virtual" && column.filterOperators) if (isGeneratorConfigImport(column.filterOperators)) {
3841
+ imports.push(convertConfigImport(column.filterOperators));
3842
+ filterOperators = column.filterOperators.name;
3843
+ } else throw new Error("Unsupported filterOperators, only imports are supported for now");
3844
+ if (type == "dateTime") {
3845
+ gridColumnType = "...dataGridDateTimeColumn,";
3846
+ valueGetter = name.includes(".") ? `(params, row) => row.${name.replace(/\./g, "?.")} && new Date(row.${name.replace(/\./g, "?.")})` : void 0;
3847
+ } else if (type == "date") {
3848
+ gridColumnType = "...dataGridDateColumn,";
3849
+ valueGetter = name.includes(".") ? `(params, row) => row.${name.replace(/\./g, "?.")} && new Date(row.${name.replace(/\./g, "?.")})` : void 0;
3850
+ } else if (type == "number") {
3851
+ gridType = "number";
3852
+ const defaultDecimals = column.currency ? 2 : 0;
3853
+ const decimals = typeof column.decimals === "number" ? column.decimals : defaultDecimals;
3854
+ renderCell = `({ value }) => {
3855
+ return (typeof value === "number") ? <FormattedNumber value={value} ${column.currency ? `style="currency" currency="${column.currency}"` : ""} minimumFractionDigits={${decimals}} maximumFractionDigits={${decimals}} /> : "";
3856
+ }`;
3857
+ } else if (type == "boolean") gridType = "boolean";
3858
+ else if (column.type == "block") renderCell = `(params) => {
3859
+ return <BlockPreviewContent block={${column.block.name}} input={params.row.${name}} />;
3860
+ }`;
3861
+ else if (type == "staticSelect") {
3862
+ valueFormatter = `(value, row) => row.${name}?.toString()`;
3863
+ const introspectionField = schemaEntity.fields.find((field) => field.name === name);
3864
+ if (!introspectionField) throw new Error(`didn't find field ${name} in gql introspection type ${gqlType}`);
3865
+ const introspectionFieldType = introspectionField.type.kind === "NON_NULL" ? introspectionField.type.ofType : introspectionField.type;
3866
+ const enumType = gqlIntrospection.__schema.types.find((t) => t.kind === "ENUM" && t.name === introspectionFieldType.name);
3867
+ column.values?.forEach((value) => {
3868
+ if (typeof value === "object" && typeof value.label === "object" && "icon" in value.label) {
3869
+ if (typeof value.label.icon === "string") iconsToImport.push(value.label.icon);
3870
+ else if (typeof value.label.icon?.name === "string") if (isGeneratorConfigImport(value.label.icon)) imports.push(convertConfigImport(value.label.icon));
3871
+ else iconsToImport.push(value.label.icon.name);
3872
+ }
3873
+ });
3874
+ let columnValues = [];
3875
+ if (column.values) columnValues = column.values;
3876
+ else if (enumType) columnValues = enumType.enumValues.map((i) => i.name);
3877
+ else throw new Error(`Enum type not found`);
3878
+ const valueOptions = `[${columnValues.map((value) => {
3879
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") return {
3880
+ value,
3881
+ label: camelCaseToHumanReadable(value.toString())
3882
+ };
3883
+ else return value;
3884
+ }).map(({ value, label }) => {
3885
+ const labelData = getValueOptionsLabelData(`${instanceGqlType}.${name}.${value.toString().charAt(0).toLowerCase() + value.toString().slice(1)}`, label);
3886
+ return `{
3887
+ value: ${JSON.stringify(value)},
3888
+ label: ${labelData.textLabel},
3889
+ ${labelData.gridCellContent !== void 0 ? `cellContent: ${labelData.gridCellContent},` : ""}
3890
+ },`;
3891
+ }).join(" ")}]`;
3892
+ renderCell = `renderStaticSelectCell`;
3893
+ return {
3894
+ name,
3895
+ headerName: column.headerName,
3896
+ type,
3897
+ gridType: "singleSelect",
3898
+ columnType: gridColumnType,
3899
+ valueOptions,
3900
+ renderCell,
3901
+ valueFormatter,
3902
+ width: column.width,
3903
+ minWidth: column.minWidth,
3904
+ maxWidth: column.maxWidth,
3905
+ flex: column.flex,
3906
+ headerInfoTooltip: column.headerInfoTooltip,
3907
+ visible: column.visible !== void 0 ? typeof column.visible == "string" ? `theme.breakpoints.${column.visible}` : "false" : void 0,
3908
+ pinned: column.pinned,
3909
+ disableExport: column.disableExport
3910
+ };
3911
+ } else if (type == "id") gridColumnType = "...dataGridIdColumn,";
3912
+ else if (type == "manyToMany") gridColumnType = "...dataGridManyToManyColumn,";
3913
+ else if (type == "oneToMany") gridColumnType = "...dataGridOneToManyColumn,";
3914
+ if ((column.type == "text" || column.type == "number" || column.type == "boolean" || column.type == "date" || column.type == "dateTime" || column.type == "virtual" || column.type == "id" || column.type == "manyToMany" || column.type == "oneToMany") && column.renderCell) if (isGeneratorConfigCode(column.renderCell)) {
3915
+ renderCell = column.renderCell.code;
3916
+ imports.push(...column.renderCell.imports.map((imprt) => convertConfigImport(imprt)));
3917
+ } else throw new Error(`Unsupported renderCell for column '${name}', only arrow functions are supported`);
3918
+ if ((column.type === "manyToMany" || column.type === "oneToMany") && !column.renderCell) {
3919
+ if (!column.labelField) throw new Error(`labelField is required for ${column.type} column '${name}' if no custom renderCell is provided`);
3920
+ renderCell = `({ row }) => <>{row.${column.name}.map((${singular(column.name)}) => ${singular(column.name)}.${column.labelField}).join(", ")}</>`;
3921
+ }
3922
+ return {
3923
+ name,
3924
+ fieldName: column.fieldName,
3925
+ headerName: column.headerName,
3926
+ type,
3927
+ gridType,
3928
+ columnType: gridColumnType,
3929
+ renderCell,
3930
+ valueGetter,
3931
+ filterOperators,
3932
+ valueFormatter,
3933
+ width: column.width,
3934
+ minWidth: column.minWidth,
3935
+ maxWidth: column.maxWidth,
3936
+ flex: column.flex,
3937
+ headerInfoTooltip: column.headerInfoTooltip,
3938
+ visible: column.visible !== void 0 ? typeof column.visible == "string" ? `theme.breakpoints.${column.visible}` : "false" : void 0,
3939
+ pinned: column.pinned,
3940
+ disableExport: column.disableExport,
3941
+ sortBy: "sortBy" in column ? column.sortBy : void 0
3942
+ };
3943
+ });
3944
+ iconsToImport.forEach((icon) => {
3945
+ imports.push({
3946
+ name: `${icon} as ${icon}Icon`,
3947
+ importPath: "@comet/admin-icons"
3948
+ });
3949
+ });
3950
+ const fragmentName = config.fragmentName ?? `${gqlTypePlural}Form`;
3951
+ if (forwardRowAction) {
3952
+ props.push({
3953
+ name: "rowAction",
3954
+ type: `(params: GridRenderCellParams<GQL${fragmentName}Fragment>) => ReactNode`,
3955
+ optional: true
3956
+ });
3957
+ props.push({
3958
+ name: "actionsColumnWidth",
3959
+ type: `number`,
3960
+ optional: true,
3961
+ defaultValue: defaultActionsColumnWidth
3962
+ });
3963
+ props.push({
3964
+ name: "onRowClick",
3965
+ type: `${muiXGridVariant.gridComponent}Props["onRowClick"]`,
3966
+ optional: true
3967
+ });
3968
+ }
3969
+ if (config.selectionProps) {
3970
+ props.push({
3971
+ name: "rowSelectionModel",
3972
+ type: `${muiXGridVariant.gridComponent}Props["rowSelectionModel"]`,
3973
+ optional: true
3974
+ });
3975
+ props.push({
3976
+ name: "onRowSelectionModelChange",
3977
+ type: `${muiXGridVariant.gridComponent}Props["onRowSelectionModelChange"]`,
3978
+ optional: true
3979
+ });
3980
+ }
3981
+ const { gridPropsTypeCode, gridPropsParamsCode } = generateGridPropsCode(props);
3982
+ const gridToolbarComponentName = `${gqlTypePlural}GridToolbar`;
3983
+ const dataGridRemoteParameters = config.initialSort || config.queryParamsPrefix || config.initialFilter ? `{${config.initialSort ? ` initialSort: [${config.initialSort.map((item) => {
3984
+ return `{field: "${item.field}", sort: "${item.sort}"}`;
3985
+ }).join(",\n")} ], ` : ""}
3986
+ ${config.initialFilter ? `initialFilter:{ ${config.initialFilter.linkOperator ? `linkOperator: GridLogicOperator.${config.initialFilter.linkOperator === "or" ? "Or" : "And"},` : ""}
3987
+ items: [${config.initialFilter.items.map((item) => {
3988
+ return `{ field: "${item.field}", operator: "${item.operator}", value: "${item.value}" }`;
3989
+ }).join(",\n")} ],},` : ""}
3990
+ ${config.queryParamsPrefix ? `queryParamsPrefix: "${config.queryParamsPrefix}",` : ""}
3991
+ }` : "";
3992
+ return {
3993
+ code: `import {
3994
+ GQL${gqlTypePlural}GridQuery,
3995
+ GQL${gqlTypePlural}GridQueryVariables,
3996
+ GQL${fragmentName}Fragment,
3997
+ GQLCreate${gqlType}Mutation,
3998
+ GQLCreate${gqlType}MutationVariables,
3999
+ GQLUpdate${gqlType}PositionMutation,
4000
+ GQLUpdate${gqlType}PositionMutationVariables,
4001
+ GQLDelete${gqlType}Mutation,
4002
+ GQLDelete${gqlType}MutationVariables
4003
+ } from "./${baseOutputFilename}.generated";
4004
+ ${generateImportsCode(imports)}
4005
+
4006
+ const ${instanceGqlTypePlural}Fragment = gql\`
4007
+ fragment ${fragmentName} on ${gqlType} {
4008
+ id
4009
+ ${fieldList}
4010
+ }
4011
+ \`;
4012
+
4013
+ const ${instanceGqlTypePlural}Query = gql\`${generateGqlOperation({
4014
+ type: "query",
4015
+ operationName: `${gqlTypePlural}Grid`,
4016
+ rootOperation: gridQuery,
4017
+ fields: hasPaging ? [`nodes...${fragmentName}`, "totalCount"] : [`...${fragmentName}`],
4018
+ fragmentVariables: [`\${${instanceGqlTypePlural}Fragment}`],
4019
+ variables: [
4020
+ ...gqlArgs.filter((gqlArg) => gqlArg.queryOrMutationName === gridQueryType.name).map((gqlArg) => ({
4021
+ name: gqlArg.name,
4022
+ type: `${gqlArg.type}!`
4023
+ })),
4024
+ ...hasPaging ? [{
4025
+ name: "offset",
4026
+ type: "Int!"
4027
+ }, {
4028
+ name: "limit",
4029
+ type: "Int!"
4030
+ }] : [],
4031
+ ...hasSort ? [{
4032
+ name: "sort",
4033
+ type: `[${gqlType}Sort!]`
4034
+ }] : [],
4035
+ ...hasSearch ? [{
4036
+ name: "search",
4037
+ type: "String"
4038
+ }] : [],
4039
+ ...filterArg && (hasFilter || hasFilterProp) ? [{
4040
+ name: "filter",
4041
+ type: `${gqlType}Filter`
4042
+ }] : []
4043
+ ]
4044
+ })}\`;
4045
+
4046
+ ${allowRowReordering ? `const update${gqlType}PositionMutation = gql\`
4047
+ mutation Update${gqlType}Position($id: ID!, $input: ${gqlType}UpdateInput!) {
4048
+ update${gqlType}(id: $id, input: $input) {
4049
+ id
4050
+ position
4051
+ updatedAt
4052
+ }
4053
+ }
4054
+ \`;` : ""}
4055
+
4056
+ ${allowDeleting ? `const delete${gqlType}Mutation = gql\`
4057
+ mutation Delete${gqlType}($id: ID!) {
4058
+ delete${gqlType}(id: $id)
4059
+ }
4060
+ \`;` : ""}
4061
+
4062
+
4063
+ ${renderToolbar ? generateGridToolbar({
4064
+ componentName: gridToolbarComponentName,
4065
+ forwardToolbarAction,
4066
+ hasSearch,
4067
+ hasFilter,
4068
+ allowAdding,
4069
+ instanceGqlType,
4070
+ gqlType,
4071
+ excelExport: config.excelExport,
4072
+ newEntryText: config.newEntryText,
4073
+ fragmentName
4074
+ }) : ""}
4075
+
4076
+ ${gridPropsTypeCode}
4077
+
4078
+ export function ${gqlTypePlural}Grid(${gridPropsParamsCode}) {
4079
+ ${showCrudContextMenuInActionsColumn ? "const client = useApolloClient();" : ""}
4080
+ const intl = useIntl();
4081
+ const dataGridProps = { ...${hasPaging ? "useDataGridRemote" : "useDataGridUrlState"}(${dataGridRemoteParameters}), ...usePersistentColumnState("${gqlTypePlural}Grid")${config.selectionProps === "multiSelect" ? `, rowSelectionModel, onRowSelectionModelChange, checkboxSelection: true, keepNonExistentRowsSelected: true` : config.selectionProps === "singleSelect" ? `, rowSelectionModel, onRowSelectionModelChange, checkboxSelection: false, keepNonExistentRowsSelected: false, disableRowSelectionOnClick: false` : ``} };
4082
+ ${useScopeFromContext ? `const { scope } = useContentScope();` : ""}
4083
+ ${gridNeedsTheme ? `const theme = useTheme();` : ""}
4084
+ ${showEditInActionsColumn ? `const stackSwitchApi = useStackSwitchApi();` : ""}
4085
+
4086
+ ${generateHandleRowOrderChange(allowRowReordering, gqlType, instanceGqlTypePlural)}
4087
+
4088
+ ${showEditInActionsColumn ? `const handleRowClick: ${muiXGridVariant.gridComponent}Props["onRowClick"] = (params) => {
4089
+ stackSwitchApi.activatePage("edit", params.row.id);
4090
+ };` : ""}
4091
+
4092
+ const columns: GridColDef<GQL${fragmentName}Fragment>[] = useMemo(()=>[
4093
+ ${gridColumnFields.map((column) => {
4094
+ const defaultMinWidth = 150;
4095
+ const defaultColumnFlex = 1;
4096
+ let minWidth;
4097
+ let maxWidth;
4098
+ let tooltipColumnWidth = column.width;
4099
+ if (typeof column.width === "undefined") {
4100
+ maxWidth = column.maxWidth;
4101
+ if (typeof column.minWidth === "undefined" && (typeof column.maxWidth === "undefined" || column.maxWidth >= defaultMinWidth)) {
4102
+ minWidth = defaultMinWidth;
4103
+ tooltipColumnWidth = defaultMinWidth;
4104
+ } else if (typeof column.minWidth !== "undefined") {
4105
+ minWidth = column.minWidth;
4106
+ tooltipColumnWidth = column.minWidth;
4107
+ }
4108
+ }
4109
+ let isColumnFilterable = !hasPaging ? true : filterFields.includes(column.name) || !!column.filterOperators;
4110
+ if (allowRowReordering) isColumnFilterable = false;
4111
+ if (column.type == "block" && !hasPaging) isColumnFilterable = false;
4112
+ let isColumnSortable = !hasPaging ? true : sortFields.includes(column.name) || !!column.sortBy;
4113
+ if (allowRowReordering) isColumnSortable = false;
4114
+ if (column.type == "block" && !hasPaging) isColumnSortable = false;
4115
+ const columnDefinition = {
4116
+ field: column.fieldName ? `"${column.fieldName}"` : `"${column.name.replace(/\./g, "_")}"`,
4117
+ renderHeader: column.headerInfoTooltip ? `() => (
4118
+ <>
4119
+ <GridColumnHeaderTitle label={${generateFormattedMessage({
4120
+ config: column.headerName,
4121
+ id: `${instanceGqlType}.${column.name}`,
4122
+ defaultMessage: camelCaseToHumanReadable(column.name),
4123
+ type: "intlCall"
4124
+ })}} columnWidth= {${tooltipColumnWidth}}
4125
+ />
4126
+ <Tooltip
4127
+ title={${generateFormattedMessage({
4128
+ config: column.headerInfoTooltip,
4129
+ id: `${instanceGqlType}.${column.name}.tooltip`,
4130
+ type: "jsx"
4131
+ })}}
4132
+ >
4133
+ <InfoIcon sx={{ marginLeft: 1 }} />
4134
+ </Tooltip>
4135
+ </>
4136
+ )` : void 0,
4137
+ headerName: column.headerName === "" ? `""` : generateFormattedMessage({
4138
+ config: column.headerName,
4139
+ id: `${instanceGqlType}.${column.name}`,
4140
+ defaultMessage: camelCaseToHumanReadable(column.name),
4141
+ type: "intlCall"
4142
+ }),
4143
+ type: column.gridType ? `"${column.gridType}"` : void 0,
4144
+ filterable: isColumnFilterable ? void 0 : `false`,
4145
+ sortable: isColumnSortable ? void 0 : `false`,
4146
+ valueGetter: column.valueGetter,
4147
+ valueFormatter: column.valueFormatter,
4148
+ valueOptions: column.valueOptions,
4149
+ renderCell: column.renderCell,
4150
+ filterOperators: column.filterOperators,
4151
+ width: column.width,
4152
+ flex: column.flex,
4153
+ pinned: column.pinned && `"${column.pinned}"`,
4154
+ visible: column.visible,
4155
+ disableExport: column.disableExport ? "true" : void 0
4156
+ };
4157
+ if ("sortBy" in column && column.sortBy) columnDefinition["sortBy"] = getSortByValue(column.sortBy);
4158
+ if (typeof column.width === "undefined") {
4159
+ columnDefinition.flex = defaultColumnFlex;
4160
+ columnDefinition.minWidth = minWidth;
4161
+ columnDefinition.maxWidth = maxWidth;
4162
+ }
4163
+ return tsCodeRecordToString(columnDefinition, column.columnType);
4164
+ }).join(",\n")},
4165
+ ${showActionsColumn ? tsCodeRecordToString({
4166
+ field: "\"actions\"",
4167
+ headerName: actionsColumnHeaderName ? generateFormattedMessage({
4168
+ config: actionsColumnHeaderName,
4169
+ id: `${instanceGqlType}.actions`,
4170
+ type: "intlCall"
4171
+ }) : `""`,
4172
+ sortable: "false",
4173
+ filterable: "false",
4174
+ type: "\"actions\"",
4175
+ align: "\"right\"",
4176
+ pinned: `"${actionsColumnPinned}"`,
4177
+ width: forwardRowAction ? "actionsColumnWidth" : actionsColumnWidth,
4178
+ visible: actionsColumnVisible !== void 0 ? typeof actionsColumnVisible == "string" ? `theme.breakpoints.${actionsColumnVisible}` : "false" : void 0,
4179
+ ...restActionsColumnConfig,
4180
+ headerInfoTooltip: restActionsColumnConfig.headerInfoTooltip ? generateFormattedMessage({
4181
+ config: restActionsColumnConfig.headerInfoTooltip,
4182
+ id: `${instanceGqlType}.actions`,
4183
+ type: "intlCall"
4184
+ }) : void 0,
4185
+ disableExport: config.excelExport ? "true" : void 0,
4186
+ renderCell: `(params) => {
4187
+ return (
4188
+ <>
4189
+ ${actionsColumnComponent?.name ? `<${actionsColumnComponent.name} {...params} />` : ""}${allowEditing ? forwardRowAction ? `{rowAction && rowAction(params)}` : `
4190
+ <IconButton color="primary" component={StackLink} pageName="edit" payload={params.row.id}>
4191
+ <EditIcon />
4192
+ </IconButton>` : ""}${showCrudContextMenuInActionsColumn ? `
4193
+ <CrudContextMenu
4194
+ ${allowDeleting ? `
4195
+ onDelete={async () => {
4196
+ await client.mutate<GQLDelete${gqlType}Mutation, GQLDelete${gqlType}MutationVariables>({
4197
+ mutation: delete${gqlType}Mutation,
4198
+ variables: { id: params.row.id },
4199
+ });
4200
+ }}
4201
+ ` : ""}
4202
+ refetchQueries={[${instanceGqlTypePlural}Query]}
4203
+ ${config.crudContextMenu?.deleteType ? `deleteType="${config.crudContextMenu.deleteType}"` : ""}
4204
+ ${config.crudContextMenu?.deleteText ? `messagesMapping={{ delete: <FormattedMessage id="${instanceGqlType}.crudContextMenu.delete" defaultMessage="${config.crudContextMenu.deleteText}" /> }}` : ""}
4205
+ />
4206
+ ` : ""}
4207
+ </>
4208
+ );
4209
+ }`
4210
+ }) : ""}
4211
+ ],[intl${gridNeedsTheme ? ", theme" : ""}${showCrudContextMenuInActionsColumn ? ", client" : ""}${forwardRowAction ? ", rowAction, actionsColumnWidth" : ""}]);
4212
+
4213
+ ${hasFilter || hasSearch ? `const { ${hasFilter ? `filter: gqlFilter, ` : ""}${hasSearch ? `search: gqlSearch, ` : ""} } = muiGridFilterToGql(columns, dataGridProps.filterModel);` : ""}
4214
+
4215
+ const { data, loading, error } = useQuery<GQL${gqlTypePlural}GridQuery, GQL${gqlTypePlural}GridQueryVariables>(${instanceGqlTypePlural}Query, {
4216
+ variables: {
4217
+ ${[
4218
+ ...gqlArgs.filter((gqlArg) => gqlArg.queryOrMutationName === gridQueryType.name).map((arg) => arg.name),
4219
+ ...filterArg ? hasFilter && hasFilterProp ? ["filter: filter ? { and: [gqlFilter, filter] } : gqlFilter"] : hasFilter ? ["filter: gqlFilter"] : hasFilterProp ? ["filter"] : [] : [],
4220
+ ...hasSearch ? ["search: gqlSearch"] : [],
4221
+ ...hasSort ? !allowRowReordering ? ["sort: muiGridSortToGql(dataGridProps.sortModel, columns)"] : [`sort: { field: "position", direction: "ASC" }`] : [],
4222
+ ...hasPaging ? !allowRowReordering ? [`offset: dataGridProps.paginationModel.page * dataGridProps.paginationModel.pageSize`, `limit: dataGridProps.paginationModel.pageSize`] : [`offset: 0`, `limit: 100`] : []
4223
+ ].join(", ")}
4224
+ },
4225
+ });
4226
+ ${hasPaging ? `const rowCount = useBufferedRowCount(data?.${gridQuery}.totalCount);` : ""}
4227
+ if (error) throw error;
4228
+ const rows = ${!allowRowReordering ? hasPaging ? `data?.${gridQuery}.nodes` : `data?.${gridQuery}` : generateRowReorderingRows(gridQuery, fieldList, config.rowReordering?.dragPreviewField)} ?? [];
4229
+
4230
+ ${generateGridExportApi(config.excelExport, gqlTypePlural, instanceGqlTypePlural, gridQuery, gqlArgs, hasPaging)}
4231
+
4232
+ return (
4233
+ <${muiXGridVariant.gridComponent}
4234
+ {...dataGridProps}
4235
+ rows={rows}
4236
+ ${hasPaging ? `rowCount={rowCount}` : ""}
4237
+ columns={columns}
4238
+ loading={loading}
4239
+ ${renderToolbar ? `slots={{
4240
+ toolbar: ${gridToolbarComponentName} as GridSlotsComponent["toolbar"],
4241
+ }}
4242
+ ${getDataGridSlotProps(gridToolbarComponentName, forwardToolbarAction, config.excelExport)}` : ""}
4243
+ ${allowRowReordering ? `rowReordering
4244
+ onRowOrderChange={handleRowOrderChange}
4245
+ hideFooterPagination` : ""}
4246
+ ${config.density ? `density="${config.density}"` : ""}
4247
+ ${showEditInActionsColumn ? `onRowClick={handleRowClick}` : forwardRowAction ? `onRowClick={onRowClick}` : ""}
4248
+ />
4249
+ );
4250
+ }
4251
+ `,
4252
+ gqlDocuments
4253
+ };
4254
+ }
4255
+ const generateRowReorderingRows = (gridQuery, fieldList, dragPreviewField) => {
4256
+ const fields = fieldList.split(" ");
4257
+ return `data?.${gridQuery}.nodes.map((node) => ({
4258
+ ...node,
4259
+ __reorder__: node.${dragPreviewField || fields.find((field) => field === "title" || field === "name") || "id"}
4260
+ }))`;
4261
+ };
4262
+ const getDefaultActionsColumnWidth = (showCrudContextMenu, showEdit) => {
4263
+ let numberOfActions = 0;
4264
+ if (showCrudContextMenu) numberOfActions += 1;
4265
+ if (showEdit) numberOfActions += 1;
4266
+ return numberOfActions * 32 + 20;
4267
+ };
4268
+ const getDataGridSlotProps = (componentName, forwardToolbarAction, excelExport) => {
4269
+ if (!forwardToolbarAction && !excelExport) return "";
4270
+ return `slotProps={{
4271
+ toolbar: ${`{
4272
+ ${forwardToolbarAction ? `toolbarAction,` : ""}
4273
+ ${excelExport ? `exportApi,` : ""}
4274
+ } as ${componentName}ToolbarProps`.replace(/\n/g, "")}
4275
+ }}`;
4276
+ };
4277
+ const generateGridExportApi = (excelExport, gqlTypePlural, instanceGqlTypePlural, gridQuery, gqlArgs, hasPaging) => {
4278
+ if (!excelExport) return "";
4279
+ const queryNodeType = hasPaging ? `GQL${gqlTypePlural}GridQuery["${gridQuery}"]["nodes"][0]` : `GQL${gqlTypePlural}GridQuery["${gridQuery}"][0]`;
4280
+ const variablesType = hasPaging ? `Omit<GQL${gqlTypePlural}GridQueryVariables, "offset" | "limit">` : `GQL${gqlTypePlural}GridQueryVariables`;
4281
+ const resolveQueryNodes = hasPaging ? `(data) => data.${gridQuery}.nodes` : `(data) => data.${gridQuery}`;
4282
+ const totalCount = hasPaging ? `data?.${gridQuery}.totalCount ?? 0` : `data?.${gridQuery}.length ?? 0`;
4283
+ return `const exportApi = useDataGridExcelExport<${queryNodeType}, GQL${gqlTypePlural}GridQuery, ${variablesType}>({
4284
+ columns,
4285
+ variables: {
4286
+ ${[...gqlArgs.filter((gqlArg) => gqlArg.queryOrMutationName === gridQuery).map((arg) => arg.name), `...muiGridFilterToGql(columns, dataGridProps.filterModel)`].join(", ")}
4287
+ },
4288
+ query: ${instanceGqlTypePlural}Query,
4289
+ resolveQueryNodes: ${resolveQueryNodes},
4290
+ totalCount: ${totalCount},
4291
+ ${!hasPaging ? `hasPaging: false,` : ""}
4292
+ exportOptions: {
4293
+ fileName: "${gqlTypePlural}",
4294
+ },
4295
+ });`;
4296
+ };
4297
+ const generateHandleRowOrderChange = (allowRowReordering, gqlType, instanceGqlTypePlural) => {
4298
+ if (!allowRowReordering) return "";
4299
+ return `const handleRowOrderChange = async ({ row: { id }, targetIndex }: GridRowOrderChangeParams) => {
4300
+ await client.mutate<GQLUpdate${gqlType}PositionMutation, GQLUpdate${gqlType}PositionMutationVariables>({
4301
+ mutation: update${gqlType}PositionMutation,
4302
+ variables: { id, input: { position: targetIndex + 1 } },
4303
+ awaitRefetchQueries: true,
4304
+ refetchQueries: [${instanceGqlTypePlural}Query]
4305
+ });
4306
+ };`;
4307
+ };
4308
+
4309
+ //#endregion
4310
+ //#region src/commands/generate/utils/writeGenerated.ts
4311
+ async function writeGenerated(filePath, contents) {
4312
+ const header = `// This file has been generated by comet admin-generator.
4313
+ // You may choose to use this file as scaffold by moving this file out of generated folder and removing this comment.
4314
+ `;
4315
+ await promises.mkdir(path.dirname(filePath), { recursive: true });
4316
+ const sourceFile = ts.createSourceFile(filePath, header + contents, ts.ScriptTarget.Latest, true, ts.ScriptKind.TSX);
4317
+ const result = ts.transform(sourceFile, [removeUnusedImports()]);
4318
+ const prettyCode = ts.createPrinter({
4319
+ newLine: ts.NewLineKind.LineFeed,
4320
+ removeComments: false
4321
+ }).printFile(result.transformed[0]).replace(/gql `/g, "gql`");
4322
+ await promises.writeFile(filePath, prettyCode);
4323
+ console.log(`generated ${filePath}`);
4324
+ }
4325
+ function removeUnusedImports() {
4326
+ return (context) => {
4327
+ function visit(sourceFile) {
4328
+ const usedIdentifiers = /* @__PURE__ */ new Set();
4329
+ function collectUsage(node) {
4330
+ if (ts.isIdentifier(node)) usedIdentifiers.add(node.text);
4331
+ else if (ts.isImportDeclaration(node)) return;
4332
+ ts.forEachChild(node, collectUsage);
4333
+ }
4334
+ ts.forEachChild(sourceFile, collectUsage);
4335
+ function visitor(node) {
4336
+ if (ts.isImportDeclaration(node) && node.importClause) {
4337
+ const { name, namedBindings } = node.importClause;
4338
+ const updatedBindings = [];
4339
+ if (name && usedIdentifiers.has(name.text)) {} else if (name) return;
4340
+ if (namedBindings && ts.isNamedImports(namedBindings)) {
4341
+ for (const specifier of namedBindings.elements) {
4342
+ const importName = specifier.name.text;
4343
+ if (usedIdentifiers.has(importName)) updatedBindings.push(specifier);
4344
+ }
4345
+ if (updatedBindings.length === 0 && !name) return;
4346
+ return ts.factory.updateImportDeclaration(node, node.modifiers, ts.factory.updateImportClause(node.importClause, node.importClause.isTypeOnly, name, updatedBindings.length > 0 ? ts.factory.updateNamedImports(namedBindings, updatedBindings) : void 0), node.moduleSpecifier, node.assertClause);
4347
+ }
4348
+ if (!namedBindings && !name) return node;
4349
+ return node;
4350
+ }
4351
+ return ts.visitEachChild(node, visitor, context);
4352
+ }
4353
+ return ts.visitNode(sourceFile, visitor);
4354
+ }
4355
+ return (sourceFile) => visit(sourceFile);
4356
+ };
4357
+ }
4358
+
4359
+ //#endregion
4360
+ //#region src/commands/generate/generate-command.ts
4361
+ const exec$1 = promisify(exec);
4362
+ function isComponentFormFieldConfig(arg) {
4363
+ return arg && arg.type === "component";
4364
+ }
4365
+ function isFormFieldConfig(arg) {
4366
+ return !isFormLayoutConfig(arg) && !isComponentFormFieldConfig(arg);
4367
+ }
4368
+ function isFormLayoutConfig(arg) {
4369
+ return arg.type !== void 0 && ["fieldSet", "optionalNestedFields"].includes(arg.type);
4370
+ }
4371
+ function injectFormVariables(fn) {
4372
+ return fn({});
4373
+ }
4374
+ function defineConfig(config) {
4375
+ return config;
4376
+ }
4377
+ /**
4378
+ * @experimental
4379
+ */
4380
+ async function runGenerate(filePattern = "src/**/*.cometGen.{ts,tsx}") {
4381
+ const gqlIntrospection = introspectionFromSchema(await loadSchema("./schema.gql", { loaders: [new GraphQLFileLoader()] }));
4382
+ const writtenFiles = [];
4383
+ const files = await glob(filePattern);
4384
+ for (const file of files) {
4385
+ let outputCode = "";
4386
+ let gqlDocumentsOutputCode = "";
4387
+ const targetDirectory = `${dirname(file)}/generated`;
4388
+ const baseOutputFilename = basename(file).replace(/\.cometGen\.tsx?$/, "");
4389
+ console.log(`generating ${file}`);
4390
+ const config = await parseConfig(`${process.cwd()}/${file}`);
4391
+ const codeOuputFilename = `${targetDirectory}/${basename(file.replace(/\.cometGen\.tsx?$/, ""))}.tsx`;
4392
+ await promises.rm(codeOuputFilename, { force: true });
4393
+ const exportName = file.match(/([^/]+)\.cometGen\.tsx?$/)?.[1];
4394
+ if (!exportName) throw new Error("Can not determine exportName");
4395
+ let generated;
4396
+ if (config.type == "form") generated = generateForm({
4397
+ exportName,
4398
+ gqlIntrospection,
4399
+ baseOutputFilename,
4400
+ targetDirectory
4401
+ }, config);
4402
+ else if (config.type == "grid") generated = generateGrid({
4403
+ exportName,
4404
+ gqlIntrospection,
4405
+ baseOutputFilename,
4406
+ targetDirectory
4407
+ }, config);
4408
+ else throw new Error(`Unknown config type`);
4409
+ outputCode += generated.code;
4410
+ for (const queryName in generated.gqlDocuments) {
4411
+ const exportStatement = generated.gqlDocuments[queryName].export ? "export " : "";
4412
+ gqlDocumentsOutputCode += `${exportStatement} const ${queryName} = gql\`${generated.gqlDocuments[queryName].document}\`\n`;
4413
+ }
4414
+ await writeGenerated(codeOuputFilename, outputCode);
4415
+ writtenFiles.push(codeOuputFilename);
4416
+ if (gqlDocumentsOutputCode != "") {
4417
+ const gqlDocumentsOuputFilename = `${targetDirectory}/${basename(file.replace(/\.cometGen\.tsx?$/, ""))}.gql.tsx`;
4418
+ await promises.rm(gqlDocumentsOuputFilename, { force: true });
4419
+ gqlDocumentsOutputCode = `import { gql } from "@apollo/client";
4420
+ import { finalFormFileUploadFragment, finalFormFileUploadDownloadableFragment } from "@comet/cms-admin";
4421
+
4422
+ ${gqlDocumentsOutputCode}
4423
+ `;
4424
+ await writeGenerated(gqlDocumentsOuputFilename, gqlDocumentsOutputCode);
4425
+ writtenFiles.push(gqlDocumentsOuputFilename);
4426
+ }
4427
+ console.log("");
4428
+ }
4429
+ if (writtenFiles.length > 0) {
4430
+ console.log("Formatting generated files...");
4431
+ await exec$1(`./node_modules/.bin/prettier --write ${writtenFiles.join(" ")}`);
4432
+ }
4433
+ }
4434
+ const generateCommand = new Command("generate").option("-f, --file <file>", "path to config file or glob pattern to generate specific files").action(async ({ file: filePattern }) => {
4435
+ console.log("️️️⚠️️️⚠️️️⚠️️️ Admin Generator is still experimental and in beta phase. ⚠️️️⚠️️️⚠️️️\n\n");
4436
+ await runGenerate(filePattern);
4437
+ });
4438
+
4439
+ //#endregion
4440
+ export { defineConfig, injectFormVariables };