@postxl/generator 0.71.2 → 0.73.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.
package/dist/generator.js CHANGED
@@ -32,13 +32,18 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
32
32
  step((generator = generator.apply(thisArg, _arguments || [])).next());
33
33
  });
34
34
  };
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
35
38
  Object.defineProperty(exports, "__esModule", { value: true });
36
39
  exports.generate = void 0;
40
+ const assert_1 = __importDefault(require("assert"));
37
41
  const generator_helper_1 = require("@prisma/generator-helper");
38
42
  const internals_1 = require("@prisma/internals");
39
43
  const zod_1 = require("zod");
40
44
  const lock_1 = require("@postxl/lock");
41
45
  const prettier = __importStar(require("@postxl/prettier"));
46
+ const runtime_1 = require("@postxl/runtime");
42
47
  const react_generator_1 = require("./generators/enums/react.generator");
43
48
  const types_generator_1 = require("./generators/enums/types.generator");
44
49
  const module_generator_1 = require("./generators/indices/data/module.generator");
@@ -75,6 +80,7 @@ const service_generator_5 = require("./generators/models/update/service.generato
75
80
  const service_generator_6 = require("./generators/models/view/service.generator");
76
81
  const meta_1 = require("./lib/meta");
77
82
  const types_1 = require("./lib/schema/types");
83
+ const types_2 = require("./lib/types");
78
84
  const client_path_1 = require("./prisma/client-path");
79
85
  const parse_1 = require("./prisma/parse");
80
86
  // NOTE: This needs to match the constant used in the manager package.
@@ -165,7 +171,6 @@ function generate(_a) {
165
171
  if (root == undefined) {
166
172
  throw new Error(`Could not find lock file. Make sure you are running the generator in a project folder.`);
167
173
  }
168
- const gitignore = lock_1.GitIgnoreUtils.getGitignore(root);
169
174
  const generated = new prettier.ExtendedVirtualFS();
170
175
  // Generate Models
171
176
  for (const model of models) {
@@ -282,9 +287,9 @@ function generate(_a) {
282
287
  },
283
288
  },
284
289
  });
