@postxl/generator 0.0.1

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 (95) hide show
  1. package/README.md +3 -0
  2. package/dist/jest.config.d.ts +3 -0
  3. package/dist/src/generator.d.ts +12 -0
  4. package/dist/src/generator.js +164 -0
  5. package/dist/src/generators/enums/react.generator.d.ts +10 -0
  6. package/dist/src/generators/enums/react.generator.js +81 -0
  7. package/dist/src/generators/enums/types.generator.d.ts +10 -0
  8. package/dist/src/generators/enums/types.generator.js +18 -0
  9. package/dist/src/generators/indices/datamockmodule.generator.d.ts +9 -0
  10. package/dist/src/generators/indices/datamockmodule.generator.js +104 -0
  11. package/dist/src/generators/indices/datamodule.generator.d.ts +9 -0
  12. package/dist/src/generators/indices/datamodule.generator.js +128 -0
  13. package/dist/src/generators/indices/dataservice.generator.d.ts +9 -0
  14. package/dist/src/generators/indices/dataservice.generator.js +47 -0
  15. package/dist/src/generators/indices/repositories.generator.d.ts +9 -0
  16. package/dist/src/generators/indices/repositories.generator.js +17 -0
  17. package/dist/src/generators/indices/seed.generator.d.ts +9 -0
  18. package/dist/src/generators/indices/seed.generator.js +17 -0
  19. package/dist/src/generators/indices/stubs.generator.d.ts +9 -0
  20. package/dist/src/generators/indices/stubs.generator.js +17 -0
  21. package/dist/src/generators/indices/testdataservice.generator.d.ts +7 -0
  22. package/dist/src/generators/indices/testdataservice.generator.js +61 -0
  23. package/dist/src/generators/indices/types.generator.d.ts +10 -0
  24. package/dist/src/generators/indices/types.generator.js +21 -0
  25. package/dist/src/generators/models/react.generator/context.generator.d.ts +9 -0
  26. package/dist/src/generators/models/react.generator/context.generator.js +66 -0
  27. package/dist/src/generators/models/react.generator/index.d.ts +10 -0
  28. package/dist/src/generators/models/react.generator/index.js +32 -0
  29. package/dist/src/generators/models/react.generator/library.generator.d.ts +9 -0
  30. package/dist/src/generators/models/react.generator/library.generator.js +113 -0
  31. package/dist/src/generators/models/react.generator/lookup.generator.d.ts +9 -0
  32. package/dist/src/generators/models/react.generator/lookup.generator.js +97 -0
  33. package/dist/src/generators/models/react.generator/modals.generator.d.ts +23 -0
  34. package/dist/src/generators/models/react.generator/modals.generator.js +521 -0
  35. package/dist/src/generators/models/repository.generator.d.ts +9 -0
  36. package/dist/src/generators/models/repository.generator.js +282 -0
  37. package/dist/src/generators/models/route.generator.d.ts +16 -0
  38. package/dist/src/generators/models/route.generator.js +112 -0
  39. package/dist/src/generators/models/seed.generator.d.ts +20 -0
  40. package/dist/src/generators/models/seed.generator.js +185 -0
  41. package/dist/src/generators/models/stub.generator.d.ts +9 -0
  42. package/dist/src/generators/models/stub.generator.js +74 -0
  43. package/dist/src/generators/models/types.generator.d.ts +9 -0
  44. package/dist/src/generators/models/types.generator.js +116 -0
  45. package/dist/src/lib/attributes.d.ts +43 -0
  46. package/dist/src/lib/attributes.js +2 -0
  47. package/dist/src/lib/exports.d.ts +26 -0
  48. package/dist/src/lib/exports.js +38 -0
  49. package/dist/src/lib/imports.d.ts +35 -0
  50. package/dist/src/lib/imports.js +55 -0
  51. package/dist/src/lib/meta.d.ts +359 -0
  52. package/dist/src/lib/meta.js +195 -0
  53. package/dist/src/lib/schema/fields.d.ts +35 -0
  54. package/dist/src/lib/schema/fields.js +49 -0
  55. package/dist/src/lib/schema/schema.d.ts +275 -0
  56. package/dist/src/lib/schema/schema.js +2 -0
  57. package/dist/src/lib/schema/types.d.ts +72 -0
  58. package/dist/src/lib/schema/types.js +41 -0
  59. package/dist/src/lib/schema/zod.d.ts +8 -0
  60. package/dist/src/lib/schema/zod.js +44 -0
  61. package/dist/src/lib/serializer.d.ts +15 -0
  62. package/dist/src/lib/serializer.js +24 -0
  63. package/dist/src/lib/utils/error.d.ts +5 -0
  64. package/dist/src/lib/utils/error.js +13 -0
  65. package/dist/src/lib/utils/file.d.ts +10 -0
  66. package/dist/src/lib/utils/file.js +54 -0
  67. package/dist/src/lib/utils/logger.d.ts +11 -0
  68. package/dist/src/lib/utils/logger.js +2 -0
  69. package/dist/src/lib/utils/string.d.ts +29 -0
  70. package/dist/src/lib/utils/string.js +75 -0
  71. package/dist/src/lib/utils/types.d.ts +12 -0
  72. package/dist/src/lib/utils/types.js +2 -0
  73. package/dist/src/lib/vfs.d.ts +137 -0
  74. package/dist/src/lib/vfs.js +419 -0
  75. package/dist/src/prisma/attributes.d.ts +17 -0
  76. package/dist/src/prisma/attributes.js +80 -0
  77. package/dist/src/prisma/client-path.d.ts +7 -0
  78. package/dist/src/prisma/client-path.js +29 -0
  79. package/dist/src/prisma/parse.d.ts +12 -0
  80. package/dist/src/prisma/parse.js +276 -0
  81. package/dist/tests/attributes.test.d.ts +1 -0
  82. package/dist/tests/attributes.test.js +76 -0
  83. package/dist/tests/file.test.d.ts +1 -0
  84. package/dist/tests/file.test.js +26 -0
  85. package/dist/tests/utils/random.d.ts +3 -0
  86. package/dist/tests/utils/random.js +15 -0
  87. package/dist/tests/vfs.test.d.ts +1 -0
  88. package/dist/tests/vfs.test.js +74 -0
  89. package/dist/tsconfig.tsbuildinfo +1 -0
  90. package/jest.config.ts +18 -0
  91. package/package.json +42 -0
  92. package/tests/attributes.test.ts +91 -0
  93. package/tests/file.test.ts +32 -0
  94. package/tests/utils/random.ts +11 -0
  95. package/tests/vfs.test.ts +92 -0
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getFieldAttributes = exports.getModelAttributes = exports.parseArgumentToStringOrStringArray = exports.parseAttributesFromDocumentation = void 0;
4
+ const remeda_1 = require("remeda");
5
+ const string_1 = require("../lib/utils/string");
6
+ /**
7
+ * Parses attributes from a given string using provided prefix.
8
+ */
9
+ function parseAttributesFromDocumentation({ documentation }) {
10
+ const prefix = '@@';
11
+ if (!documentation)
12
+ return {};
13
+ return documentation
14
+ .split('\n')
15
+ .filter((d) => d.startsWith(prefix))
16
+ .map((d) => d.replace(prefix, ''))
17
+ .reduce((acc, line) => {
18
+ const pattern = /(\w+)\((.*?)\)$/;
19
+ if (!pattern.test(line))
20
+ return acc;
21
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
22
+ const [attribute, arg] = line.match(pattern).slice(1);
23
+ acc[(0, string_1.toCamelCase)(attribute)] = parseArgumentToStringOrStringArray(arg);
24
+ return acc;
25
+ }, {});
26
+ }
27
+ exports.parseAttributesFromDocumentation = parseAttributesFromDocumentation;
28
+ function parseArgumentToStringOrStringArray(str) {
29
+ if (str === '')
30
+ return '';
31
+ try {
32
+ return JSON.parse(str);
33
+ }
34
+ catch (_a) {
35
+ try {
36
+ return JSON.parse(`[${str}]`);
37
+ }
38
+ catch (_b) {
39
+ console.log(str);
40
+ return JSON.parse(`"${str}"`);
41
+ }
42
+ }
43
+ }
44
+ exports.parseArgumentToStringOrStringArray = parseArgumentToStringOrStringArray;
45
+ /**
46
+ * Returns attribute information for a given model.
47
+ */
48
+ function getModelAttributes(model) {
49
+ const attributes = parseAttributesFromDocumentation(model);
50
+ return {
51
+ ignore: Object.hasOwn(attributes, 'ignore'),
52
+ skipUpdate: Object.hasOwn(attributes, 'skipUpdate') || Object.hasOwn(attributes, 'customUpdate'),
53
+ skipCreate: Object.hasOwn(attributes, 'skipCreate') || Object.hasOwn(attributes, 'customCreate'),
54
+ skipDelete: Object.hasOwn(attributes, 'skipDelete') || Object.hasOwn(attributes, 'customDelete'),
55
+ description: attributes.description && (0, remeda_1.isString)(attributes.description) ? attributes.description : undefined,
56
+ };
57
+ }
58
+ exports.getModelAttributes = getModelAttributes;
59
+ /**
60
+ * Returns all attributes assigned to a field
61
+ */
62
+ function getFieldAttributes(field) {
63
+ const attributes = parseAttributesFromDocumentation(field);
64
+ if (attributes.examples === undefined && attributes.example !== undefined) {
65
+ attributes.examples = attributes.example;
66
+ }
67
+ return {
68
+ // Prisma also has an "@ignore" attribute - see https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference#ignore
69
+ // we handle this the same way as our custom "ignore" attribute
70
+ ignore: field.isIgnored || Object.hasOwn(attributes, 'ignore'),
71
+ description: attributes.description && (0, remeda_1.isString)(attributes.description) ? attributes.description : undefined,
72
+ isDefaultField: Object.hasOwn(attributes, 'isDefaultField'),
73
+ examples: !attributes.examples
74
+ ? undefined
75
+ : Array.isArray(attributes.examples)
76
+ ? attributes.examples
77
+ : [attributes.examples],
78
+ };
79
+ }
80
+ exports.getFieldAttributes = getFieldAttributes;
@@ -0,0 +1,7 @@
1
+ import { GeneratorConfig } from '@prisma/generator-helper';
2
+ /**
3
+ * Returns the the Node import path for the Prisma Client.
4
+ *
5
+ * NOTE: This should normally be @prisma/client, but can be different if output is specified in schema.prisma.
6
+ */
7
+ export declare function getClientImportPath(generators: GeneratorConfig[]): string;
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getClientImportPath = void 0;
4
+ /**
5
+ * Returns the the Node import path for the Prisma Client.
6
+ *
7
+ * NOTE: This should normally be @prisma/client, but can be different if output is specified in schema.prisma.
8
+ */
9
+ function getClientImportPath(generators) {
10
+ var _a;
11
+ const clientGenerator = generators.find((g) => g.provider.value === 'prisma-client-js');
12
+ if (!clientGenerator) {
13
+ return '@prisma/client';
14
+ }
15
+ const output = (_a = clientGenerator.output) === null || _a === void 0 ? void 0 : _a.value;
16
+ if (!output) {
17
+ return '@prisma/client';
18
+ }
19
+ //if output contains @..., return everything starting from @ and replace \\ with /
20
+ if (output.includes('@')) {
21
+ return output.substring(output.lastIndexOf('@')).replace(/\\/g, '/');
22
+ }
23
+ //if output contains node_modules, return everything after node_modules and replace \\ with /
24
+ if (output.includes('node_modules')) {
25
+ return output.substring(output.indexOf('node_modules') + 'node_modules'.length).replace(/\\/g, '/');
26
+ }
27
+ return '@prisma/client';
28
+ }
29
+ exports.getClientImportPath = getClientImportPath;
@@ -0,0 +1,12 @@
1
+ import { DMMF } from '@prisma/generator-helper';
2
+ import * as Schema from '../lib/schema/schema';
3
+ /**
4
+ * Converts a Prisma schema (DMMF) document to a Schema that's passed around generators.
5
+ */
6
+ export declare function parsePrismaSchema({ datamodel: { enums: enumsRaw, models: modelsRaw }, config, }: {
7
+ datamodel: DMMF.Datamodel;
8
+ config: Schema.SchemaConfig;
9
+ }): {
10
+ models: Schema.Model[];
11
+ enums: Schema.Enum[];
12
+ };
@@ -0,0 +1,276 @@
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.parsePrismaSchema = void 0;
27
+ const Types = __importStar(require("../lib/schema/types"));
28
+ const error_1 = require("../lib/utils/error");
29
+ const string_1 = require("../lib/utils/string");
30
+ const attributes_1 = require("./attributes");
31
+ /**
32
+ * Converts a Prisma schema (DMMF) document to a Schema that's passed around generators.
33
+ */
34
+ function parsePrismaSchema({ datamodel: { enums: enumsRaw, models: modelsRaw }, config, }) {
35
+ // NOTE: We preprocess models and enums so that we can populate relationships.
36
+ const models = modelsRaw.map((dmmfModel) => parseModelCore({ dmmfModel, config }));
37
+ const enums = enumsRaw.map((dmmfEnum) => parseEnum({ dmmfEnum, config }));
38
+ const modelsWithFields = modelsRaw
39
+ .map((dmmfModel) => parseModel({ dmmfModel, models, enums, config }))
40
+ .filter((model) => !model.attributes.ignore);
41
+ return { models: modelsWithFields, enums };
42
+ }
43
+ exports.parsePrismaSchema = parsePrismaSchema;
44
+ /**
45
+ * Parses the core properties of a model without fields.
46
+ */
47
+ function parseModelCore({ dmmfModel, config, }) {
48
+ const attributes = (0, attributes_1.getModelAttributes)(dmmfModel);
49
+ return {
50
+ name: (0, string_1.toPascalCase)(dmmfModel.name),
51
+ description: attributes.description,
52
+ typeName: Types.toTypeName((0, string_1.toPascalCase)(dmmfModel.name)),
53
+ sourceName: dmmfModel.name,
54
+ brandedIdType: Types.toTypeName(`${(0, string_1.toPascalCase)(dmmfModel.name)}Id`),
55
+ attributes,
56
+ schemaConfig: config,
57
+ };
58
+ }
59
+ /**
60
+ * Converts a preprocessed model (with DMMF model) to a complete Schema.Model
61
+ * by extracting/converting fields from DMMF and attaching them to the model
62
+ */
63
+ function parseModel({ dmmfModel, enums, models, config, }) {
64
+ const core = parseModelCore({ dmmfModel, config });
65
+ // NOTE: We assume that each relation may only reference one field. Because of this,
66
+ // we can "relate" a given relation to a scalar field used in the relation.
67
+ // Since Prisma doesn't mark those fields as relations, we need to preprocess
68
+ // relations and then figure out which scalar fields are used in relations.
69
+ const relations = {};
70
+ for (const dmmfField of dmmfModel.fields) {
71
+ if (dmmfField.kind !== 'object' ||
72
+ !dmmfField.relationName ||
73
+ !dmmfField.relationFromFields ||
74
+ !dmmfField.relationToFields) {
75
+ continue;
76
+ }
77
+ if (dmmfField.relationFromFields.length > 1) {
78
+ throw new Error(`❌❌❌ Relation ${dmmfField.relationName} has more than one from field`);
79
+ }
80
+ const referencedModel = models.find((m) => m.sourceName === dmmfField.type);
81
+ if (!referencedModel) {
82
+ (0, error_1.throwError)(`Investigate: Field references unknown model ${dmmfField.type}.`);
83
+ }
84
+ relations[dmmfField.relationFromFields[0]] = referencedModel;
85
+ }
86
+ const fields = dmmfModel.fields
87
+ .filter((dmmfField) =>
88
+ // if field is a "backlink", i.e. the reciever of a relation, we ignore it
89
+ dmmfField.kind !== 'object')
90
+ .map((dmmfField) => {
91
+ const attributes = (0, attributes_1.getFieldAttributes)(dmmfField);
92
+ const shared = {
93
+ name: (0, string_1.toCamelCase)(dmmfField.name),
94
+ description: attributes.description,
95
+ sourceName: dmmfField.name,
96
+ isRequired: dmmfField.isRequired,
97
+ attributes,
98
+ schemaConfig: config,
99
+ };
100
+ // NOTE: We mark scalar fields which are used in relations as relation fields by Purple Schema standards.
101
+ if (dmmfField.name in relations) {
102
+ const refModel = relations[dmmfField.name];
103
+ return Object.assign(Object.assign({ kind: 'relation' }, shared), { typeName: Types.toTypeName(dmmfField.type), unbrandedTypeName: getTsTypeForId(dmmfField), relationToModel: refModel });
104
+ }
105
+ if (dmmfField.isId) {
106
+ return Object.assign(Object.assign({ kind: 'id' }, shared), { isUnique: isUniqueField(dmmfField), isGenerated: isAutoIncrementField(dmmfField), unbrandedTypeName: getTsTypeForId(dmmfField), model: core });
107
+ }
108
+ if (dmmfField.kind === 'scalar') {
109
+ let validation = undefined;
110
+ if (dmmfField.type === 'Int') {
111
+ validation = { type: 'int' };
112
+ }
113
+ if (dmmfField.type === 'Float') {
114
+ validation = { type: 'float' };
115
+ }
116
+ return Object.assign(Object.assign({ kind: 'scalar' }, shared), { isUnique: isUniqueField(dmmfField), isGenerated: isAutoIncrementField(dmmfField), typeName: getTsTypeForScalar(dmmfField) });
117
+ }
118
+ if (dmmfField.kind === 'enum') {
119
+ const fieldEnumDef = enums.find((e) => e.sourceName === dmmfField.type);
120
+ if (!fieldEnumDef) {
121
+ (0, error_1.throwError)(`Investigate: Field references unknown enum ${dmmfField.type}.`);
122
+ }
123
+ return Object.assign(Object.assign({ kind: 'enum' }, shared), { typeName: getTsTypeForEnum(dmmfField), enumerator: fieldEnumDef });
124
+ }
125
+ (0, error_1.throwError)(`Investigate: Field ${shared.sourceName}.${shared.sourceName} is not scalar, enum nor relation.`);
126
+ })
127
+ .filter((field) => !isFieldIgnored({ field }));
128
+ const { idField, defaultField, nameField } = validateFields({ fields, model: core });
129
+ return Object.assign(Object.assign({}, core), { idField,
130
+ defaultField,
131
+ nameField,
132
+ fields });
133
+ }
134
+ /**
135
+ * Checks that there is exactly one id field and that there is at most one default field.
136
+ */
137
+ function validateFields({ fields, model: { name } }) {
138
+ let idField = undefined;
139
+ let nameField = undefined;
140
+ let nameFieldFallback = undefined;
141
+ let defaultField = undefined;
142
+ for (const field of fields) {
143
+ switch (field.kind) {
144
+ case 'scalar':
145
+ if (field.name === 'name') {
146
+ nameFieldFallback = field;
147
+ }
148
+ break;
149
+ case 'id':
150
+ if (idField) {
151
+ throw new Error(`❌❌❌ Model ${name} has multiple id fields`);
152
+ }
153
+ idField = field;
154
+ break;
155
+ case 'relation':
156
+ break;
157
+ case 'enum':
158
+ break;
159
+ }
160
+ //handle default case
161
+ if (Object.hasOwn(field.attributes, 'isDefault') && field.kind === 'scalar') {
162
+ if (defaultField !== undefined) {
163
+ throw new Error(`❌❌❌ Model ${name} has multiple default fields`);
164
+ }
165
+ defaultField = field;
166
+ }
167
+ //handle name field
168
+ if ((Object.hasOwn(field.attributes, 'name') || Object.hasOwn(field.attributes, 'label')) &&
169
+ field.kind === 'scalar') {
170
+ if (name !== undefined) {
171
+ throw new Error(`❌❌❌ Model ${name} has multiple name fields`);
172
+ }
173
+ nameField = field;
174
+ }
175
+ }
176
+ if (!idField) {
177
+ throw new Error(`❌❌❌ Model ${name} does not have an id field`);
178
+ }
179
+ if (!nameField && nameFieldFallback) {
180
+ nameField = nameFieldFallback;
181
+ }
182
+ return { idField, defaultField, nameField };
183
+ }
184
+ function isAutoIncrementField(fieldDmmf) {
185
+ const d = fieldDmmf.default;
186
+ return d !== undefined && !!d.name && d.name === 'autoincrement';
187
+ }
188
+ function isUniqueField(fieldRaw) {
189
+ return fieldRaw.isUnique && fieldRaw.type === 'String';
190
+ }
191
+ /**
192
+ * Tells whether the parsed schema should skip a given field.
193
+ */
194
+ function isFieldIgnored({ field }) {
195
+ if (field.name === 'createdAt' || field.name === 'updatedAt' || field.name === 'deletedAt') {
196
+ return true;
197
+ }
198
+ if (Object.hasOwn(field.attributes, 'ignore') && field.attributes.ignore) {
199
+ return true;
200
+ }
201
+ if (field.kind === 'relation' && field.relationToModel.attributes.ignore) {
202
+ return true;
203
+ }
204
+ return false;
205
+ }
206
+ /**
207
+ * Parses a given enumerator type.
208
+ */
209
+ function parseEnum({ dmmfEnum, config }) {
210
+ return {
211
+ name: dmmfEnum.name,
212
+ typeName: Types.toTypeName((0, string_1.toPascalCase)(dmmfEnum.name)),
213
+ sourceName: dmmfEnum.name,
214
+ values: dmmfEnum.values.map((v) => v.name),
215
+ schemaConfig: config,
216
+ };
217
+ }
218
+ /**
219
+ * Returns the TypeScript type of a scalar database field
220
+ */
221
+ function getTsTypeForScalar(field) {
222
+ switch (field.type) {
223
+ case 'BigInt':
224
+ case 'String':
225
+ return Types.toTypeName('string');
226
+ case 'Boolean':
227
+ return Types.toTypeName('boolean');
228
+ case 'DateTime':
229
+ return Types.toTypeName('Date');
230
+ case 'Decimal':
231
+ case 'Float':
232
+ case 'Int':
233
+ return Types.toTypeName('number');
234
+ case 'JSON':
235
+ case 'Bytes':
236
+ (0, error_1.throwError)('Not implemented yet');
237
+ default:
238
+ // return field.type
239
+ (0, error_1.throwError)(`Investigate: 'default' case in getTypescriptType for field ${field.name} of type ${field.type}`);
240
+ }
241
+ }
242
+ /**
243
+ * Returns the TypeScript type of a scalar id field.
244
+ */
245
+ function getTsTypeForId(field) {
246
+ switch (field.type) {
247
+ case 'BigInt':
248
+ case 'String':
249
+ return Types.toTypeName('string');
250
+ case 'Boolean':
251
+ return Types.toTypeName('boolean');
252
+ case 'Decimal':
253
+ case 'Float':
254
+ case 'Int':
255
+ return Types.toTypeName('number');
256
+ default:
257
+ (0, error_1.throwError)(`The id field ${field.name} is of type ${field.type} - but only BigInt, Boolean, Decimal, Float, Int and String are supported for Ids.`);
258
+ }
259
+ }
260
+ /**
261
+ * Returns the TypeScript type of an enum field.
262
+ */
263
+ function getTsTypeForEnum(field) {
264
+ switch (field.type) {
265
+ case 'String':
266
+ return Types.toTypeName('string');
267
+ case 'BigInt':
268
+ case 'Boolean':
269
+ case 'Decimal':
270
+ case 'Float':
271
+ case 'Int':
272
+ (0, error_1.throwError)(`The enum field ${field.name} is of type ${field.type} - but only String fields are supported for enums so far.`);
273
+ default:
274
+ return Types.toTypeName(field.type);
275
+ }
276
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const attributes_1 = require("../src/prisma/attributes");
4
+ describe('argument parser', () => {
5
+ test('Blank argument should return blank string', () => {
6
+ expect((0, attributes_1.parseArgumentToStringOrStringArray)('')).toEqual('');
7
+ });
8
+ test('Argument without quotes should return as is', () => {
9
+ expect((0, attributes_1.parseArgumentToStringOrStringArray)('example')).toEqual('example');
10
+ });
11
+ test('Argument with quotes should return without quotes', () => {
12
+ expect((0, attributes_1.parseArgumentToStringOrStringArray)('"example"')).toEqual('example');
13
+ });
14
+ test('Argument with escaped quotes should return without quotes', () => {
15
+ expect((0, attributes_1.parseArgumentToStringOrStringArray)('"example \\"with quotes\\""')).toEqual('example "with quotes"');
16
+ });
17
+ test('Argument with array of strings should convert to array', () => {
18
+ expect((0, attributes_1.parseArgumentToStringOrStringArray)('["example1", "example2"]')).toEqual(['example1', 'example2']);
19
+ });
20
+ });
21
+ describe('attribute parser', () => {
22
+ test('Missing documentation should return blank object', () => {
23
+ expect((0, attributes_1.parseAttributesFromDocumentation)({})).toEqual({});
24
+ });
25
+ test('Entries without "@@" should be ignored', () => {
26
+ expect((0, attributes_1.parseAttributesFromDocumentation)({ documentation: 'Some documentation' })).toEqual({});
27
+ });
28
+ test('Entries with "@@" should be parsed', () => {
29
+ expect((0, attributes_1.parseAttributesFromDocumentation)({ documentation: '@@ignore()' })).toEqual({ ignore: '' });
30
+ });
31
+ test('Attributes should be converted to camelCase', () => {
32
+ expect((0, attributes_1.parseAttributesFromDocumentation)({ documentation: '@@IGNORE()' })).toEqual({ iGNORE: '' });
33
+ });
34
+ });
35
+ describe('model attribute: ignore', () => {
36
+ test('should default to false', () => {
37
+ expect((0, attributes_1.getModelAttributes)({}).ignore).toBe(false);
38
+ expect((0, attributes_1.getModelAttributes)({ documentation: '' }).ignore).toBe(false);
39
+ expect((0, attributes_1.getModelAttributes)({ documentation: '@@test()' }).ignore).toBe(false);
40
+ });
41
+ test('should be true if @@ignore attribute is provided', () => {
42
+ expect((0, attributes_1.getModelAttributes)({ documentation: '@@ignore()' }).ignore).toBe(true);
43
+ });
44
+ });
45
+ describe('field attribute: ignore', () => {
46
+ test('should default to false', () => {
47
+ expect((0, attributes_1.getFieldAttributes)({}).ignore).toBe(false);
48
+ expect((0, attributes_1.getFieldAttributes)({ documentation: '' }).ignore).toBe(false);
49
+ expect((0, attributes_1.getFieldAttributes)({ documentation: '@@test()' }).ignore).toBe(false);
50
+ });
51
+ test('should be true if @@ignore attribute is provided', () => {
52
+ expect((0, attributes_1.getFieldAttributes)({ documentation: '@@ignore()' }).ignore).toBe(true);
53
+ });
54
+ test('should be true if Prisma field has isIgnored flag set to true', () => {
55
+ expect((0, attributes_1.getFieldAttributes)({ isIgnored: true }).ignore).toBe(true);
56
+ });
57
+ });
58
+ describe('field attributes: example and examples', () => {
59
+ test('should default to undefined', () => {
60
+ expect((0, attributes_1.getFieldAttributes)({}).examples).toBe(undefined);
61
+ });
62
+ test('should parse "@@examples" attribute', () => {
63
+ expect((0, attributes_1.getFieldAttributes)({ documentation: '@@examples("test")' }).examples).toStrictEqual(['test']);
64
+ });
65
+ test('should parse "@@example" attribute', () => {
66
+ expect((0, attributes_1.getFieldAttributes)({ documentation: '@@example("test")' }).examples).toStrictEqual(['test']);
67
+ });
68
+ test('should give precedence to "@@examples" over "@@example" attribute', () => {
69
+ expect((0, attributes_1.getFieldAttributes)({ documentation: '@@example("B")\n@@examples("A")' }).examples).toStrictEqual([
70
+ 'A',
71
+ ]);
72
+ });
73
+ test('should parse "@@example" attribute with an array of examples', () => {
74
+ expect((0, attributes_1.getFieldAttributes)({ documentation: '@@example("A", "B")' }).examples).toStrictEqual(['A', 'B']);
75
+ });
76
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const file_1 = require("../src/lib/utils/file");
4
+ describe('virtual file system', () => {
5
+ test('correctly resolves path to the same file', () => {
6
+ expect((0, file_1.getRelativePath)({ from: 'a/b/c', to: 'a/b/c' })).toEqual('./c');
7
+ });
8
+ test('correctly resolves path to a file in the same folder', () => {
9
+ expect((0, file_1.getRelativePath)({ from: 'a/b/c', to: 'a/b/d' })).toEqual('./d');
10
+ });
11
+ test('correclty, resolves path to a file in a parent folder', () => {
12
+ expect((0, file_1.getRelativePath)({ from: 'a/b/c', to: 'a/d' })).toEqual('../d');
13
+ });
14
+ test('correctly resolves completely different paths', () => {
15
+ expect((0, file_1.getRelativePath)({ from: 'a/b/c', to: 'd/e/f' })).toEqual('../../d/e/f');
16
+ });
17
+ test('correctly resolves path to a package', () => {
18
+ expect((0, file_1.getRelativePath)({ from: 'a/b/c', to: '@lib/package' })).toEqual('@lib/package');
19
+ });
20
+ test('correctly resolves relative paths', () => {
21
+ expect((0, file_1.getRelativePath)({
22
+ from: './backend/libs/data/src/services/data.module',
23
+ to: './backend/libs/data/src/repositories/country.repository',
24
+ })).toEqual('../repositories/country.repository');
25
+ });
26
+ });
@@ -0,0 +1,3 @@
1
+ export declare namespace RandomUtils {
2
+ function generateRandomAlphaNumericString(len: number): string;
3
+ }
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RandomUtils = void 0;
4
+ const ALPHANUMERIC_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
5
+ var RandomUtils;
6
+ (function (RandomUtils) {
7
+ function generateRandomAlphaNumericString(len) {
8
+ let text = '';
9
+ for (let i = 0; i < len; i++) {
10
+ text += ALPHANUMERIC_CHARS.charAt(Math.floor(Math.random() * ALPHANUMERIC_CHARS.length));
11
+ }
12
+ return text;
13
+ }
14
+ RandomUtils.generateRandomAlphaNumericString = generateRandomAlphaNumericString;
15
+ })(RandomUtils = exports.RandomUtils || (exports.RandomUtils = {}));
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const vfs_1 = require("../src/lib/vfs");
4
+ const random_1 = require("./utils/random");
5
+ function adjustPathToOS(path) {
6
+ return path.replace(/\//g, process.platform === 'win32' ? '\\' : '/');
7
+ }
8
+ describe('virtual file system', () => {
9
+ test('IO works', () => {
10
+ const vfs = new vfs_1.VirtualFS();
11
+ const files = [];
12
+ for (let depth = 0; depth < 100; depth++) {
13
+ const path = '/folder'.repeat(depth) + '/file.txt';
14
+ const content = random_1.RandomUtils.generateRandomAlphaNumericString(160);
15
+ const status = vfs.write(path, content);
16
+ expect(status.ok).toBeTruthy();
17
+ files.push({ path, content });
18
+ }
19
+ for (const { path, content } of files) {
20
+ const file = vfs.read(path);
21
+ expect(file).toEqual({ ok: true, content });
22
+ }
23
+ });
24
+ test('lists files correctly', () => {
25
+ const vfs = new vfs_1.VirtualFS();
26
+ vfs.write('/a.txt', 'a');
27
+ vfs.write('/b.txt', 'b');
28
+ vfs.write('/c.txt', 'c');
29
+ vfs.write('/sub/a.txt', 'a');
30
+ vfs.write('/sub/b.txt', 'b');
31
+ vfs.write('/sub/c.txt', 'c');
32
+ const files = vfs.list('/');
33
+ const subFiles = vfs.list('/sub');
34
+ expect(files).toHaveLength(4);
35
+ expect(files).toContainEqual({ kind: 'FILE', name: 'a.txt' });
36
+ expect(files).toContainEqual({ kind: 'FILE', name: 'b.txt' });
37
+ expect(files).toContainEqual({ kind: 'FILE', name: 'c.txt' });
38
+ expect(files).toContainEqual({ kind: 'FOLDER', name: 'sub' });
39
+ expect(subFiles).toHaveLength(3);
40
+ expect(subFiles).toContainEqual({ kind: 'FILE', name: 'a.txt' });
41
+ expect(subFiles).toContainEqual({ kind: 'FILE', name: 'b.txt' });
42
+ expect(subFiles).toContainEqual({ kind: 'FILE', name: 'c.txt' });
43
+ });
44
+ test('lists folders correctly', () => {
45
+ const vfs = new vfs_1.VirtualFS();
46
+ vfs.write('/a/b/a/file.txt', 'a');
47
+ vfs.write('/a/b/b/file.txt', 'b');
48
+ vfs.write('/a/b/c/file.txt', 'c');
49
+ vfs.write('/a/b/d/file.txt', 'd');
50
+ const folders = vfs.list('/a/b');
51
+ expect(folders).toHaveLength(4);
52
+ expect(folders).toContainEqual({ kind: 'FOLDER', name: 'a' });
53
+ expect(folders).toContainEqual({ kind: 'FOLDER', name: 'b' });
54
+ expect(folders).toContainEqual({ kind: 'FOLDER', name: 'c' });
55
+ expect(folders).toContainEqual({ kind: 'FOLDER', name: 'd' });
56
+ });
57
+ test('copies files correctly', () => {
58
+ const vfs = new vfs_1.VirtualFS();
59
+ const src = new vfs_1.VirtualFS();
60
+ src.write('/a.txt', 'a');
61
+ src.write('/b.txt', 'b');
62
+ src.write('/c.txt', 'c');
63
+ vfs.copy(src, '/');
64
+ vfs.copy(src, '/sub');
65
+ expect(vfs.files()).toEqual({
66
+ [adjustPathToOS('/a.txt')]: 'a',
67
+ [adjustPathToOS('/b.txt')]: 'b',
68
+ [adjustPathToOS('/c.txt')]: 'c',
69
+ [adjustPathToOS('/sub/a.txt')]: 'a',
70
+ [adjustPathToOS('/sub/b.txt')]: 'b',
71
+ [adjustPathToOS('/sub/c.txt')]: 'c',
72
+ });
73
+ });
74
+ });