@postxl/generator 0.13.0 → 0.15.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 +20 -0
- package/dist/generators/indices/businesslogicindex.generator.d.ts +9 -0
- package/dist/generators/indices/businesslogicindex.generator.js +19 -0
- package/dist/generators/indices/businesslogicmodule.generator.d.ts +9 -0
- package/dist/generators/indices/businesslogicmodule.generator.js +43 -0
- package/dist/generators/indices/businesslogicservice.generator.d.ts +9 -0
- package/dist/generators/indices/businesslogicservice.generator.js +32 -0
- package/dist/generators/indices/datamockmodule.generator.js +2 -2
- package/dist/generators/indices/datamodule.generator.js +22 -21
- package/dist/generators/indices/dataservice.generator.js +1 -1
- package/dist/generators/indices/seed-template-decoder.generator.d.ts +9 -0
- package/dist/generators/indices/seed-template-decoder.generator.js +137 -0
- package/dist/generators/indices/seed-template.generator.d.ts +9 -0
- package/dist/generators/indices/seed-template.generator.js +80 -0
- package/dist/generators/models/businesslogic.generator.d.ts +9 -0
- package/dist/generators/models/businesslogic.generator.js +172 -0
- package/dist/generators/models/react.generator/context.generator.js +5 -3
- package/dist/generators/models/react.generator/library.generator.js +6 -3
- package/dist/generators/models/react.generator/lookup.generator.js +1 -1
- package/dist/generators/models/react.generator/modals.generator.d.ts +1 -1
- package/dist/generators/models/react.generator/modals.generator.js +128 -65
- package/dist/generators/models/repository.generator.js +38 -15
- package/dist/generators/models/route.generator.js +6 -6
- package/dist/generators/models/seed.generator.js +49 -25
- package/dist/generators/models/stub.generator.js +21 -14
- package/dist/generators/models/types.generator.js +34 -3
- package/dist/lib/attributes.d.ts +1 -1
- package/dist/lib/imports.d.ts +1 -1
- package/dist/lib/imports.js +12 -3
- package/dist/lib/meta.d.ts +150 -14
- package/dist/lib/meta.js +34 -1
- package/dist/lib/schema/fields.d.ts +5 -1
- package/dist/lib/schema/schema.d.ts +26 -1
- package/dist/lib/schema/schema.js +1 -1
- package/dist/lib/schema/types.d.ts +2 -2
- package/dist/lib/utils/file.js +2 -0
- package/dist/lib/utils/logger.d.ts +5 -5
- package/dist/lib/utils/string.d.ts +5 -0
- package/dist/lib/utils/string.js +10 -2
- package/dist/prisma/attributes.js +20 -9
- package/dist/prisma/parse.js +17 -3
- package/package.json +3 -2
|
@@ -41,14 +41,16 @@ function generateRepository({ model, meta }) {
|
|
|
41
41
|
};
|
|
42
42
|
};
|
|
43
43
|
const indexes = model.attributes.index ? [getIndexDefinition(model.attributes.index)] : [];
|
|
44
|
-
const defaultValueInitFn =
|
|
44
|
+
const defaultValueInitFn = model.defaultField
|
|
45
|
+
? `
|
|
45
46
|
if (item.${(_a = model.defaultField) === null || _a === void 0 ? void 0 : _a.name}) {
|
|
46
47
|
if (this.defaultValue) {
|
|
47
48
|
console.warn(\`More than one default ${meta.userFriendlyName} found! \${this.defaultValue.id} and \${item.id}\`)
|
|
48
49
|
}
|
|
49
50
|
this.defaultValue = item
|
|
50
51
|
}
|
|
51
|
-
|
|
52
|
+
`
|
|
53
|
+
: '';
|
|
52
54
|
const defaultValueInitCheckFn = `
|
|
53
55
|
if (!this.db.isCLI && !this.defaultValue) {
|
|
54
56
|
throw new Error('No default ${meta.userFriendlyName} found!')
|
|
@@ -58,14 +60,16 @@ function generateRepository({ model, meta }) {
|
|
|
58
60
|
const idIntInitFn = `this.currentMaxId = (await this.db.${meta.data.repository.getMethodFnName}.aggregate({ _max: { ${idField.sourceName}: true } }))._max.${idField.sourceName} ?? 0`;
|
|
59
61
|
const imports = imports_1.ImportsGenerator.from(meta.data.repoFilePath)
|
|
60
62
|
.addImport({
|
|
61
|
-
items: [model.typeName, model.brandedIdType, meta.types.toBrandedIdTypeFnName],
|
|
63
|
+
items: [model.typeName, model.brandedIdType, ...(isGenerated ? [meta.types.toBrandedIdTypeFnName] : [])],
|
|
62
64
|
from: meta.types.importPath,
|
|
63
65
|
})
|
|
64
|
-
.addImport({ items: [meta.types.zodDecoderFnName], from: meta.types.importPath })
|
|
65
66
|
.addImport({
|
|
66
67
|
items: [(0, types_1.toClassName)('Repository')],
|
|
67
68
|
from: (0, types_1.toFileName)(model.schemaConfig.paths.dataLibPath + 'repository.type'),
|
|
68
69
|
});
|
|
70
|
+
if (!model.attributes.inMemoryOnly) {
|
|
71
|
+
imports.addImport({ items: [meta.types.zodDecoderFnName], from: meta.types.importPath });
|
|
72
|
+
}
|
|
69
73
|
relations.forEach((r) => {
|
|
70
74
|
imports.addImport({
|
|
71
75
|
items: [r.meta.types.brandedIdType],
|
|
@@ -74,8 +78,12 @@ function generateRepository({ model, meta }) {
|
|
|
74
78
|
});
|
|
75
79
|
return `
|
|
76
80
|
import { Injectable, Logger } from '@nestjs/common'
|
|
81
|
+
${model.attributes.inMemoryOnly
|
|
82
|
+
? ''
|
|
83
|
+
: `
|
|
77
84
|
import { DbService, ${model.sourceName} as DbType } from '@${model.schemaConfig.project}/db'
|
|
78
85
|
import { format, pluralize ${indexes.length === 0 ? '' : ', NestedMap'} } from '@pxl/common'
|
|
86
|
+
`}
|
|
79
87
|
|
|
80
88
|
${imports.generate()}
|
|
81
89
|
|
|
@@ -235,6 +243,11 @@ export class ${meta.data.repositoryClassName} implements Repository<
|
|
|
235
243
|
${[...model.fields.values()].map((f) => `${f.sourceName}: item.${f.name}`).join(',\n')}
|
|
236
244
|
}
|
|
237
245
|
}
|
|
246
|
+
${model.attributes.inMemoryOnly
|
|
247
|
+
? `
|
|
248
|
+
// Non-mocked version is async - so we keep type-compatible signatures for create() and createWithId()
|
|
249
|
+
// eslint-disable-next-line @typescript-eslint/require-await, @typescript-eslint/no-unused-vars`
|
|
250
|
+
: ''}
|
|
238
251
|
public async createWithId(item: Omit<${model.typeName}, '${idField.name}'> & {
|
|
239
252
|
id: ${model.brandedIdType}
|
|
240
253
|
}): Promise<${model.typeName}> {
|
|
@@ -254,6 +267,11 @@ export class ${meta.data.repositoryClassName} implements Repository<
|
|
|
254
267
|
return newItem
|
|
255
268
|
}
|
|
256
269
|
|
|
270
|
+
${model.attributes.inMemoryOnly
|
|
271
|
+
? `
|
|
272
|
+
// Non-mocked version is async - so we keep type-compatible signatures for create() and createWithId()
|
|
273
|
+
// eslint-disable-next-line @typescript-eslint/require-await, @typescript-eslint/no-unused-vars`
|
|
274
|
+
: ''}
|
|
257
275
|
public async create(
|
|
258
276
|
item: Omit<${model.typeName}, 'id'>
|
|
259
277
|
): Promise<${model.typeName}> {
|
|
@@ -405,17 +423,22 @@ export class ${meta.data.repositoryClassName} implements Repository<
|
|
|
405
423
|
}
|
|
406
424
|
`)
|
|
407
425
|
.join('\n')}
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
426
|
+
|
|
427
|
+
${maxLengthStringFields
|
|
428
|
+
.map((f) => `
|
|
429
|
+
/**
|
|
430
|
+
* Utility function that ensures that the ${f.name} field has a max length of ${f.attributes.maxLength}
|
|
431
|
+
*/
|
|
432
|
+
private ${getEnsureMaxLengthFnName(f)}(item: { ${f.name}?: string }) {
|
|
433
|
+
if (!item.${f.name}) {
|
|
434
|
+
return
|
|
435
|
+
}
|
|
436
|
+
if (item.${f.name}.length <= ${f.attributes.maxLength}) {
|
|
437
|
+
return
|
|
438
|
+
}
|
|
439
|
+
item.${f.name} = item.${f.name}.substring(0, ${f.attributes.maxLength - 4}) + \`...\`
|
|
440
|
+
}`)
|
|
441
|
+
.join('\n')}
|
|
419
442
|
|
|
420
443
|
${uniqueStringFields
|
|
421
444
|
.map((f) => {
|
|
@@ -11,7 +11,7 @@ const imports_1 = require("../../lib/imports");
|
|
|
11
11
|
function generateRoute({ model, meta }) {
|
|
12
12
|
const { idField, defaultField } = model;
|
|
13
13
|
const defaultValueMethod = `
|
|
14
|
-
getDefault: procedure.query(({ ctx }) => ctx.
|
|
14
|
+
getDefault: procedure.query(({ ctx }) => ctx.data.${meta.data.dataServiceName}.defaultValue),
|
|
15
15
|
`;
|
|
16
16
|
const createMethod = getCreateMethod({ model, meta });
|
|
17
17
|
const updateMethod = getUpdateMethod({ model, meta });
|
|
@@ -38,8 +38,8 @@ export const ${meta.trpc.routerName} = router({
|
|
|
38
38
|
|
|
39
39
|
get: procedure
|
|
40
40
|
.input(z.${idField.unbrandedTypeName}().transform(${meta.types.toBrandedIdTypeFnName}))
|
|
41
|
-
.query(
|
|
42
|
-
getMap: procedure.query(({ ctx }) => ctx.
|
|
41
|
+
.query(({ input, ctx }) => ctx.data.${meta.data.dataServiceName}.get(input)),
|
|
42
|
+
getMap: procedure.query(({ ctx }) => ctx.data.${meta.data.dataServiceName}.getAll()),
|
|
43
43
|
|
|
44
44
|
${omit(createMethod, model.attributes.skipCreate)}
|
|
45
45
|
${omit(updateMethod, model.attributes.skipUpdate)}
|
|
@@ -66,7 +66,7 @@ function getCreateMethod({ model: { fields }, meta }) {
|
|
|
66
66
|
create: procedure.input(z.object({
|
|
67
67
|
${parameters}
|
|
68
68
|
}))
|
|
69
|
-
.mutation(({ input, ctx }) => ctx.
|
|
69
|
+
.mutation(({ input, ctx }) => ctx.data.${meta.data.dataServiceName}.create(input)),
|
|
70
70
|
`;
|
|
71
71
|
}
|
|
72
72
|
function getUpdateMethod({ model: { fields }, meta }) {
|
|
@@ -79,14 +79,14 @@ function getUpdateMethod({ model: { fields }, meta }) {
|
|
|
79
79
|
${parameters}
|
|
80
80
|
})
|
|
81
81
|
)
|
|
82
|
-
.mutation(({ input, ctx }) => ctx.
|
|
82
|
+
.mutation(({ input, ctx }) => ctx.data.${meta.data.dataServiceName}.update(input)),
|
|
83
83
|
`;
|
|
84
84
|
}
|
|
85
85
|
function getDeleteMethod({ idField, meta }) {
|
|
86
86
|
return `
|
|
87
87
|
delete: procedure
|
|
88
88
|
.input(z.${idField.unbrandedTypeName}().transform(${meta.types.toBrandedIdTypeFnName}))
|
|
89
|
-
.mutation(({ input, ctx }) => ctx.
|
|
89
|
+
.mutation(({ input, ctx }) => ctx.data.${meta.data.dataServiceName}.delete(input)),
|
|
90
90
|
`;
|
|
91
91
|
}
|
|
92
92
|
/**
|
|
@@ -95,39 +95,60 @@ function generateFieldData({ field, model, index, exampleMode, }) {
|
|
|
95
95
|
throw new types_1.ExhaustiveSwitchCheck(field);
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
|
-
function generateFieldDataId({ field,
|
|
98
|
+
function generateFieldDataId({ field, index }) {
|
|
99
99
|
const idModelMeta = (0, meta_1.getModelMetadata)({ model: field.model });
|
|
100
100
|
return `${idModelMeta.types.toBrandedIdTypeFnName}(${field.unbrandedTypeName === 'string' ? `'${index}'` : index})`;
|
|
101
101
|
}
|
|
102
102
|
function quoteSingleQuote(str) {
|
|
103
|
-
return str
|
|
103
|
+
return str.replace(/'/g, "\\'");
|
|
104
104
|
}
|
|
105
105
|
function generateFieldDataScalar({ field, model, index, exampleMode, }) {
|
|
106
106
|
const { hasExample, example } = getFieldExample({ field, model, index, exampleMode });
|
|
107
107
|
switch (field.typeName) {
|
|
108
|
-
case 'string':
|
|
109
|
-
|
|
110
|
-
|
|
108
|
+
case 'string': {
|
|
109
|
+
if (hasExample && typeof example === 'string') {
|
|
110
|
+
return `'${quoteSingleQuote(example)}'`;
|
|
111
|
+
}
|
|
112
|
+
const result = generateFieldDataString({ field, model, index });
|
|
113
|
+
if (result === null) {
|
|
111
114
|
return 'null';
|
|
112
|
-
|
|
115
|
+
}
|
|
116
|
+
if (result === undefined) {
|
|
113
117
|
return 'undefined';
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
case '
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
118
|
+
}
|
|
119
|
+
return `'${result.replace(/'/g, "\\'")}'`;
|
|
120
|
+
}
|
|
121
|
+
case 'number': {
|
|
122
|
+
if (hasExample) {
|
|
123
|
+
return `${example}`;
|
|
124
|
+
}
|
|
125
|
+
return generateFieldDataNumber();
|
|
126
|
+
}
|
|
127
|
+
case 'boolean': {
|
|
128
|
+
if (hasExample) {
|
|
129
|
+
return `${example}`;
|
|
130
|
+
}
|
|
131
|
+
return generateFieldDataBoolean();
|
|
132
|
+
}
|
|
133
|
+
case 'Date': {
|
|
134
|
+
if (hasExample) {
|
|
135
|
+
// TODO: Maybe we should parse the date example to correct format?
|
|
136
|
+
return `${example}`;
|
|
137
|
+
}
|
|
138
|
+
return generateFieldDataDate();
|
|
139
|
+
}
|
|
140
|
+
default: {
|
|
122
141
|
console.warn(`Unknown scalar type: ${field.typeName}`);
|
|
123
142
|
return '';
|
|
143
|
+
}
|
|
124
144
|
}
|
|
125
145
|
}
|
|
126
|
-
function getFieldExample({ field,
|
|
127
|
-
if (exampleMode.mode === 'NoExamples')
|
|
128
|
-
return { hasExample: false
|
|
146
|
+
function getFieldExample({ field, index, exampleMode, }) {
|
|
147
|
+
if (exampleMode.mode === 'NoExamples') {
|
|
148
|
+
return { hasExample: false };
|
|
149
|
+
}
|
|
129
150
|
if (!field.attributes.examples || field.attributes.examples.length === 0) {
|
|
130
|
-
return { hasExample: false
|
|
151
|
+
return { hasExample: false };
|
|
131
152
|
}
|
|
132
153
|
switch (exampleMode.mode) {
|
|
133
154
|
case 'Permutations': {
|
|
@@ -138,30 +159,33 @@ function getFieldExample({ field, model, index, exampleMode, }) {
|
|
|
138
159
|
const example = field.attributes.examples[(index - 1) % field.attributes.examples.length];
|
|
139
160
|
return { hasExample: true, example };
|
|
140
161
|
}
|
|
141
|
-
default:
|
|
162
|
+
default: {
|
|
142
163
|
throw new types_1.ExhaustiveSwitchCheck(exampleMode);
|
|
164
|
+
}
|
|
143
165
|
}
|
|
144
166
|
}
|
|
145
167
|
function generateFieldDataString({ field, model, index }) {
|
|
146
|
-
if (field.name === 'name')
|
|
168
|
+
if (field.name === 'name') {
|
|
147
169
|
return `${(0, string_1.toPascalCase)(model.name)} ${index}`;
|
|
148
|
-
|
|
170
|
+
}
|
|
171
|
+
if (field.name === 'email') {
|
|
149
172
|
return faker_1.faker.internet.email();
|
|
173
|
+
}
|
|
150
174
|
return faker_1.faker.lorem.words(3);
|
|
151
175
|
}
|
|
152
|
-
function generateFieldDataNumber(
|
|
176
|
+
function generateFieldDataNumber() {
|
|
153
177
|
return faker_1.faker.datatype.float({ precision: 0.1, min: 0, max: 1 }).toString();
|
|
154
178
|
}
|
|
155
|
-
function generateFieldDataBoolean(
|
|
179
|
+
function generateFieldDataBoolean() {
|
|
156
180
|
return faker_1.faker.datatype.boolean().toString();
|
|
157
181
|
}
|
|
158
|
-
function generateFieldDataDate(
|
|
182
|
+
function generateFieldDataDate() {
|
|
159
183
|
const d = faker_1.faker.date.past(3, '2023-04-01T00:00:00.000Z');
|
|
160
184
|
//set time to midnight UTC
|
|
161
185
|
d.setUTCHours(0, 0, 0, 0);
|
|
162
186
|
return `new Date('${d.toISOString()}')`;
|
|
163
187
|
}
|
|
164
|
-
function generateFieldDataRelation({ field,
|
|
188
|
+
function generateFieldDataRelation({ field, itemCount, }) {
|
|
165
189
|
const referenceId = faker_1.faker.datatype.number({ min: 1, max: itemCount });
|
|
166
190
|
const refModelMeta = (0, meta_1.getModelMetadata)({ model: field.relationToModel });
|
|
167
191
|
const brandingFn = refModelMeta.types.toBrandedIdTypeFnName;
|
|
@@ -14,13 +14,7 @@ function generateStub({ model, meta }) {
|
|
|
14
14
|
items: [model.typeName, meta.types.toBrandedIdTypeFnName],
|
|
15
15
|
from: meta.types.importPath,
|
|
16
16
|
});
|
|
17
|
-
|
|
18
|
-
const depMeta = (0, meta_1.getModelMetadata)({ model: relation.relationToModel });
|
|
19
|
-
imports.addImport({
|
|
20
|
-
items: [relation.relationToModel.typeName, depMeta.types.toBrandedIdTypeFnName],
|
|
21
|
-
from: meta.types.importPath,
|
|
22
|
-
});
|
|
23
|
-
}
|
|
17
|
+
const assignments = getAssignmentStatementModel({ fields, imports });
|
|
24
18
|
return `
|
|
25
19
|
${imports.generate()}
|
|
26
20
|
|
|
@@ -28,7 +22,7 @@ ${imports.generate()}
|
|
|
28
22
|
* Utility object containing default values for all fields in a model.
|
|
29
23
|
*/
|
|
30
24
|
export const ${meta.data.defaultStubConstantName}: ${model.typeName} = {
|
|
31
|
-
${
|
|
25
|
+
${assignments}
|
|
32
26
|
}
|
|
33
27
|
|
|
34
28
|
/**
|
|
@@ -46,25 +40,38 @@ exports.generateStub = generateStub;
|
|
|
46
40
|
/**
|
|
47
41
|
* Return an assignment statement for a model where each field is assigned null or its type's default value.
|
|
48
42
|
*/
|
|
49
|
-
function
|
|
43
|
+
function getAssignmentStatementModel({ fields, imports }) {
|
|
50
44
|
return fields
|
|
51
45
|
.map((f) => {
|
|
52
46
|
if (!f.isRequired) {
|
|
53
47
|
return `${f.name}: null`;
|
|
54
48
|
}
|
|
55
49
|
switch (f.kind) {
|
|
56
|
-
case 'scalar':
|
|
50
|
+
case 'scalar': {
|
|
57
51
|
return `${f.name}: ${(0, fields_1.getDefaultValueForType)(f.typeName)}`;
|
|
58
|
-
|
|
52
|
+
}
|
|
53
|
+
case 'id': {
|
|
59
54
|
const idRefMeta = (0, meta_1.getModelMetadata)({ model: f.model });
|
|
55
|
+
imports.addImport({
|
|
56
|
+
items: [idRefMeta.types.toBrandedIdTypeFnName],
|
|
57
|
+
from: idRefMeta.types.importPath,
|
|
58
|
+
});
|
|
60
59
|
return `${f.name}: ${idRefMeta.types.toBrandedIdTypeFnName}(${(0, fields_1.getDefaultValueForType)(f.unbrandedTypeName)})`;
|
|
61
|
-
|
|
60
|
+
}
|
|
61
|
+
case 'relation': {
|
|
62
62
|
const refModelMeta = (0, meta_1.getModelMetadata)({ model: f.relationToModel });
|
|
63
|
+
imports.addImport({
|
|
64
|
+
items: [refModelMeta.types.toBrandedIdTypeFnName],
|
|
65
|
+
from: refModelMeta.types.importPath,
|
|
66
|
+
});
|
|
63
67
|
return `${f.name}: ${refModelMeta.types.toBrandedIdTypeFnName}(${(0, fields_1.getDefaultValueForType)(f.unbrandedTypeName)})`;
|
|
64
|
-
|
|
68
|
+
}
|
|
69
|
+
case 'enum': {
|
|
65
70
|
return `${f.name}: "${f.enumerator.values[0]}"`;
|
|
66
|
-
|
|
71
|
+
}
|
|
72
|
+
default: {
|
|
67
73
|
throw new types_1.ExhaustiveSwitchCheck(f);
|
|
74
|
+
}
|
|
68
75
|
}
|
|
69
76
|
})
|
|
70
77
|
.join(',\n');
|
|
@@ -12,6 +12,7 @@ const types_1 = require("../../lib/types");
|
|
|
12
12
|
function generateModelTypes({ model, meta }) {
|
|
13
13
|
const idField = model.idField;
|
|
14
14
|
const imports = imports_1.ImportsGenerator.from(meta.types.filePath);
|
|
15
|
+
let hasLinkedItems = false;
|
|
15
16
|
for (const relation of (0, fields_1.getRelationFields)(model)) {
|
|
16
17
|
if (relation.relationToModel.typeName === model.typeName) {
|
|
17
18
|
continue;
|
|
@@ -19,9 +20,10 @@ function generateModelTypes({ model, meta }) {
|
|
|
19
20
|
const refModel = relation.relationToModel;
|
|
20
21
|
const refMeta = (0, meta_1.getModelMetadata)({ model: refModel });
|
|
21
22
|
imports.addImport({
|
|
22
|
-
items: [refMeta.types.toBrandedIdTypeFnName, refModel.brandedIdType],
|
|
23
|
+
items: [refMeta.types.toBrandedIdTypeFnName, refModel.brandedIdType, refMeta.types.typeName],
|
|
23
24
|
from: refMeta.types.filePath,
|
|
24
25
|
});
|
|
26
|
+
hasLinkedItems = true;
|
|
25
27
|
}
|
|
26
28
|
for (const f of (0, fields_1.getEnumFields)(model)) {
|
|
27
29
|
const refEnumMeta = (0, meta_1.getEnumMetadata)({ enumerator: f.enumerator });
|
|
@@ -42,7 +44,7 @@ ${model.description
|
|
|
42
44
|
* ${model.description.split('\n').join('\n * ')}
|
|
43
45
|
*/`
|
|
44
46
|
: ''}
|
|
45
|
-
export type ${
|
|
47
|
+
export type ${meta.types.typeName} = {
|
|
46
48
|
${model.fields
|
|
47
49
|
.map((f) => `
|
|
48
50
|
${getFieldComment(f)}
|
|
@@ -50,6 +52,17 @@ ${f.name}: ${getFieldType(f)}${f.isRequired ? '' : ' | null'}`)
|
|
|
50
52
|
.join('\n')}
|
|
51
53
|
}
|
|
52
54
|
|
|
55
|
+
${!hasLinkedItems
|
|
56
|
+
? ``
|
|
57
|
+
: `
|
|
58
|
+
export type ${meta.types.linkedTypeName} = {
|
|
59
|
+
${model.fields
|
|
60
|
+
.map((f) => `
|
|
61
|
+
${getFieldComment(f)}
|
|
62
|
+
${getLinkedFieldType(f)}${f.isRequired ? '' : ' | null'}`)
|
|
63
|
+
.join('\n')}
|
|
64
|
+
}`}
|
|
65
|
+
|
|
53
66
|
/**
|
|
54
67
|
* Branded Id type that should be used to identify an instance of this model.
|
|
55
68
|
*/
|
|
@@ -90,8 +103,9 @@ function getFieldComment(f) {
|
|
|
90
103
|
${comment}*/`;
|
|
91
104
|
}
|
|
92
105
|
function getFieldExamples(f) {
|
|
93
|
-
if (!f.attributes.examples)
|
|
106
|
+
if (!f.attributes.examples) {
|
|
94
107
|
return undefined;
|
|
108
|
+
}
|
|
95
109
|
return `Examples: ${f.attributes.examples.map((e) => `"${e}"`).join(', ')}`;
|
|
96
110
|
}
|
|
97
111
|
/**
|
|
@@ -111,3 +125,20 @@ function getFieldType(f) {
|
|
|
111
125
|
throw new types_1.ExhaustiveSwitchCheck(f);
|
|
112
126
|
}
|
|
113
127
|
}
|
|
128
|
+
/**
|
|
129
|
+
* Converts a field to a TypeScript type definition with linked fields.
|
|
130
|
+
*/
|
|
131
|
+
function getLinkedFieldType(f) {
|
|
132
|
+
switch (f.kind) {
|
|
133
|
+
case 'enum':
|
|
134
|
+
return `${f.name}: ${f.typeName}`;
|
|
135
|
+
case 'relation':
|
|
136
|
+
return `${f.relatedModelBacklinkFieldName}: ${f.relationToModel.typeName}`;
|
|
137
|
+
case 'id':
|
|
138
|
+
return `${f.name}: ${f.model.brandedIdType}`;
|
|
139
|
+
case 'scalar':
|
|
140
|
+
return `${f.name}: ${f.typeName}`;
|
|
141
|
+
default:
|
|
142
|
+
throw new types_1.ExhaustiveSwitchCheck(f);
|
|
143
|
+
}
|
|
144
|
+
}
|
package/dist/lib/attributes.d.ts
CHANGED
|
@@ -51,7 +51,7 @@ export type FieldAttributes = {
|
|
|
51
51
|
/**
|
|
52
52
|
* Schema tag: ´@@Examples("Example1", "Example2")`
|
|
53
53
|
*/
|
|
54
|
-
examples?:
|
|
54
|
+
examples?: (string | number | boolean)[];
|
|
55
55
|
/**
|
|
56
56
|
* Schema tag: ´@@DefaultField()`
|
|
57
57
|
* The property of the model that identifies the default row.
|
package/dist/lib/imports.d.ts
CHANGED
|
@@ -25,7 +25,7 @@ export declare class ImportsGenerator {
|
|
|
25
25
|
* NOTE: You should never add no items from a given path.
|
|
26
26
|
*/
|
|
27
27
|
addImport({ items, from, }: {
|
|
28
|
-
items: (Types.
|
|
28
|
+
items: (Types.Fnction | Types.ClassName | Types.TypeName | Types.VariableName)[];
|
|
29
29
|
from: Types.Path;
|
|
30
30
|
}): ImportsGenerator;
|
|
31
31
|
/**
|
package/dist/lib/imports.js
CHANGED
|
@@ -41,15 +41,24 @@ class ImportsGenerator {
|
|
|
41
41
|
* Returns the TypeScript import statement.
|
|
42
42
|
*/
|
|
43
43
|
generate() {
|
|
44
|
-
const
|
|
45
|
-
.sort(([a], [b]) =>
|
|
44
|
+
const statements = Object.entries(this._imports)
|
|
45
|
+
.sort(([a], [b]) => {
|
|
46
|
+
// //in case a or b start with "@", they will be sorted first
|
|
47
|
+
// if (a.startsWith('@') && !b.startsWith('@')) {
|
|
48
|
+
// return -1
|
|
49
|
+
// }
|
|
50
|
+
// if (!a.startsWith('@') && b.startsWith('@')) {
|
|
51
|
+
// return 1
|
|
52
|
+
// }
|
|
53
|
+
return a.localeCompare(b);
|
|
54
|
+
})
|
|
46
55
|
.map(([path, items]) => {
|
|
47
56
|
const alphabeticallySortedItems = Array.from(items).sort((a, b) => a.localeCompare(b));
|
|
48
57
|
// NOTE: You cannot remove imports and we check that there's at least one imported item for every path.
|
|
49
58
|
return `import { ${alphabeticallySortedItems.join(', ')} } from '${path}'`;
|
|
50
59
|
})
|
|
51
60
|
.join('\n');
|
|
52
|
-
return
|
|
61
|
+
return statements;
|
|
53
62
|
}
|
|
54
63
|
}
|
|
55
64
|
exports.ImportsGenerator = ImportsGenerator;
|