285
- const unfixableErrorCount = lintResult.totalErrorCount - lintResult.totalFixableErrorCount;
286
- if (unfixableErrorCount > 0) {
287
- console.log(`LINT: ${unfixableErrorCount} unfixable errors! Please open an issue with your schema!`);
290
+ const unFixableErrorCount = lintResult.totalErrorCount - lintResult.totalFixableErrorCount;
291
+ if (unFixableErrorCount > 0) {
292
+ console.log(`LINT: ${unFixableErrorCount} non-fixable errors! Please open an issue with your schema!`);
288
293
  }
289
294
  const unfixedWarningCount = lintResult.totalWarningCount - lintResult.totalFixableWarningCount;
290
295
  if (unfixedWarningCount > 0) {
@@ -295,17 +300,20 @@ function generate(_a) {
295
300
  console.log(result.message);
296
301
  }
297
302
  }
298
- if (unfixedWarningCount === 0 && unfixableErrorCount === 0) {
303
+ if (unfixedWarningCount === 0 && unFixableErrorCount === 0) {
299
304
  console.log(`LINT: All files linted successfully without warnings and errors!`);
300
305
  }
301
306
  yield generated.formatUTF8Files(prettier.config);
302
307
  // -------------------------------------------------------------------------
303
- const vfs = yield lock_1.VirtualFS.fromLockFile({
304
- root,
305
- namespace: GENERATOR_NAMESPACE,
308
+ const gitignore = lock_1.GitIgnoreUtils.getGitignore(root);
309
+ const lock = yield lock_1.LockFile.fromProjectRoot({ root, namespace: GENERATOR_NAMESPACE });
310
+ const vfs = yield lock_1.VirtualFS.fromDirectory(root, {
306
311
  // NOTE: We start with a clean slate every time we generate so we can detect
307
312
  // which files were not generated in the last run.
308
- opts: { clean: true },
313
+ clean: true,
314
+ // NOTE: We only load files that may be impacted by the generator.
315
+ include: lock.listManagedFiles(),
316
+ ignore: [lock_1.LockFile.LOCKFILE_PATH],
309
317
  });
310
318
  // Merge with existing files.
311
319
  yield vfs.copy(generated, './');
@@ -316,11 +324,103 @@ function generate(_a) {
316
324
  if (FORCE_ENV) {
317
325
  console.debug('Forcing regeneration of all files due to POSTXL_FORCE_REWRITE=true!');
318
326
  }
319
- const changes = yield vfs.flush(process.cwd(), GENERATOR_NAMESPACE, {
320
- force: config.force || FORCE_ENV,
321
- gitIgnoredFiles: gitignore === null || gitignore === void 0 ? void 0 : gitignore.entries,
322
- });
323
- const log = lock_1.ConsoleUtils.getFilesChangelog(changes.filter((c) => c.status !== 'skipped'));
327
+ const isForceMode = FORCE_ENV || config.force;
328
+ const results = yield vfs.flush(root, (_b) => __awaiter(this, [_b], void 0, function* ({ path, disk, file }) {
329
+ const fileLockEntry = lock.get(path);
330
+ switch (fileLockEntry.status) {
331
+ case 'unauthorized':
332
+ // NOTE: We never override files that are not managed by the generator namespace!
333
+ return 'skip';
334
+ case 'managed': {
335
+ // NOTE: File is detached because developer changed the contents or deleted the file.
336
+ if (
337
+ // NOTE: User deleted the file!
338
+ disk === undefined) {
339
+ // NOTE: Unless the file is deleted because of gitignore or we are in force mode, we skip it.
340
+ if ((gitignore === null || gitignore === void 0 ? void 0 : gitignore.entries.has(path)) || isForceMode) {
341
+ return 'write';
342
+ }
343
+ return 'skip';
344
+ }
345
+ // NOTE: The file exists in the lock so we check whether it's managed or detached.
346
+ const diskFileChecksum = yield lock_1.MiniGit.calculateFileChecksum({ path, content: disk.content });
347
+ if (
348
+ // NOTE: File is detached because developer changed the contents of the file.
349
+ fileLockEntry.checksum !== diskFileChecksum) {
350
+ // NOTE: We only skip detached files when we are not in force mode.
351
+ if (isForceMode) {
352
+ return 'write';
353
+ }
354
+ return 'skip';
355
+ }
356
+ // NOTE: File is managed!
357
+ (0, assert_1.default)(fileLockEntry.checksum === diskFileChecksum && disk !== undefined);
358
+ if (file) {
359
+ const newFileChecksum = yield lock_1.MiniGit.calculateFileChecksum({
360
+ path,
361
+ content: file.kind === 'UTF8-FILE' ? file.utf8Content : file.binaryContent,
362
+ });
363
+ // NOTE: We defensively don't override files with matching checksums unless in force mode
364
+ // because checksum is by design not an injection.
365
+ if (newFileChecksum === fileLockEntry.checksum && !isForceMode) {
366
+ return 'skip';
367
+ }
368
+ return 'write';
369
+ }
370
+ // NOTE: File has been deleted.
371
+ return 'write';
372
+ }
373
+ case 'enoent': {
374
+ // NOTE: File has no lockfile entry.
375
+ const is3rdPartFile = disk !== undefined;
376
+ if (is3rdPartFile && !isForceMode) {
377
+ return 'skip';
378
+ }
379
+ return 'write';
380
+ }
381
+ default:
382
+ throw new types_2.ExhaustiveSwitchCheck(fileLockEntry);
383
+ }
384
+ }), { dryRun: false });
385
+ // NOTE: Lastly we update the lockfile with all changes we've flushed.
386
+ for (const change of results) {
387
+ switch (change.status) {
388
+ case 'write': {
389
+ // NOTE: We update the lockfile entries of the files that were changed.
390
+ if (change.disk === undefined) {
391
+ lock.remove(change.path);
392
+ }
393
+ else {
394
+ const r = yield lock.add({ path: change.path, content: change.disk.content });
395
+ // NOTE: Adding a managed file should never fail.
396
+ (0, assert_1.default)(r != null);
397
+ }
398
+ break;
399
+ }
400
+ case 'skip':
401
+ break;
402
+ default:
403
+ throw new types_2.ExhaustiveSwitchCheck(change);
404
+ }
405
+ }
406
+ yield lock.writeToProjectRoot(root, { dryRun: false });
407
+ // NOTE: Lastly we generate the log of the changes.
408
+ const log = lock_1.ConsoleUtils.getFilesChangelog(results.map((result) => {
409
+ if (result.status === 'write') {
410
+ if (result.prevDisk === undefined) {
411
+ return { path: result.path, status: 'new' };
412
+ }
413
+ if (result.disk === undefined) {
414
+ return { path: result.path, status: 'deleted' };
415
+ }
416
+ if (runtime_1.BufferUtils.equals(result.prevDisk.content, result.disk.content) &&
417
+ result.prevDisk.mode === result.disk.mode) {
418
+ return { path: result.path, status: 'unchanged' };
419
+ }
420
+ return { path: result.path, status: 'changed' };
421
+ }
422
+ return { path: result.path, status: 'skipped' };
423
+ }));
324
424
  console.info(log);
325
425
  });
326
426
  }
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.generateModelExportEncoder = void 0;
4
4
  const imports_1 = require("../../../lib/imports");
5
+ const meta_1 = require("../../../lib/meta");
5
6
  const types_1 = require("../../../lib/schema/types");
6
7
  /**
7
8
  * Creates an encoder for the Seed Excel template.
@@ -13,15 +14,13 @@ function generateModelExportEncoder({ model, meta }) {
13
14
  [meta.import.decoder.location.import]: [meta.import.decoder.rowDecoderName],
14
15
  });
15
16
  const { userFriendlyName: userFriendly, userFriendlyNamePlural: userFriendlyPlural } = meta;
17
+ const fieldEncoders = generateFieldEncoders({ model });
16
18
  /* prettier-ignore */
17
19
  return `
18
20
  import * as z from 'zod'
19
21
 
20
- import { capitalizeKeys } from '@postxl/runtime'
21
-
22
22
  ${imports.generate()}
23
23
 
24
-
25
24
  /**
26
25
  * The type for rows in the ${userFriendly} table
27
26
  */
@@ -31,7 +30,9 @@ function generateModelExportEncoder({ model, meta }) {
31
30
  /**
32
31
  * Converts a ${userFriendly} to an Excel row
33
32
  */
34
- export const ${itemEncoderFunctionName} = (item: ${model.typeName}): ${encodedExcelType} => capitalizeKeys(item)
33
+ export const ${itemEncoderFunctionName} = (item: ${model.typeName}): ${encodedExcelType} => ({
34
+ ${fieldEncoders.join(',\n')}
35
+ })
35
36
 
36
37
  /**
37
38
  * Converts a list of ${userFriendlyPlural} to an Excel table
@@ -40,3 +41,11 @@ function generateModelExportEncoder({ model, meta }) {
40
41
  `;
41
42
  }
42
43
  exports.generateModelExportEncoder = generateModelExportEncoder;
44
+ function generateFieldEncoders({ model }) {
45
+ const fieldEncoders = [];
46
+ for (const field of model.fields) {
47
+ const fieldMeta = (0, meta_1.getFieldMetadata)({ field });
48
+ fieldEncoders.push(`"${fieldMeta.excelColumnName}": item.${field.name}`);
49
+ }
50
+ return fieldEncoders;
51
+ }
@@ -17,11 +17,10 @@ function generateModelImportDecoder({ model, meta }) {
17
17
  });
