@comet/admin-generator 8.0.0-beta.2 → 8.0.0-beta.4

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.
@@ -40,6 +40,7 @@ export type FormFieldConfig<T> = (({
40
40
  multiline?: boolean;
41
41
  } & InputBaseFieldConfig) | ({
42
42
  type: "number";
43
+ decimals?: number;
43
44
  } & InputBaseFieldConfig) | ({
44
45
  type: "numberRange";
45
46
  minValue: number;
@@ -105,11 +106,13 @@ export type FormConfig<T extends {
105
106
  createMutation?: string;
106
107
  fields: (FormFieldConfig<T> | FormLayoutConfig<T> | ComponentFormFieldConfig)[];
107
108
  };
108
- type TabsConfig = {
109
+ type TabsConfig<T extends {
110
+ __typename?: string;
111
+ }> = {
109
112
  type: "tabs";
110
113
  tabs: {
111
114
  name: string;
112
- content: GeneratorConfig;
115
+ content: GeneratorConfig<T>;
113
116
  }[];
114
117
  };
115
118
  type BaseColumnConfig = Pick<GridColDef, "headerName" | "width" | "minWidth" | "maxWidth" | "flex" | "pinned" | "disableExport"> & {
@@ -157,7 +160,7 @@ export type ActionsGridColumnConfig = {
157
160
  export type VirtualGridColumnConfig<T extends GridValidRowModel> = {
158
161
  type: "virtual";
159
162
  name: string;
160
- queryFields?: UsableFields<T>[];
163
+ queryFields?: UsableFields<T, true>[];
161
164
  renderCell: (params: GridRenderCellParams<T, any, any>) => JSX.Element;
162
165
  } & Pick<GridColDef, "sortBy"> & BaseColumnConfig;
163
166
  type InitialFilterConfig = {
@@ -191,7 +194,12 @@ export type GridConfig<T extends {
191
194
  rowActionProp?: boolean;
192
195
  selectionProps?: "multiSelect" | "singleSelect";
193
196
  };
194
- export type GeneratorConfig = FormConfig<any> | GridConfig<any> | TabsConfig;
197
+ export type GeneratorConfig<T extends {
198
+ __typename?: string;
199
+ }> = FormConfig<T> | GridConfig<T> | TabsConfig<T>;
200
+ export declare function defineConfig<T extends {
201
+ __typename?: string;
202
+ }>(config: GeneratorConfig<T>): GeneratorConfig<T>;
195
203
  type GQLDocumentConfig = {
196
204
  document: string;
197
205
  export: boolean;
@@ -12,6 +12,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.generateCommand = void 0;
13
13
  exports.isFormFieldConfig = isFormFieldConfig;
14
14
  exports.isFormLayoutConfig = isFormLayoutConfig;
15
+ exports.defineConfig = defineConfig;
15
16
  const graphql_file_loader_1 = require("@graphql-tools/graphql-file-loader");
16
17
  const load_1 = require("@graphql-tools/load");
17
18
  const commander_1 = require("commander");
@@ -29,11 +30,15 @@ function isFormFieldConfig(arg) {
29
30
  function isFormLayoutConfig(arg) {
30
31
  return arg.type !== undefined && ["fieldSet", "optionalNestedFields"].includes(arg.type);
31
32
  }
33
+ function defineConfig(config) {
34
+ return config;
35
+ }
32
36
  /**
33
37
  * @experimental
34
38
  */
35
39
  function runGenerate() {
36
40
  return __awaiter(this, arguments, void 0, function* (filePattern = "src/**/*.cometGen.{ts,tsx}") {
41
+ var _a;
37
42
  const schema = yield (0, load_1.loadSchema)("./schema.gql", {
38
43
  loaders: [new graphql_file_loader_1.GraphQLFileLoader()],
39
44
  });
@@ -44,28 +49,28 @@ function runGenerate() {
44
49
  let gqlDocumentsOutputCode = "";
45
50
  const targetDirectory = `${(0, path_1.dirname)(file)}/generated`;
46
51
  const baseOutputFilename = (0, path_1.basename)(file).replace(/\.cometGen\.tsx?$/, "");
47
- const configs = (0, tsMorphHelper_1.configsFromSourceFile)((0, tsMorphHelper_1.morphTsSource)(file));
52
+ console.log(`generating ${file}`);
53
+ const config = (0, tsMorphHelper_1.configFromSourceFile)((0, tsMorphHelper_1.morphTsSource)(file));
54
+ const exportName = (_a = file.match(/([^/]+)\.cometGen\.tsx?$/)) === null || _a === void 0 ? void 0 : _a[1];
55
+ if (!exportName)
56
+ throw new Error("Can not determine exportName");
48
57
  //const configs = await import(`${process.cwd()}/${file.replace(/\.ts$/, "")}`);
49
58
  const codeOuputFilename = `${targetDirectory}/${(0, path_1.basename)(file.replace(/\.cometGen\.tsx?$/, ""))}.tsx`;
50
59
  yield fs_1.promises.rm(codeOuputFilename, { force: true });
51
- console.log(`generating ${file}`);
52
- for (const exportName in configs) {
53
- const config = configs[exportName];
54
- let generated;
55
- if (config.type == "form") {
56
- generated = (0, generateForm_1.generateForm)({ exportName, gqlIntrospection, baseOutputFilename, targetDirectory }, config);
57
- }
58
- else if (config.type == "grid") {
59
- generated = (0, generateGrid_1.generateGrid)({ exportName, gqlIntrospection, baseOutputFilename, targetDirectory }, config);
60
- }
61
- else {
62
- throw new Error(`Unknown config type: ${config.type}`);
63
- }
64
- outputCode += generated.code;
65
- for (const queryName in generated.gqlDocuments) {
66
- const exportStatement = generated.gqlDocuments[queryName].export ? "export " : "";
67
- gqlDocumentsOutputCode += `${exportStatement} const ${queryName} = gql\`${generated.gqlDocuments[queryName].document}\`\n`;
68
- }
60
+ let generated;
61
+ if (config.type == "form") {
62
+ generated = (0, generateForm_1.generateForm)({ exportName, gqlIntrospection, baseOutputFilename, targetDirectory }, config);
63
+ }
64
+ else if (config.type == "grid") {
65
+ generated = (0, generateGrid_1.generateGrid)({ exportName, gqlIntrospection, baseOutputFilename, targetDirectory }, config);
66
+ }
67
+ else {
68
+ throw new Error(`Unknown config type: ${config.type}`);
69
+ }
70
+ outputCode += generated.code;
71
+ for (const queryName in generated.gqlDocuments) {
72
+ const exportStatement = generated.gqlDocuments[queryName].export ? "export " : "";
73
+ gqlDocumentsOutputCode += `${exportStatement} const ${queryName} = gql\`${generated.gqlDocuments[queryName].document}\`\n`;
69
74
  }
70
75
  yield (0, writeGenerated_1.writeGenerated)(codeOuputFilename, outputCode);
71
76
  if (gqlDocumentsOutputCode != "") {
@@ -260,6 +260,7 @@ config) {
260
260
  FinalFormSelect,
261
261
  FinalFormSubmitEvent,
262
262
  Loading,
263
+ NumberField,
263
264
  RadioGroupField,
264
265
  TextAreaField,
265
266
  TextField,
@@ -158,18 +158,20 @@ function generateFormField({ gqlIntrospection, baseOutputFilename, config, formC
158
158
  : ""}
159
159
  ${validateCode}
160
160
  />`;
161
+ if (!config.virtual && !required && !config.readOnly) {
162
+ formValueToGqlInputCode = `${name}: formValues.${name} ?? "",`;
163
+ }
161
164
  }
162
165
  else if (config.type == "number") {
163
166
  code = `
164
- <Field
167
+ <NumberField
165
168
  ${required ? "required" : ""}
166
169
  ${config.readOnly ? readOnlyPropsWithLock : ""}
167
170
  variant="horizontal"
168
171
  fullWidth
169
172
  name="${nameWithPrefix}"
170
- component={FinalFormInput}
171
- type="number"
172
173
  label={${fieldLabel}}
174
+ ${config.decimals ? `decimals={${config.decimals}}` : ""}
173
175
  ${config.startAdornment ? `startAdornment={<InputAdornment position="start">${startAdornment.adornmentString}</InputAdornment>}` : ""}
174
176
  ${config.endAdornment ? `endAdornment={<InputAdornment position="end">${endAdornment.adornmentString}</InputAdornment>}` : ""}
175
177
  ${config.helperText
@@ -462,7 +464,14 @@ function generateFormField({ gqlIntrospection, baseOutputFilename, config, formC
462
464
  imports.push({ name: "OnChangeField", importPath: "@comet/admin" });
463
465
  finalFormConfig = { subscription: { values: true }, renderProps: { values: true, form: true } };
464
466
  }
465
- formValueToGqlInputCode = !config.virtual ? `${name}: formValues.${name}?.id,` : ``;
467
+ if (!config.virtual) {
468
+ if (!required) {
469
+ formValueToGqlInputCode = `${name}: formValues.${name} ? formValues.${name}.id : null,`;
470
+ }
471
+ else {
472
+ formValueToGqlInputCode = `${name}: formValues.${name}?.id,`;
473
+ }
474
+ }
466
475
  imports.push({
467
476
  name: `GQL${queryName}Query`,
468
477
  importPath: `./${baseOutputFilename}.generated`,
@@ -487,9 +487,7 @@ function generateGrid({ exportName, baseOutputFilename, targetDirectory, gqlIntr
487
487
  muiGridFilterToGql,
488
488
  muiGridSortToGql,
489
489
  StackLink,
490
- ToolbarActions,
491
490
  FillSpace,
492
- ToolbarItem,
493
491
  Tooltip,
494
492
  useBufferedRowCount,
495
493
  useDataGridExcelExport,
@@ -9,8 +9,8 @@ const generateGridToolbar = ({ componentName, forwardToolbarAction, hasSearch, h
9
9
  function ${componentName}(${getGridToolbarProps(componentName, !!forwardToolbarAction, !!excelExport)}) {
10
10
  return (
11
11
  <DataGridToolbar>
12
- ${hasSearch ? searchItem : ""}
13
- ${hasFilter ? filterItem : ""}
12
+ ${hasSearch ? "<GridToolbarQuickFilter />" : ""}
13
+ ${hasFilter ? "<GridFilterButton />" : ""}
14
14
  <FillSpace />
15
15
  ${renderToolbarActions({
16
16
  forwardToolbarAction,
@@ -44,12 +44,6 @@ const getGridToolbarProps = (componentName, toolbarAction, exportApi) => {
44
44
  ${props.map((prop) => `${prop.destructured}`).join(",")}
45
45
  }: ${componentName}ToolbarProps`;
46
46
  };
47
- const searchItem = `<ToolbarItem>
48
- <GridToolbarQuickFilter />
49
- </ToolbarItem>`;
50
- const filterItem = `<ToolbarItem>
51
- <GridFilterButton />
52
- </ToolbarItem>`;
53
47
  const renderToolbarActions = ({ forwardToolbarAction, addItemText, excelExport, allowAdding }) => {
54
48
  const showMoreActionsMenu = excelExport;
55
49
  if (!showMoreActionsMenu && !allowAdding) {
@@ -76,10 +70,9 @@ const renderToolbarActions = ({ forwardToolbarAction, addItemText, excelExport,
76
70
  ${addItemText}
77
71
  </Button>`;
78
72
  const addAction = forwardToolbarAction ? "{toolbarAction}" : defaultAddItemButton;
79
- return `<ToolbarActions>
73
+ return `
80
74
  ${showMoreActionsMenu ? moreActionsMenu : ""}
81
- ${allowAdding ? addAction : ""}
82
- </ToolbarActions>`;
75
+ ${allowAdding ? addAction : ""}`;
83
76
  };
84
77
  const renderToolbarProps = (componentName, forwardToolbarAction, exportApi) => {
85
78
  if (forwardToolbarAction || exportApi) {
@@ -1,8 +1,9 @@
1
- type GqlLeaves<T> = T extends any ? "__typename" extends keyof T ? {
2
- [K in keyof T as K extends "__typename" ? never : K]-?: GqlLeaves<T[K]>;
1
+ type Prev = [never, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
2
+ type GqlLeaves<T, FollowArrays extends boolean = false, Depth extends number = 5> = [Depth] extends [never] ? never : T extends any ? T extends Array<infer ArrayType> ? FollowArrays extends true ? GqlLeaves<ArrayType, FollowArrays, Prev[Depth]> : never : "__typename" extends keyof T ? {
3
+ [K in keyof T as K extends "__typename" ? never : K]-?: GqlLeaves<T[K], FollowArrays, Prev[Depth]>;
3
4
  } : never : never;
4
5
  type FieldNames<T> = {
5
6
  [K in keyof T]: `${Exclude<K, symbol>}${FieldNames<T[K]> extends never ? "" : `.${FieldNames<T[K]>}`}`;
6
7
  }[keyof T];
7
- export type UsableFields<T> = FieldNames<GqlLeaves<T>>;
8
+ export type UsableFields<T, FollowArrays extends boolean = false> = FieldNames<GqlLeaves<T, FollowArrays>>;
8
9
  export {};
@@ -1,2 +1,3 @@
1
1
  "use strict";
2
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
3
  Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,4 +1,4 @@
1
1
  import { type SourceFile } from "ts-morph";
2
2
  import { type GeneratorConfig } from "../generate-command";
3
3
  export declare function morphTsSource(path: string): SourceFile;
4
- export declare function configsFromSourceFile(sourceFile: SourceFile): Record<string, GeneratorConfig>;
4
+ export declare function configFromSourceFile(sourceFile: SourceFile): GeneratorConfig<any>;
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.morphTsSource = morphTsSource;
4
- exports.configsFromSourceFile = configsFromSourceFile;
4
+ exports.configFromSourceFile = configFromSourceFile;
5
5
  const ts_morph_1 = require("ts-morph");
6
6
  const project = new ts_morph_1.Project({
7
7
  tsConfigFilePath: "tsconfig.json",
@@ -29,18 +29,22 @@ const supportedInlineCodePaths = [
29
29
  //support in up to 5 levels of nested fields (eg. fieldSet)
30
30
  ...Array.from(Array(5).keys()).map((i) => `[type=form]${".fields".repeat(i + 1)}.validate`),
31
31
  ];
32
- function configsFromSourceFile(sourceFile) {
33
- const configs = {}; //GeneratorConfig is not fully correct (runtime vs config mismatch), we work around that using type guards
32
+ function configFromSourceFile(sourceFile) {
34
33
  for (const [name, declarations] of Array.from(sourceFile.getExportedDeclarations().entries())) {
35
- //console.log(name);
36
- if (declarations.length != 1) {
37
- throw new Error(`Expected exactly one declaration for ${name}`);
34
+ if (name == "default") {
35
+ if (declarations.length != 1) {
36
+ throw new Error(`Expected exactly one declaration for ${name}`);
37
+ }
38
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
39
+ const config = exportedDeclarationToJson(declarations[0]);
40
+ //console.dir(config, { depth: 10 });
41
+ return config;
42
+ }
43
+ else {
44
+ //ignore this export
38
45
  }
39
- const config = exportedDeclarationToJson(declarations[0]);
40
- //console.dir(config, { depth: 10 });
41
- configs[name] = config;
42
46
  }
43
- return configs;
47
+ throw new Error(`No default export found, please export the GeneratorConfig as default, preferrable using defineConfig helper.`);
44
48
  }
45
49
  function findUsedImports(node) {
46
50
  const imports = [];
@@ -80,7 +84,7 @@ function getTypePropertyFromObjectLiteral(node) {
80
84
  return null;
81
85
  }
82
86
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
83
- function astExpressionToJson(node, path) {
87
+ function astNodeToJson(node, path) {
84
88
  var _a;
85
89
  if (node.getKind() == ts_morph_1.SyntaxKind.ObjectLiteralExpression) {
86
90
  if (path == "") {
@@ -94,7 +98,7 @@ function astExpressionToJson(node, path) {
94
98
  const propertyAssignment = property;
95
99
  const propertyAssignmentInitializer = propertyAssignment.getInitializer();
96
100
  if (propertyAssignmentInitializer) {
97
- ret[propertyAssignment.getName()] = astExpressionToJson(propertyAssignmentInitializer, `${path}.${propertyAssignment.getName()}`);
101
+ ret[propertyAssignment.getName()] = astNodeToJson(propertyAssignmentInitializer, `${path}.${propertyAssignment.getName()}`);
98
102
  }
99
103
  else {
100
104
  throw new Error(`Initializer is required for propertyAssignment '${propertyAssignment.getName()}'`);
@@ -137,7 +141,7 @@ function astExpressionToJson(node, path) {
137
141
  else if (node.getKind() == ts_morph_1.SyntaxKind.ArrayLiteralExpression) {
138
142
  const ret = [];
139
143
  for (const element of node.getElements()) {
140
- ret.push(astExpressionToJson(element, path));
144
+ ret.push(astNodeToJson(element, path));
141
145
  }
142
146
  return ret;
143
147
  }
@@ -166,7 +170,7 @@ function astExpressionToJson(node, path) {
166
170
  if (variableDeclaration.getName() == node.getText()) {
167
171
  const variableInitializer = variableDeclaration.getInitializer();
168
172
  if (variableInitializer) {
169
- return astExpressionToJson(variableInitializer, path);
173
+ return astNodeToJson(variableInitializer, path);
170
174
  }
171
175
  else {
172
176
  throw new Error(`Initializer is required for variableDeclaration '${variableDeclaration.getName()}'`);
@@ -187,12 +191,25 @@ function exportedDeclarationToJson(node) {
187
191
  const variableDeclaration = node;
188
192
  const initializer = variableDeclaration.getInitializer();
189
193
  if (initializer) {
190
- return astExpressionToJson(initializer, "");
194
+ return astNodeToJson(initializer, "");
191
195
  }
192
196
  else {
193
197
  throw new Error(`Initializer is required for variableDeclaration '${variableDeclaration.getName()}'`);
194
198
  }
195
199
  }
200
+ else if (node.getKind() == ts_morph_1.SyntaxKind.CallExpression) {
201
+ const callExpression = node;
202
+ if (callExpression.getExpression().getText() == "defineConfig") {
203
+ const args = callExpression.getArguments();
204
+ if (args.length != 1) {
205
+ throw new Error(`Expected exactly one argument for defineConfig`);
206
+ }
207
+ return astNodeToJson(args[0], "");
208
+ }
209
+ else {
210
+ throw new Error(`Only direct call to defineConfig is supported`);
211
+ }
212
+ }
196
213
  else {
197
214
  throw new Error(`Unsupported declaration kind '${node.getKindName()}'`);
198
215
  }
package/lib/index.d.ts CHANGED
@@ -1 +1,2 @@
1
1
  export type { FormConfig, FormFieldConfig, GeneratorConfig, GridColumnConfig, GridConfig } from "./commands/generate/generate-command";
2
+ export { defineConfig } from "./commands/generate/generate-command";
package/lib/index.js CHANGED
@@ -1,2 +1,5 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.defineConfig = void 0;
4
+ var generate_command_1 = require("./commands/generate/generate-command");
5
+ Object.defineProperty(exports, "defineConfig", { enumerable: true, get: function () { return generate_command_1.defineConfig; } });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@comet/admin-generator",
3
- "version": "8.0.0-beta.2",
3
+ "version": "8.0.0-beta.4",
4
4
  "repository": {
5
5
  "directory": "packages/admin/admin-generator",
6
6
  "type": "git",
@@ -30,27 +30,27 @@
30
30
  "ts-node": "^10.9.2"
31
31
  },
32
32
  "devDependencies": {
33
- "@mui/material": "^6.4.8",
34
- "@mui/x-data-grid": "^7.27.3",
33
+ "@mui/material": "^7.0.0",
34
+ "@mui/x-data-grid": "^7.28.1",
35
35
  "@types/jest": "^29.5.14",
36
- "@types/node": "^22.13.10",
36
+ "@types/node": "^22.14.0",
37
37
  "@types/object-path": "^0.11.4",
38
38
  "@types/pluralize": "^0.0.33",
39
- "@types/react": "^18.3.18",
39
+ "@types/react": "^18.3.20",
40
40
  "eslint": "^9.22.0",
41
41
  "final-form": "^4.20.10",
42
42
  "jest": "^29.7.0",
43
43
  "npm-run-all2": "^5.0.2",
44
44
  "prettier": "^3.5.3",
45
45
  "react": "^18.3.1",
46
- "react-intl": "^7.1.6",
46
+ "react-intl": "^7.1.10",
47
47
  "rimraf": "^6.0.1",
48
48
  "ts-jest": "^29.2.6",
49
49
  "typescript": "^5.7.3",
50
- "@comet/admin": "8.0.0-beta.2",
51
- "@comet/admin-icons": "8.0.0-beta.2",
52
- "@comet/cms-admin": "8.0.0-beta.2",
53
- "@comet/eslint-config": "8.0.0-beta.2"
50
+ "@comet/admin": "8.0.0-beta.4",
51
+ "@comet/admin-icons": "8.0.0-beta.4",
52
+ "@comet/cms-admin": "8.0.0-beta.4",
53
+ "@comet/eslint-config": "8.0.0-beta.4"
54
54
  },
55
55
  "engines": {
56
56
  "node": ">=22.0.0"