@postxl/generator 0.72.0 → 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/generators/models/export/encoder.generator.js +13 -4
- package/dist/generators/models/import/decoder.generator.js +18 -8
- package/dist/generators/models/react/modals.generator.js +1 -1
- package/dist/lib/attributes.d.ts +13 -2
- package/dist/lib/meta.js +1 -1
- package/dist/lib/schema/schema.d.ts +4 -4
- package/dist/lib/schema/types.d.ts +10 -0
- package/dist/lib/schema/types.js +5 -1
- package/dist/lib/utils/error.js +0 -1
- package/dist/prisma/attributes.js +6 -4
- package/dist/prisma/parse.js +14 -8
- package/package.json +1 -1
|
@@ -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} =>
|
|
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}
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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 =
|
|
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.
|
package/dist/lib/attributes.d.ts
CHANGED
|
@@ -81,10 +81,21 @@ export type FieldAttributes = {
|
|
|
81
81
|
*/
|
|
82
82
|
maxLength?: number;
|
|
83
83
|
/**
|
|
84
|
-
* Schema tag: `@@
|
|
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
|
-
|
|
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:
|
|
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 (
|
|
287
|
+
* Name of the field and variable (must be `id`)
|
|
288
288
|
*/
|
|
289
|
-
name: Types.
|
|
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 (
|
|
317
|
+
* Name of the field and variable (must be `id`)
|
|
318
318
|
*/
|
|
319
|
-
name: Types.
|
|
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
|
*/
|
package/dist/lib/schema/types.js
CHANGED
|
@@ -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
|
*/
|
package/dist/lib/utils/error.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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: (
|
|
165
|
+
isUpdatedAt: (_b = field.isUpdatedAt) !== null && _b !== void 0 ? _b : false,
|
|
164
166
|
isCreatedAt: field.name === 'createdAt',
|
|
165
167
|
};
|
|
166
168
|
});
|
package/dist/prisma/parse.js
CHANGED
|
@@ -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.
|
|
320
|
+
if (field.attributes.isNameField) {
|
|
321
321
|
if (labelField !== undefined) {
|
|
322
|
-
|
|
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
|
}
|