18
18
  const { userFriendlyName: userFriendly, internalSingularNameCapitalized: singularCapitalized } = meta;
19
19
  const { fieldDecoders, blankFieldDecoders } = generateFieldDecoders({ model, meta, imports });
20
+ const fieldTransformers = generateFieldTransformers({ model });
20
21
  return `
21
22
  import * as z from 'zod'
22
23
 
23
- import { uncapitalizeKeys } from '@postxl/runtime'
24
-
25
24
  ${imports.generate()}
26
25
 
27
26
  /**
@@ -52,7 +51,10 @@ const blank${singularCapitalized}RowDecoder = z
52
51
  export const ${tableImportDecoder} = z
53
52
  .array(
54
53
  blank${singularCapitalized}RowDecoder
55
- .or(${meta.import.decoder.rowDecoderName}.transform(uncapitalizeKeys))
54
+ .or(${meta.import.decoder.rowDecoderName}
55
+ .transform(item => ({
56
+ ${fieldTransformers.join(',\n')}
57
+ })))
56
58
  )
57
59
  .transform((items) => items.filter(Boolean) as ${model.typeName}[])`;
58
60
  }
@@ -63,11 +65,11 @@ function generateFieldDecoders({ model, meta, imports, }) {
63
65
  for (const field of model.fields) {
64
66
  const fieldMeta = (0, meta_1.getFieldMetadata)({ field });
65
67
  const optionalModifier = field.attributes.isUpdatedAt || field.attributes.isCreatedAt ? '.optional()' : '';
66
- blankFieldDecoders.push(`${fieldMeta.excelColumnName}: excelNullOrBlankDecoder${optionalModifier}`);
68
+ blankFieldDecoders.push(`'${fieldMeta.excelColumnName}': excelNullOrBlankDecoder${optionalModifier}`);
67
69
  switch (field.kind) {
68
70
  case 'id': {
69
71
  imports.addImport({ items: [meta.types.toBrandedIdTypeFnName], from: meta.types.importPath });
70
- fieldDecoders.push(`${fieldMeta.excelColumnName}: ${toExcelDecoder({
72
+ fieldDecoders.push(`'${fieldMeta.excelColumnName}': ${toExcelDecoder({
71
73
  tsTypeName: field.unbrandedTypeName,
72
74
  nullable: false,
73
75
  imports,
@@ -75,7 +77,7 @@ function generateFieldDecoders({ model, meta, imports, }) {
75
77
  break;
76
78
  }
77
79
  case 'scalar': {
78
- fieldDecoders.push(`${fieldMeta.excelColumnName}: ${toExcelDecoder({
80
+ fieldDecoders.push(`'${fieldMeta.excelColumnName}': ${toExcelDecoder({
79
81
  tsTypeName: field.tsTypeName,
80
82
  nullable: !field.isRequired,
81
83
  imports,
@@ -86,7 +88,7 @@ function generateFieldDecoders({ model, meta, imports, }) {
86
88
  const refModel = field.relationToModel;
87
89
  const refMeta = (0, meta_1.getModelMetadata)({ model: refModel });
88
90
  imports.addImport({ items: [refMeta.types.toBrandedIdTypeFnName], from: refMeta.types.importPath });
89
- fieldDecoders.push(`${fieldMeta.excelColumnName}: ${toExcelDecoder({
91
+ fieldDecoders.push(`'${fieldMeta.excelColumnName}': ${toExcelDecoder({
90
92
  tsTypeName: field.unbrandedTypeName,
91
93
  nullable: !field.isRequired,
92
94
  imports,
@@ -98,7 +100,7 @@ function generateFieldDecoders({ model, meta, imports, }) {
98
100
  break;
99
101
  }
100
102
  case 'enum': {
101
- fieldDecoders.push(`${fieldMeta.excelColumnName}: z.enum([
103
+ fieldDecoders.push(`'${fieldMeta.excelColumnName}': z.enum([
102
104
  ${field.enumerator.values.map((v) => `'${v}'`).join(', ')}
103
105
  ])${field.isRequired ? '' : '.nullable()'}${optionalModifier}`);
104
106
  break;
@@ -136,3 +138,11 @@ function toExcelDecoder({ tsTypeName, nullable, imports, }) {
136
138
  throw new Error('Unknown type');
137
139
  }
138
140
  }
141
+ function generateFieldTransformers({ model }) {
142
+ const fieldTransformers = [];
143
+ for (const field of model.fields) {
144
+ const fieldMeta = (0, meta_1.getFieldMetadata)({ field });
145
+ fieldTransformers.push(`${field.name}: item['${fieldMeta.excelColumnName}']`);
146
+ }
147
+ return fieldTransformers;
148
+ }
@@ -574,7 +574,7 @@ function getFormFieldComponents({ model, testIdCollector, }) {
574
574
  continue;
575
575
  }
576
576
  const formikFieldName = getFormikFieldName(field.name);
577
- const label = StringUtils.toPascalCase(field.name);
577
+ const label = field.attributes.label;
578
578
  switch (field.kind) {
579
579
  case 'id': {
580
580
  // NOTE: We never show the ID field in the form even if it's in the type signature of the form input.
@@ -81,10 +81,21 @@ export type FieldAttributes = {
81
81
  */
82
82
  maxLength?: number;
83
83
  /**
84
- * Schema tag: `@@Label()`
84
+ * Schema tag: `@@IsNameField()`
85
85
  * The field that should be used as the default label for the model.
86
+ *
87
+ * If this is set, the repository will verify that exactly one record has this field set to true - and use it as the default label.
88
+ *
89
+ * If this attribute is set, this field will be used in the code/UI as the field that specifies the model's name. If not provided, we check for the existence of the`name` field. If that is not found, we use the `id` field as the name field.
90
+ */
91
+ isNameField?: boolean;
92
+ /**
93
+ * Schema tag: `@@Label("Label")`
94
+ * The human readable label/name of the field.
95
+ *
96
+ * If not provided, we use the field name.
86
97
  */
87
- isLabel?: boolean;
98
+ label: string;
88
99
  };
89
100
  export type EnumAttributes = {
90
101
  /**
package/dist/lib/meta.js CHANGED
@@ -402,7 +402,7 @@ function getFieldMetadata({ field }) {
402
402
  tsFieldName: Types.toVariableName((0, string_1.toCamelCase)(field.name)),
403
403
  getByForeignKeyMethodFnName: Types.toFunctionName(`getItemsFor${PascalCase}`),
404
404
  getByForeignKeyIdsMethodFnName: Types.toFunctionName(`getIdsFor${PascalCase}`),
405
- excelColumnName: (0, string_1.toPascalCase)(field.name),
405
+ excelColumnName: field.attributes.label,
406
406
  };
407
407
  }
408
408
  exports.getFieldMetadata = getFieldMetadata;
@@ -284,9 +284,9 @@ export type FieldScalar = Prettify<Omit<FieldCore, 'name'> & {
284
284
  export type FieldId = Prettify<Omit<FieldCore, 'name'> & {
285
285
  kind: 'id';
286
286
  /**
287
- * Name of the field and variable (e.g. id)
287
+ * Name of the field and variable (must be `id`)
288
288
  */
289
- name: Types.FieldName;
289
+ name: Types.IdFieldName;
290
290
  /**
291
291
  * Model that this ID field identifies.
292
292
  */
@@ -314,9 +314,9 @@ export type FieldId = Prettify<Omit<FieldCore, 'name'> & {
314
314
  export declare const isFieldId: (field: Field) => field is Prettify<Omit<FieldCore, "name"> & {
315
315
  kind: 'id';
316
316
  /**
317
- * Name of the field and variable (e.g. id)
317
+ * Name of the field and variable (must be `id`)
318
318
  */
319
- name: Types.FieldName;
319
+ name: Types.IdFieldName;
320
320
  /**
321
321
  * Model that this ID field identifies.
322
322
  */
@@ -71,6 +71,16 @@ export declare const isAnnotatedTypeName: (t: string | AnnotatedTypeName) => t i
71
71
  export type FieldName = string & {
72
72
  readonly ___type: 'FieldName';
73
73
  };
74
+ /**
75
+ * Brands a raw string to an IdFieldName identifier.
76
+ */
77
+ export declare const ID_FIELD_NAME: IdFieldName;
78
+ /**
79
+ * The name of the id field. Must be `id`.
80
+ */
81
+ export type IdFieldName = 'id' & {
82
+ readonly ___type: 'FieldName';
83
+ };
74
84
  /**
75
85
  * Brands a raw string to a FieldName identifier.
76
86
  */
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  // MARK: - Generated content related types
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.toPackageName = exports.toPath = exports.toBackendModulePath = exports.toModuleLocation = exports.toFolderName = exports.toFileName = exports.toVariableName = exports.toFunctionName = exports.toEnumName = exports.toFieldName = exports.isAnnotatedTypeName = exports.toAnnotatedTypeName = exports.toTypeName = exports.toModelName = exports.toDiscriminantName = exports.toClassName = void 0;
4
+ exports.toPackageName = exports.toPath = exports.toBackendModulePath = exports.toModuleLocation = exports.toFolderName = exports.toFileName = exports.toVariableName = exports.toFunctionName = exports.toEnumName = exports.toFieldName = exports.ID_FIELD_NAME = exports.isAnnotatedTypeName = exports.toAnnotatedTypeName = exports.toTypeName = exports.toModelName = exports.toDiscriminantName = exports.toClassName = void 0;
5
5
  /**
6
6
  * Converts a raw string to a branded ClassName.
7
7
  */
@@ -35,6 +35,10 @@ exports.toAnnotatedTypeName = toAnnotatedTypeName;
35
35
  */
36
36
  const isAnnotatedTypeName = (t) => typeof t === 'object' && t.kind === 'TypeName';
37
37
  exports.isAnnotatedTypeName = isAnnotatedTypeName;
38
+ /**
39
+ * Brands a raw string to an IdFieldName identifier.
40
+ */
41
+ exports.ID_FIELD_NAME = 'id';
38
42
  /**
39
43
  * Brands a raw string to a FieldName identifier.
40
44
  */
@@ -34,7 +34,6 @@ function extractNestedErrors(value) {
34
34
  * As a fallback, it returns a JSON string representation of the error.
35
35
  */
36
36
  function formatZodError(e) {
37
- console.log(e);
38
37
  const formatted = e.format();
39
38
  if (typeof formatted === 'string') {
40
39
  return formatted;
@@ -138,7 +138,8 @@ function getFieldAttributes(field) {
138
138
  ignore: blankStringBooleanDecoder,
139
139
  description: zod_1.default.string().optional(),
140
140
  isDefault: blankStringBooleanDecoder,
141
- label: blankStringBooleanDecoder,
141
+ isNameField: blankStringBooleanDecoder,
142
+ label: zod_1.default.string().optional(),
142
143
  example: examplesDecoder,
143
144
  examples: examplesDecoder,
144
145
  maxLength: zod_1.default
@@ -148,7 +149,7 @@ function getFieldAttributes(field) {
148
149
  readonly: blankStringBooleanDecoder,
149
150
  })
150
151
  .transform((obj) => {
151
- var _a;
152
+ var _a, _b;
152
153
  if (isPrismaIgnored && !obj.ignore) {
153
154
  throw new Error(`Field ${field.name} is ignored by Prisma, but is missing the "ignore" PostXL attribute!`);
154
155
  }
@@ -156,11 +157,12 @@ function getFieldAttributes(field) {
156
157
  ignore: obj.ignore,
157
158
  description: obj.description,
158
159
  isDefaultField: obj.isDefault,
159
- isLabel: obj.label,
160
+ isNameField: obj.isNameField,
161
+ label: (_a = obj.label) !== null && _a !== void 0 ? _a : (0, string_1.toPascalCase)(field.name),
160
162
  examples: obj.examples || obj.example,
161
163
  maxLength: obj.maxLength,
162
164
  isReadonly: obj.readonly || field.isGenerated || field.isUpdatedAt || field.name === 'createdAt' || field.isId,
163
- isUpdatedAt: (_a = field.isUpdatedAt) !== null && _a !== void 0 ? _a : false,
165
+ isUpdatedAt: (_b = field.isUpdatedAt) !== null && _b !== void 0 ? _b : false,
164
166
  isCreatedAt: field.name === 'createdAt',
165
167
  };
166
168
  });
@@ -226,7 +226,7 @@ function parseModel({ dmmfModel, enums, models, config, }) {
226
226
  }
227
227
  if (dmmfField.isId) {
228
228
  const isGeneratedField = isAutoIncrementField(dmmfField) || isUUIDField(dmmfField);
229
- const _field = Object.assign(Object.assign({ kind: 'id' }, shared), { isUnique: isUniqueField(dmmfField), isGenerated: isGeneratedField, unbrandedTypeName: getTsTypeForId(dmmfField), model: core });
229
+ const _field = Object.assign(Object.assign({ kind: 'id' }, shared), { name: Types.ID_FIELD_NAME, isUnique: isUniqueField(dmmfField), isGenerated: isGeneratedField, unbrandedTypeName: getTsTypeForId(dmmfField), model: core });
230
230
  return _field;
231
231
  }
232
232
  if (dmmfField.kind === 'scalar') {
@@ -282,25 +282,25 @@ function validateFields({ fields, model: { name } }) {
282
282
  const fieldName = (0, logger_1.highlight)(`${name}.${field.name}`);
283
283
  switch (field.kind) {
284
284
  case 'scalar':
285
- if (field.name === 'name') {
285
+ if (field.name === 'name' && nameField === undefined) {
286
286
  nameField = field;
287
287
  }
288
288
  if (field.attributes.isCreatedAt) {
289
289
  if (createdAtField) {
290
- (0, error_1.throwError)(`${fieldName} has multiple createdAt fields`);
290
+ (0, error_1.throwError)(`${fieldName} has multiple createdAt fields - ${createdAtField.name} and ${field.name}`);
291
291
  }
292
292
  createdAtField = field;
293
293
  }
294
294
  if (field.attributes.isUpdatedAt) {
295
295
  if (updatedAtField) {
296
- (0, error_1.throwError)(`${fieldName} has multiple updatedAt fields`);
296
+ (0, error_1.throwError)(`${fieldName} has multiple updatedAt fields - ${updatedAtField.name} and ${field.name}`);
297
297
  }
298
298
  updatedAtField = field;
299
299
  }
300
300
  break;
301
301
  case 'id':
302
302
  if (idField) {
303
- (0, error_1.throwError)(`${fieldName} has multiple id fields`);
303
+ (0, error_1.throwError)(`${fieldName} has multiple id fields - ${idField.name} and ${field.name}`);
304
304
  }
305
305
  idField = field;
306
306
  break;
@@ -312,14 +312,20 @@ function validateFields({ fields, model: { name } }) {
312
312
  //handle default case
313
313
  if (field.attributes.isDefaultField && field.kind === 'scalar') {
314
314
  if (defaultField !== undefined) {
315
- (0, error_1.throwError)(`${fieldName} has multiple default fields`);
315
+ (0, error_1.throwError)(`${fieldName} has multiple default fields - ${defaultField.name} and ${field.name}`);
316
316
  }
317
317
  defaultField = field;
318
318
  }
319
319
  //handle name field
320
- if (field.attributes.isLabel) {
320
+ if (field.attributes.isNameField) {
321
321
  if (labelField !== undefined) {
322
- (0, error_1.throwError)(`${fieldName} has multiple name fields`);
322
+ // Note: In case we have a field called "name" but assign the "@@Label" attribute to another field, we ignore the "name" field.
323
+ if (labelField.name === 'name') {
324
+ labelField = field;
325
+ }
326
+ else {
327
+ (0, error_1.throwError)(`${fieldName} has multiple name fields - ${labelField.name} and ${field.name}`);
328
+ }
323
329
  }
324
330
  labelField = field;
325
331
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@postxl/generator",
3
- "version": "0.71.2",
3
+ "version": "0.73.0",
4
4
  "main": "./dist/generator.js",
5
5
  "typings": "./dist/generator.d.ts",
6
6
  "bin": {
@@ -19,10 +19,10 @@
19
19
  "@prisma/internals": "5.8.1",
20
20
  "exceljs": "4.3.0",
21
21
  "fast-glob": "3.2.12",
22
- "remeda": "1.9.4",
23
22
  "zod": "3.22.2",
24
- "@postxl/lock": "1.4.2",
25
- "@postxl/prettier": "0.0.2"
23
+ "@postxl/lock": "1.5.0",
24
+ "@postxl/prettier": "0.1.0",
25
+ "@postxl/runtime": "0.1.3"
26
26
  },
27
27
  "devDependencies": {
28
28
  "@jest/globals": "29.7.0",
@@ -40,9 +40,6 @@
40
40
  "peerDependencies": {
41
41
  "prisma": "5.8.1"
42
42
  },
43
- "wallaby": {
44
- "autoDetect": true
45
- },
46
43
  "scripts": {
47
44
  "test:generators": "./scripts/test-generators.sh",
48
45
  "test:setup": "./scripts/test-setup.sh",