@gadmin2n/prisma-react-generator 0.0.35

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 (37) hide show
  1. package/LICENSE +177 -0
  2. package/README.md +1 -0
  3. package/dist/cli.d.ts +2 -0
  4. package/dist/cli.js +4 -0
  5. package/dist/generator/field-classifiers.d.ts +13 -0
  6. package/dist/generator/field-classifiers.js +45 -0
  7. package/dist/generator/generate-config-props.d.ts +21 -0
  8. package/dist/generator/generate-config-props.js +198 -0
  9. package/dist/generator/generate-create-page.d.ts +13 -0
  10. package/dist/generator/generate-create-page.js +129 -0
  11. package/dist/generator/generate-edit-page.d.ts +13 -0
  12. package/dist/generator/generate-edit-page.js +138 -0
  13. package/dist/generator/generate-index-page.d.ts +13 -0
  14. package/dist/generator/generate-index-page.js +16 -0
  15. package/dist/generator/generate-list-page.d.ts +13 -0
  16. package/dist/generator/generate-list-page.js +262 -0
  17. package/dist/generator/generate-model-props.d.ts +14 -0
  18. package/dist/generator/generate-model-props.js +78 -0
  19. package/dist/generator/generate-models-index.d.ts +9 -0
  20. package/dist/generator/generate-models-index.js +19 -0
  21. package/dist/generator/generate-resources.d.ts +8 -0
  22. package/dist/generator/generate-resources.js +33 -0
  23. package/dist/generator/generate-show-page.d.ts +13 -0
  24. package/dist/generator/generate-show-page.js +71 -0
  25. package/dist/generator/generate-ui-config.d.ts +2 -0
  26. package/dist/generator/generate-ui-config.js +354 -0
  27. package/dist/generator/helpers.d.ts +55 -0
  28. package/dist/generator/helpers.js +356 -0
  29. package/dist/generator/index.d.ts +9 -0
  30. package/dist/generator/index.js +131 -0
  31. package/dist/generator/template-helpers.d.ts +27 -0
  32. package/dist/generator/template-helpers.js +78 -0
  33. package/dist/generator/types.d.ts +27 -0
  34. package/dist/generator/types.js +2 -0
  35. package/dist/index.d.ts +3 -0
  36. package/dist/index.js +53 -0
  37. package/package.json +79 -0
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generatePageShow = void 0;
4
+ const case_1 = require("case");
5
+ const fs = require("fs");
6
+ const generatePageShow = ({ model, templateHelpers: t, uiConfig, allModels, }) => {
7
+ const instanceName = (0, case_1.camel)(model.name);
8
+ return `
9
+ import { ModelType, getColumns, produceModel } from "@gadmin2/react-common";
10
+ import { CloneButton, DeleteButton, EditButton, ListButton, RefreshButton, Show } from "@refinedev/antd";
11
+ import { IResourceComponentsProps, useShow, useTranslate } from "@refinedev/core";
12
+ import React, { useState } from "react";
13
+ import { getShowField } from "../../helpers";
14
+ import type { ${model.name} } from "../../generated/types/prisma.types"; //'.prisma/client/index';
15
+ import {
16
+ ${instanceName}ShowConfig as showConfig,
17
+ ${instanceName}ShowPrismaSelect as showPrismaSelect,
18
+ } from "../../generated/props/${instanceName}/config";
19
+ import { ${instanceName}Model } from "../../generated/props/${instanceName}/model";
20
+ import { modelsMap } from "generated/models.index";
21
+
22
+ export const ${model.name}Show: React.FC<IResourceComponentsProps> = () => {
23
+ const resourceName = "${instanceName}";
24
+ const t = useTranslate();
25
+
26
+ const { queryResult } = useShow<${model.name}>({
27
+ meta: { select: showPrismaSelect},
28
+ });
29
+ const { data, isLoading } = queryResult;
30
+ const record = data?.data;
31
+
32
+ const [[fields, model]] = useState(() => {
33
+ const model: ModelType = produceModel(${instanceName}Model, {
34
+ // status: { render: xxxxx }
35
+ });
36
+
37
+ // getColumns is a function that returns an array of fields
38
+ const fields = getColumns("${model.name}", showConfig.fields, {
39
+ ...modelsMap,
40
+ ${model.name}: { model, meta: modelsMap["${model.name}"].meta },
41
+ });
42
+
43
+ return [fields, model] as const;
44
+ });
45
+
46
+ return (
47
+ <Show
48
+ isLoading={isLoading}
49
+ headerButtons={
50
+ <>
51
+ <ListButton/>
52
+ <EditButton recordItemId={record?.id} />
53
+ <CloneButton recordItemId={record?.id} />
54
+ <DeleteButton recordItemId={record?.id} />
55
+ <RefreshButton
56
+ recordItemId={record?.id}
57
+ meta={{ select: showPrismaSelect}}
58
+ />
59
+ </>
60
+ }
61
+ >
62
+ {fields.map((field: any) => {
63
+ return getShowField(field, resourceName, record, t, model, modelsMap);
64
+ })}
65
+ </Show>
66
+ );
67
+ };
68
+
69
+ `;
70
+ };
71
+ exports.generatePageShow = generatePageShow;
@@ -0,0 +1,2 @@
1
+ import { DMMF } from '@prisma/generator-helper';
2
+ export declare function addNewModelsConfig(allModels: DMMF.Model[], enums?: DMMF.SchemaEnum[]): any;
@@ -0,0 +1,354 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.addNewModelsConfig = void 0;
27
+ const ts = __importStar(require("ts-morph"));
28
+ const shell = __importStar(require("shelljs"));
29
+ const case_1 = require("case");
30
+ const helpers_1 = require("./helpers");
31
+ const path = __importStar(require("path"));
32
+ const fs = require('fs');
33
+ function detectConfigMode() {
34
+ const hasConfigFile = fs.existsSync('../config/ui.config.ts');
35
+ const hasConfigDir = fs.existsSync('../config/ui') && fs.statSync('../config/ui').isDirectory();
36
+ if (hasConfigDir) {
37
+ return 'directory';
38
+ }
39
+ if (hasConfigFile) {
40
+ return 'file';
41
+ }
42
+ return 'none';
43
+ }
44
+ function loadConfigFromDirectory(allModels, enums = []) {
45
+ console.log('Loading UI config from directory mode (config/ui/) ...');
46
+ const configDir = '../config/ui';
47
+ const configDirAbs = path.resolve(configDir);
48
+ const configFiles = fs.readdirSync(configDir)
49
+ .filter((file) => file.endsWith('.ts') && !file.endsWith('.d.ts'));
50
+ if (configFiles.length === 0) {
51
+ throw new Error('No .ts config files found in config/ui/ directory');
52
+ }
53
+ const existingModelNames = new Set();
54
+ const tsProject = new ts.Project({
55
+ manipulationSettings: {
56
+ indentationText: ts.IndentationText.TwoSpaces,
57
+ },
58
+ });
59
+ configFiles.forEach((file) => {
60
+ const filePath = path.join(configDir, file);
61
+ try {
62
+ const sourceFile = tsProject.addSourceFileAtPath(filePath);
63
+ sourceFile.getVariableDeclarations().forEach((varDecl) => {
64
+ if (varDecl.isExported()) {
65
+ const name = varDecl.getName();
66
+ if (!['pageActions', 'PAGE_SIZE', 'modelsConfig'].includes(name)) {
67
+ existingModelNames.add(name);
68
+ }
69
+ }
70
+ });
71
+ }
72
+ catch (e) {
73
+ console.log(`Warning: Failed to parse ${file}: ${e.message}`);
74
+ }
75
+ });
76
+ const newModels = allModels.filter((model) => !existingModelNames.has(model.name));
77
+ newModels.forEach((model) => {
78
+ const configContent = generateModelConfigFile(model, enums);
79
+ const filePath = path.join(configDir, `${model.name}.ts`);
80
+ fs.writeFileSync(filePath, configContent);
81
+ console.log(`Created new config file: config/ui/${model.name}.ts`);
82
+ });
83
+ console.log('Compile UI config files ...');
84
+ const { code } = shell.cd(configDirAbs).exec('tsc *.ts --moduleResolution node --esModuleInterop');
85
+ if (code !== 0) {
86
+ shell.cd('../../server');
87
+ process.exit(code);
88
+ }
89
+ const modelsConfig = {};
90
+ let pageActions = null;
91
+ let PAGE_SIZE = 10;
92
+ const jsFiles = fs.readdirSync('.')
93
+ .filter((file) => file.endsWith('.js') && !file.startsWith('_'));
94
+ const commonJsPath = path.join(configDirAbs, '_common.js');
95
+ if (fs.existsSync(commonJsPath)) {
96
+ delete require.cache[require.resolve(commonJsPath)];
97
+ const commonModule = require(commonJsPath);
98
+ if (commonModule.pageActions) {
99
+ pageActions = commonModule.pageActions;
100
+ }
101
+ if (commonModule.PAGE_SIZE) {
102
+ PAGE_SIZE = commonModule.PAGE_SIZE;
103
+ }
104
+ }
105
+ jsFiles.forEach((file) => {
106
+ const jsFilePath = path.join(configDirAbs, file);
107
+ delete require.cache[require.resolve(jsFilePath)];
108
+ const moduleExports = require(jsFilePath);
109
+ Object.keys(moduleExports).forEach((key) => {
110
+ if (key === 'pageActions') {
111
+ pageActions = moduleExports[key];
112
+ }
113
+ else if (key === 'PAGE_SIZE') {
114
+ PAGE_SIZE = moduleExports[key];
115
+ }
116
+ else if (key !== 'modelsConfig' && key !== 'default') {
117
+ modelsConfig[key] = moduleExports[key];
118
+ }
119
+ });
120
+ });
121
+ shell.rm('-rf', '*.js');
122
+ shell.cd('../../server');
123
+ if (!pageActions) {
124
+ pageActions = {
125
+ hasDetailPage: true,
126
+ editOnNewPage: true,
127
+ detailOnNewPage: true,
128
+ createOnNewPage: true,
129
+ };
130
+ }
131
+ return {
132
+ modelsConfig,
133
+ pageActions,
134
+ PAGE_SIZE,
135
+ };
136
+ }
137
+ function loadConfigFromFile(allModels, enums = []) {
138
+ console.log('Loading UI config from file mode (config/ui.config.ts) ...');
139
+ const tsProject = new ts.Project({
140
+ manipulationSettings: {
141
+ indentationText: ts.IndentationText.TwoSpaces,
142
+ },
143
+ });
144
+ const tsFile = tsProject.addSourceFileAtPath('../config/ui.config.ts');
145
+ try {
146
+ const modelsConfig = tsFile
147
+ .getVariableDeclarationOrThrow('modelsConfig')
148
+ .getInitializerIfKindOrThrow(ts.SyntaxKind.ObjectLiteralExpression);
149
+ const tableNames = modelsConfig
150
+ .getProperties()
151
+ .map((p) => p.asKindOrThrow(ts.SyntaxKind.PropertyAssignment).getName());
152
+ allModels
153
+ .filter((model) => !tableNames.includes(model.name))
154
+ .forEach((model) => {
155
+ modelsConfig.addPropertyAssignment({
156
+ name: model.name,
157
+ initializer: getModelConfigStruct(model, enums),
158
+ });
159
+ });
160
+ tsFile.saveSync();
161
+ }
162
+ catch (e) {
163
+ console.log('Add new models config to ui.config.ts error:', e.message);
164
+ }
165
+ const uiConfig = (function (exports = {}) {
166
+ console.log('Compile ui.config.ts ...');
167
+ const { code } = shell.cd('../config/').exec('tsc ui.config.ts');
168
+ if (code !== 0) {
169
+ process.exit(code);
170
+ }
171
+ const data = fs.readFileSync('ui.config.js');
172
+ eval(data.toString());
173
+ shell.rm('-rf', 'ui.config.js');
174
+ shell.cd('../server');
175
+ return exports;
176
+ })();
177
+ return uiConfig;
178
+ }
179
+ function generateModelConfigFile(model, enums = []) {
180
+ return `import { ModelConfig } from "../.types";
181
+ import { pageActions, PAGE_SIZE } from "./_common";
182
+
183
+ export const ${model.name}: ModelConfig = ${getModelConfigStruct(model, enums)};
184
+ `;
185
+ }
186
+ function initializeConfigDirectory(allModels, enums = []) {
187
+ console.log('No UI config found. Creating config/ui/ directory with default configs ...');
188
+ const configDir = '../config/ui';
189
+ if (!fs.existsSync(configDir)) {
190
+ fs.mkdirSync(configDir, { recursive: true });
191
+ }
192
+ const commonConfigContent = `import { PageActions } from "../.types";
193
+
194
+ /**
195
+ * 默认分页大小
196
+ */
197
+ export const PAGE_SIZE = 10;
198
+
199
+ /**
200
+ * 全局页面行为配置
201
+ */
202
+ export const pageActions: PageActions = {
203
+ hasDetailPage: true,
204
+ editOnNewPage: true,
205
+ detailOnNewPage: true,
206
+ createOnNewPage: true,
207
+ };
208
+ `;
209
+ fs.writeFileSync(path.join(configDir, '_common.ts'), commonConfigContent);
210
+ console.log('Created: config/ui/_common.ts');
211
+ allModels.forEach((model) => {
212
+ const configContent = generateModelConfigFile(model, enums);
213
+ const filePath = path.join(configDir, `${model.name}.ts`);
214
+ fs.writeFileSync(filePath, configContent);
215
+ console.log(`Created: config/ui/${model.name}.ts`);
216
+ });
217
+ return loadConfigFromDirectory(allModels, enums);
218
+ }
219
+ function addNewModelsConfig(allModels, enums = []) {
220
+ const configMode = detectConfigMode();
221
+ if (configMode === 'none') {
222
+ return initializeConfigDirectory(allModels, enums);
223
+ }
224
+ else if (configMode === 'directory') {
225
+ return loadConfigFromDirectory(allModels, enums);
226
+ }
227
+ else {
228
+ return loadConfigFromFile(allModels, enums);
229
+ }
230
+ }
231
+ exports.addNewModelsConfig = addNewModelsConfig;
232
+ function getModelConfigStruct(model, enums = []) {
233
+ const relationFields = model.fields
234
+ .filter((field) => field.kind === 'object' && !field.isList)
235
+ .map((field) => field.name);
236
+ const relationsFields = model.fields
237
+ .filter((field) => field.kind === 'object' && field.isList)
238
+ .map((field) => field.name);
239
+ const enumFields = model.fields
240
+ .filter((field) => (0, helpers_1.isEnumField)(field))
241
+ .map((field) => field.name);
242
+ const searchFields = model.fields
243
+ .filter((field) => ['id', 'title', 'name'].includes(field.name) &&
244
+ !relationFields.includes(field.name) &&
245
+ !relationsFields.includes(field.name) &&
246
+ !enumFields.includes(field.name))
247
+ .map((field) => field.name);
248
+ const editableFields = [...relationFields, ...relationsFields].reduce((acc, cur) => {
249
+ acc.push(`!${cur}.*`);
250
+ return acc;
251
+ }, ['*', '!creator', '!createdAt', '!updatedAt']);
252
+ const textFieldsExclude = model.fields
253
+ .filter((field) => {
254
+ const { formItem: { type }, } = (0, helpers_1.parseDocumentation)(field.documentation || '', field);
255
+ return ['Text', 'Html', 'File', 'Markdown'].includes(type);
256
+ })
257
+ .map((field) => `!${field.name}`);
258
+ const tableFileds = relationsFields
259
+ .reduce((acc, cur) => {
260
+ acc.push(`!${cur}.*`);
261
+ acc.push(`_count.${cur}`);
262
+ return acc;
263
+ }, ['*', '!createdAt', ...textFieldsExclude])
264
+ .concat(relationFields.reduce((acc, cur) => {
265
+ acc.push(`!${cur}.*`);
266
+ acc.push(`${cur}`);
267
+ return acc;
268
+ }, []));
269
+ const showFields = tableFileds.filter((fieldName) => !textFieldsExclude.includes(fieldName));
270
+ function getFirstEnumChangeStatusStr() {
271
+ const enumField = model.fields.find((field) => field.kind === 'enum');
272
+ if (enumField) {
273
+ const enumInfo = enums.find((item) => item.name === enumField.type);
274
+ if (enumInfo) {
275
+ return `{
276
+ action: "CHANGE_STATUS",
277
+ desc: "${(0, case_1.title)(enumInfo.values[0])}",
278
+ values: {"${enumField.name}": "${enumInfo.values[0]}"},
279
+ },`;
280
+ }
281
+ }
282
+ return '';
283
+ }
284
+ return `
285
+ {
286
+ metadata: {
287
+ nameKeys: ["${searchFields.find((name) => ['name', 'title'].includes(name)) || 'id'}"],
288
+ pageActions,
289
+ },
290
+ table: {
291
+ toolbar: {
292
+ searchBar: {
293
+ fields: ${JSON.stringify(searchFields)},
294
+ containsFields: ${JSON.stringify(searchFields.filter((field) => field !== 'id'))},
295
+ placeholder: ${JSON.stringify(searchFields.join(','))},
296
+ },
297
+ actions: [
298
+ {action: 'REFRESH', desc: 'Refresh'},
299
+ {action: 'SETTING', desc: 'Setting'},
300
+ {
301
+ action: "EXPORT",
302
+ desc: 'export',
303
+ fields: ${JSON.stringify(tableFileds)}
304
+ },
305
+ ],
306
+ },
307
+ header: {
308
+ filter: ${JSON.stringify(model.fields
309
+ .filter((field) => enumFields.includes(field.name) ||
310
+ (field.kind === 'object' && !field.isList))
311
+ .map((field) => field.name))},
312
+ sorter: ${JSON.stringify(['id'].concat(enumFields))},
313
+ },
314
+ fields: ${JSON.stringify(tableFileds)},
315
+ rowSelection: {
316
+ actions: [
317
+ {action: 'INSERT', desc: 'Insert'},
318
+ ${getFirstEnumChangeStatusStr()}
319
+ {action: 'DELETE', desc: 'Delete'},
320
+ {action: 'EXPORT', desc: 'Export'},
321
+ ],
322
+ },
323
+ rowActions: {
324
+ visibleNum: 2,
325
+ actions: [
326
+ {
327
+ action: "EDIT",
328
+ desc: "Edit",
329
+ },
330
+ ${getFirstEnumChangeStatusStr()}
331
+ {action: "DELETE", desc: 'Delete'}
332
+ ],
333
+ },
334
+ params: {
335
+ pageSize: PAGE_SIZE,
336
+ },
337
+ },
338
+ form: {
339
+ fields: ${JSON.stringify(editableFields)},
340
+ reaction: {
341
+ id: {
342
+ toggle: [],
343
+ defaultProps: {
344
+ hidden: true,
345
+ },
346
+ },
347
+ },
348
+ },
349
+ show: {
350
+ fields: ${JSON.stringify(showFields)},
351
+ },
352
+ }
353
+ `;
354
+ }
@@ -0,0 +1,55 @@
1
+ import type { DMMF } from '@prisma/generator-helper';
2
+ import type { ImportStatementParams, ParsedField } from './types';
3
+ export declare type GlobType = 'read' | 'write';
4
+ export declare const uniq: <T = any>(input: T[]) => T[];
5
+ export declare const concatIntoArray: <T = any>(source: T[], target: T[]) => void;
6
+ export declare function isGameAngle(model: DMMF.Model): boolean | undefined;
7
+ export declare function omit(obj: Record<string, any>, fields: string[]): Record<string, any>;
8
+ export declare function pick(obj: Record<string, any>, fields: string[]): Record<string, any>;
9
+ export declare function isObject(item: any): any;
10
+ export declare function flattenObj(obj: Record<string, any>): {};
11
+ export declare const makeImportsFromPrismaClient: (fields: ParsedField[]) => ImportStatementParams | null;
12
+ export declare const mapDMMFToParsedField: (field: DMMF.Field, overrides?: Partial<DMMF.Field>) => ParsedField;
13
+ export declare const getRelationScalars: (fields: DMMF.Field[]) => Record<string, string[]>;
14
+ export declare const mergeImportStatements: (first: ImportStatementParams, second: ImportStatementParams) => ImportStatementParams;
15
+ export declare const zipImportStatementParams: (items: ImportStatementParams[]) => ImportStatementParams[];
16
+ export interface IModelSelect {
17
+ [key: string]: IModelSelect | true | string;
18
+ }
19
+ export declare function getPrismaReadStruct(allModels: DMMF.Model[]): IModelSelect;
20
+ export declare function structFilteredByGlob(dmmf: DMMF.Model[], modelName: string, notationGlob: string[], type?: GlobType): IModelSelect | undefined;
21
+ export declare function globToFieldList(dmmf: DMMF.Model[], modelName: string, glob?: string[], type?: GlobType): string[];
22
+ export declare function getModelsFieldsTypeMap(models: DMMF.Model[]): Record<string, Record<string, DMMF.Field>>;
23
+ export declare function isEnumField(field: DMMF.Field): boolean;
24
+ export declare function getModelsEnum(enumTypesModel: DMMF.SchemaEnum[]): Record<string, Record<string, string>>;
25
+ declare type UiType = {
26
+ formItem: {
27
+ type: 'File' | 'Image';
28
+ args: {
29
+ maxCount: number;
30
+ accept: string;
31
+ sizeLimit: number;
32
+ };
33
+ } | {
34
+ type: 'Text';
35
+ args: {
36
+ rows: number;
37
+ };
38
+ } | {
39
+ type: 'CheckBox' | 'Radio';
40
+ args: {
41
+ options: string[];
42
+ };
43
+ } | {
44
+ type: 'Select';
45
+ args: {
46
+ options: string[];
47
+ mode?: 'multiple' | undefined;
48
+ };
49
+ } | {
50
+ type: 'String' | 'Boolean' | 'Int' | 'BigInt' | 'Float' | 'Decimal' | 'DateTime' | 'Markdown' | 'Html' | 'Url' | 'Email' | 'Other';
51
+ args: {};
52
+ };
53
+ };
54
+ export declare function parseDocumentation(documentation: string, field: DMMF.Field): UiType;
55
+ export {};