rads-db 3.0.18 → 3.0.20

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/index.d.ts CHANGED
@@ -206,6 +206,7 @@ interface TypeDefinition {
206
206
  enumValues?: Record<string, EnumDefinition>;
207
207
  handle?: string;
208
208
  handlePlural?: string;
209
+ isExtending?: string;
209
210
  }
210
211
  interface FileUploadResult {
211
212
  url: string;
@@ -256,6 +257,7 @@ interface FieldDefinition {
256
257
  name: string;
257
258
  type: string;
258
259
  defaultValue?: any;
260
+ defaultValueClass?: string;
259
261
  defaultValueCopyFrom?: string;
260
262
  isRequired?: boolean;
261
263
  isArray?: boolean;
@@ -10,8 +10,77 @@ var _pluralize = _interopRequireDefault(require("pluralize"));
10
10
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
11
11
  const supportedPrimitiveTypes = ["string", "number", "boolean", "Record<string, string>", "Record<string, any>"];
12
12
  function parseSchema(typescriptFiles) {
13
+ const typeNodesMap = getTypeNodesMap(typescriptFiles);
14
+ const schema = getSchema(typeNodesMap);
15
+ resolveIsExtending(schema);
16
+ fillComputedDefinitionsForType(schema);
17
+ verifyDefaultValueTypes(schema, typeNodesMap);
18
+ verifyRelationFields(schema);
19
+ return schema;
20
+ }
21
+ function resolveIsExtending(schema) {
22
+ for (const key in schema) {
23
+ const isExtendingType = schema[key].isExtending;
24
+ if (!isExtendingType) continue;
25
+ if (!schema[isExtendingType]) throw new Error(`Unknown type: "${isExtendingType}"`);
26
+ schema[key].fields = {
27
+ ...schema[isExtendingType].fields,
28
+ ...schema[key].fields
29
+ };
30
+ schema[key].decorators = {
31
+ ...schema[isExtendingType].decorators,
32
+ ...schema[key].decorators
33
+ };
34
+ if (schema[key].decorators.entity && !schema[key].fields?.id) {
35
+ throw new Error(`Entity "${key}" must have an id`);
36
+ }
37
+ }
38
+ }
39
+ function getSchema(typeNodesMap) {
13
40
  const result = {};
14
- const typesMap = {};
41
+ for (const key in typeNodesMap) {
42
+ const {
43
+ node,
44
+ name
45
+ } = typeNodesMap[key];
46
+ if (![_typescript.SyntaxKind.ClassDeclaration, _typescript.SyntaxKind.TypeAliasDeclaration].includes(node.kind)) {
47
+ throw new Error(`Unexpected type kind - "${name}"`);
48
+ }
49
+ }
50
+ for (const key in typeNodesMap) {
51
+ if (result[key]) continue;
52
+ const {
53
+ node,
54
+ sourceFile,
55
+ name
56
+ } = typeNodesMap[key];
57
+ if (node.kind !== _typescript.SyntaxKind.ClassDeclaration) continue;
58
+ const parsedClass = parseClassDeclaration(node, name, {
59
+ typeNodesMap,
60
+ sourceFile,
61
+ result
62
+ });
63
+ result[key] = parsedClass;
64
+ }
65
+ for (const key in typeNodesMap) {
66
+ if (result[key]) continue;
67
+ const {
68
+ node,
69
+ sourceFile,
70
+ name
71
+ } = typeNodesMap[key];
72
+ if (node.kind !== _typescript.SyntaxKind.TypeAliasDeclaration) continue;
73
+ const parsedClass = parseTypeAliasDeclaration(node, name, {
74
+ typeNodesMap,
75
+ sourceFile,
76
+ result
77
+ });
78
+ result[key] = parsedClass;
79
+ }
80
+ return result;
81
+ }
82
+ function getTypeNodesMap(typescriptFiles) {
83
+ const typeNodesMap = {};
15
84
  for (const key in typescriptFiles) {
16
85
  const text = typescriptFiles[key];
17
86
  const sourceFile = (0, _typescript.createSourceFile)(`${key}.ts`, text, _typescript.ScriptTarget.Latest);
@@ -20,75 +89,44 @@ function parseSchema(typescriptFiles) {
20
89
  const nameNode = cd.name;
21
90
  if (!nameNode || nameNode.kind !== _typescript.SyntaxKind.Identifier) throw new Error("Cannot detect class name");
22
91
  const name = nameNode.text;
23
- typesMap[name] = {
92
+ typeNodesMap[name] = {
24
93
  name,
25
94
  node: cd,
26
95
  sourceFile
27
96
  };
28
97
  }
29
- if (!typesMap[key]) {
98
+ if (!typeNodesMap[key]) {
30
99
  throw new Error(`File ${key}.ts must contain class declaration with name "${key}"`);
31
100
  }
32
101
  }
33
- for (const key in typesMap) {
34
- if (result[key]) continue;
35
- const {
36
- node,
37
- sourceFile,
38
- name
39
- } = typesMap[key];
40
- const parsedClass = parseType(node, name, {
41
- typesMap,
42
- sourceFile,
43
- result
44
- });
45
- if (parsedClass.name !== key) throw new Error(`File name must correspond to exported class name ("${key}", "${parsedClass.name}")`);
46
- result[key] = parsedClass;
47
- }
48
- for (const key in result) {
49
- const isExtendingType = result[key].isExtending;
50
- if (!isExtendingType) continue;
51
- if (!result[isExtendingType]) throw new Error(`Unknown type: "${isExtendingType}"`);
52
- result[key].fields = {
53
- ...result[isExtendingType].fields,
54
- ...result[key].fields
55
- };
56
- result[key].decorators = {
57
- ...result[isExtendingType].decorators,
58
- ...result[key].decorators
59
- };
60
- if (result[key].decorators.entity && !result[key].fields?.id) {
61
- throw new Error(`Entity "${key}" must have an id`);
62
- }
63
- }
64
- fillComputedDefinitionsForType(result);
65
- processThisReferenceDefaultValues(result, typesMap);
66
- verifyRelationFields(result);
67
- return result;
102
+ return typeNodesMap;
68
103
  }
69
- function processThisReferenceDefaultValues(result, typesMap) {
70
- for (const key in result) {
71
- const type = result[key];
104
+ function verifyDefaultValueTypes(schema, typeNodesMap) {
105
+ for (const key in schema) {
106
+ const type = schema[key];
72
107
  const fields = type.fields;
73
108
  if (!fields) continue;
74
109
  for (const fName in fields) {
75
110
  const field = fields[fName];
76
- if (field.defaultValueCopyFrom) {
77
- const sourceField = fields[field.defaultValueCopyFrom];
78
- if (!sourceField) throw new Error(`Cannot find field ${key}.${field.defaultValueCopyFrom}"`);
79
- if (field.type === "thisReference") {
80
- field.type = sourceField.type;
81
- field.isArray = sourceField.isArray;
82
- }
83
- verifyDefaultValueType(field.isArray || false, {
84
- type: sourceField.type,
85
- value: sourceField.defaultValue
86
- }, field.type, supportedPrimitiveTypes, {
87
- typesMap,
88
- result,
89
- sourceFile: typesMap[key]?.sourceFile
111
+ if (field.defaultValue) {
112
+ verifyDefaultValueType(field, {
113
+ typeNodesMap,
114
+ result: schema,
115
+ sourceFile: typeNodesMap[key]?.sourceFile
90
116
  });
91
117
  }
118
+ for (const fName2 in fields) {
119
+ const field2 = fields[fName2];
120
+ if (field2.defaultValueCopyFrom) {
121
+ const sourceField = fields[field2.defaultValueCopyFrom];
122
+ if (!sourceField) throw new Error(`Cannot find field ${key}.${field2.defaultValueCopyFrom}"`);
123
+ verifyDefaultValueTypeCopyFrom(field2, sourceField, {
124
+ typeNodesMap,
125
+ result: schema,
126
+ sourceFile: typeNodesMap[key]?.sourceFile
127
+ });
128
+ }
129
+ }
92
130
  }
93
131
  }
94
132
  }
@@ -113,7 +151,12 @@ function getOrder(f) {
113
151
  };
114
152
  return decorator.order ?? defaultOrders[decorator.preset] ?? 0;
115
153
  }
116
- function parseType(typeDeclaration, typeName, ctx) {
154
+ function parseClassOrTypeDeclaration(typeDeclaration, typeName, ctx) {
155
+ if (typeDeclaration.kind === _typescript.SyntaxKind.ClassDeclaration) return parseClassDeclaration(typeDeclaration, typeName, ctx);
156
+ if (typeDeclaration.kind === _typescript.SyntaxKind.TypeAliasDeclaration) return parseTypeAliasDeclaration(typeDeclaration, typeName, ctx);
157
+ throw new Error(`Unexpected type definition - ${typeName}`);
158
+ }
159
+ function parseClassDeclaration(typeDeclaration, typeName, ctx) {
117
160
  if (ctx.result[typeName]) return ctx.result[typeName];
118
161
  const {
119
162
  modifiers
@@ -123,62 +166,64 @@ function parseType(typeDeclaration, typeName, ctx) {
123
166
  const name = nameNode.text;
124
167
  const comment = typeDeclaration.jsDoc?.[0]?.comment;
125
168
  const decorators = parseDecorators(modifiers, ctx);
126
- if (typeDeclaration.kind === _typescript.SyntaxKind.ClassDeclaration) {
127
- const classDeclaration = typeDeclaration;
128
- const {
129
- members,
130
- heritageClauses
131
- } = classDeclaration;
132
- const isExtendingExpr = heritageClauses?.[0]?.types?.[0]?.expression;
133
- const isExtending = isExtendingExpr?.text;
134
- for (const m of members) {
135
- if (m.kind !== _typescript.SyntaxKind.PropertyDeclaration) {
136
- throw new Error(`Unexpected class member - only properties are allowed("${m.getText(ctx.sourceFile)}")`);
137
- }
138
- }
139
- const fieldsArray = members.map(m => parseClassMember(m, name, ctx));
140
- const fields = {};
141
- for (const f of fieldsArray) {
142
- fields[f.name] = f;
169
+ const classDeclaration = typeDeclaration;
170
+ const {
171
+ members,
172
+ heritageClauses
173
+ } = classDeclaration;
174
+ const isExtendingExpr = heritageClauses?.[0]?.types?.[0]?.expression;
175
+ const isExtending = isExtendingExpr?.text;
176
+ for (const m of members) {
177
+ if (m.kind !== _typescript.SyntaxKind.PropertyDeclaration) {
178
+ throw new Error(`Unexpected class member - only properties are allowed("${m.getText(ctx.sourceFile)}")`);
143
179
  }
144
- const handle = _lodash.default.lowerFirst(name);
145
- const handlePlural = (0, _pluralize.default)(handle);
146
- const result = {
180
+ }
181
+ const fields = {};
182
+ for (const m of members) {
183
+ const field = parseClassMember(m, fields, name, ctx);
184
+ fields[field.name] = field;
185
+ }
186
+ const handle = _lodash.default.lowerFirst(name);
187
+ const handlePlural = (0, _pluralize.default)(handle);
188
+ const result = {
189
+ name,
190
+ handle,
191
+ handlePlural,
192
+ decorators,
193
+ fields,
194
+ isExtending,
195
+ comment
196
+ };
197
+ return result;
198
+ }
199
+ function parseTypeAliasDeclaration(typeDeclaration, typeName, ctx) {
200
+ if (ctx.result[typeName]) return ctx.result[typeName];
201
+ const nameNode = typeDeclaration.name;
202
+ if (!nameNode || nameNode.kind !== _typescript.SyntaxKind.Identifier) throw new Error("Cannot detect class name");
203
+ const name = nameNode.text;
204
+ const comment = typeDeclaration.jsDoc?.[0]?.comment;
205
+ const typeAliasDeclaration = typeDeclaration;
206
+ const typeAliasType = typeAliasDeclaration.type;
207
+ if (typeAliasType.kind === _typescript.SyntaxKind.UnionType) {
208
+ const typeAliasValue = typeAliasDeclaration.type;
209
+ const enumValues = getEnumValues(typeAliasValue, typeDeclaration, ctx);
210
+ return {
147
211
  name,
148
- handle,
149
- handlePlural,
150
- decorators,
151
- fields,
152
- isExtending,
153
- comment
212
+ enumValues,
213
+ comment,
214
+ decorators: {}
154
215
  };
155
- return result;
156
216
  }
157
- if (typeDeclaration.kind === _typescript.SyntaxKind.TypeAliasDeclaration) {
158
- const typeAliasDeclaration = typeDeclaration;
159
- const typeAliasType = typeAliasDeclaration.type;
160
- if (typeAliasType.kind === _typescript.SyntaxKind.UnionType) {
161
- const typeAliasValue = typeAliasDeclaration.type;
162
- const enumValues = getEnumValues(typeAliasValue, typeDeclaration, ctx);
163
- return {
164
- name,
165
- decorators,
166
- enumValues,
167
- comment
168
- };
169
- }
170
- if (typeAliasType.kind === _typescript.SyntaxKind.TypeOperator && typeAliasType.operator === _typescript.SyntaxKind.KeyOfKeyword) {
171
- const enumValues = getEnumValuesFromKeyOf(typeAliasType, ctx);
172
- return {
173
- name,
174
- decorators,
175
- enumValues,
176
- comment
177
- };
178
- }
179
- throw new Error(`Unexpected type definition - ${typeDeclaration.getText(ctx.sourceFile)}. Did you mean 'class'?`);
217
+ if (typeAliasType.kind === _typescript.SyntaxKind.TypeOperator && typeAliasType.operator === _typescript.SyntaxKind.KeyOfKeyword) {
218
+ const enumValues = getEnumValuesFromKeyOf(typeAliasType, ctx);
219
+ return {
220
+ name,
221
+ enumValues,
222
+ comment,
223
+ decorators: {}
224
+ };
180
225
  }
181
- throw new Error(`Unexpected type kind - "${name}"`);
226
+ throw new Error(`Unexpected type definition - ${typeDeclaration.getText(ctx.sourceFile)}. Did you mean 'class'?`);
182
227
  }
183
228
  function parseDecorators(modifiers, ctx) {
184
229
  if (!modifiers) return {};
@@ -205,28 +250,29 @@ function getEnumValues(node, parentNode, ctx) {
205
250
  });
206
251
  return _lodash.default.keyBy(enumValuesArray, "name");
207
252
  }
208
- function parseClassMember(node, parentName, ctx) {
253
+ function parseClassMember(node, parentFields, parentName, ctx) {
209
254
  const name = node.name.getText(ctx.sourceFile);
210
- const defaultValueDescription = parseLiteralNode(node.initializer, ctx);
211
- let defaultValue;
212
- let defaultValueCopyFrom;
213
- if (defaultValueDescription) {
214
- if (defaultValueDescription.type === "thisReference") {
215
- defaultValueCopyFrom = defaultValueDescription.value;
216
- } else {
217
- defaultValue = defaultValueDescription.value;
218
- }
219
- }
255
+ const {
256
+ defaultValue,
257
+ defaultValueCopyFrom,
258
+ defaultValueClass
259
+ } = parseDefaultValueExpression(node.initializer, ctx);
220
260
  const isRequired = !node.questionToken;
221
261
  const comment = node.jsDoc?.[0]?.comment;
222
262
  const decorators = parseDecorators(node.modifiers, ctx);
263
+ let defaultValueType = defaultValueClass || getPrimitiveTypeFromDefaultValue(defaultValue);
264
+ if (defaultValueCopyFrom) {
265
+ const parentField = parentFields[defaultValueCopyFrom];
266
+ if (!parentField) throw new Error(`Cannot find field ${parentName}.${defaultValueCopyFrom}"`);
267
+ defaultValueType = parentField.type;
268
+ }
223
269
  const {
224
270
  isArray,
225
271
  isRelation,
226
272
  isChange,
227
273
  relationDenormFields,
228
274
  type
229
- } = parseFieldType(ctx, parentName, name, node, defaultValueDescription);
275
+ } = parseFieldType(ctx, parentName, name, node, defaultValueType);
230
276
  const result = {
231
277
  type,
232
278
  defaultValue,
@@ -240,9 +286,18 @@ function parseClassMember(node, parentName, ctx) {
240
286
  comment
241
287
  };
242
288
  if (!_lodash.default.isEmpty(decorators)) result.decorators = decorators;
289
+ if (defaultValueClass) result.defaultValueClass = defaultValueClass;
243
290
  return result;
244
291
  }
245
- function parseFieldType(ctx, parentName, fieldName, node, defaultValueDescription) {
292
+ function getPrimitiveTypeFromDefaultValue(value) {
293
+ if (_lodash.default.isString(value)) return "string";
294
+ if (_lodash.default.isNumber(value)) return "number";
295
+ if (_lodash.default.isBoolean(value)) return "boolean";
296
+ if (_lodash.default.isArray(value)) return "array";
297
+ if (_lodash.default.isObject(value)) return "object";
298
+ return void 0;
299
+ }
300
+ function parseFieldType(ctx, parentName, fieldName, node, defaultValueType) {
246
301
  const parsedType = {
247
302
  isArray: false,
248
303
  isRelation: false,
@@ -257,20 +312,17 @@ function parseFieldType(ctx, parentName, fieldName, node, defaultValueDescriptio
257
312
  parseFieldTypeInlineEnum(parsedType, parentName, fieldName, ctx);
258
313
  parseFieldTypeKeyofEnum(parsedType, parentName, fieldName, ctx);
259
314
  parseFieldTypeRecordEnum(parsedType, parentName, fieldName, ctx);
260
- parsedType.type = parsedType.type ?? parsedType.nodeType?.getText(ctx.sourceFile) ?? defaultValueDescription?.type;
315
+ parsedType.type = parsedType.type ?? parsedType.nodeType?.getText(ctx.sourceFile) ?? defaultValueType;
261
316
  if (!parsedType.type) throw new Error(`Cannot detect property type: '${node.getText(ctx.sourceFile)}'`);
262
317
  if (parsedType.type.startsWith("Change<")) {
263
318
  parsedType.type = parsedType.type.slice(7, -1);
264
- if (!ctx.typesMap[parsedType.type]) throw new Error(`Unexpected property type: '${parsedType.type}'`);
319
+ if (!ctx.typeNodesMap[parsedType.type]) throw new Error(`Unexpected property type: '${parsedType.type}'`);
265
320
  parsedType.isChange = true;
266
321
  } else {
267
- if (!supportedPrimitiveTypes.includes(parsedType.type) && !ctx.typesMap[parsedType.type] && !ctx.result[parsedType.type] && parsedType.type !== "thisReference") {
322
+ if (!supportedPrimitiveTypes.includes(parsedType.type) && !ctx.typeNodesMap[parsedType.type] && !ctx.result[parsedType.type]) {
268
323
  throw new Error(`Unexpected property type: '${parsedType.type}'`);
269
324
  }
270
325
  }
271
- if (defaultValueDescription && defaultValueDescription.type !== "thisReference") {
272
- verifyDefaultValueType(parsedType.isArray, defaultValueDescription, parsedType.type, supportedPrimitiveTypes, ctx);
273
- }
274
326
  return {
275
327
  isArray: parsedType.isArray || void 0,
276
328
  isRelation: parsedType.isRelation || void 0,
@@ -286,9 +338,9 @@ function parseFieldTypeRecordEnum(parsedType, parentName, fieldName, ctx) {
286
338
  if (nt.typeArguments?.length !== 2) return;
287
339
  const keyTypeName = nt.typeArguments[0].getText(ctx.sourceFile);
288
340
  const valueTypeName = nt.typeArguments[1].getText(ctx.sourceFile);
289
- const keyType = ctx.typesMap[keyTypeName];
341
+ const keyType = ctx.typeNodesMap[keyTypeName];
290
342
  if (!keyType) return;
291
- if (!ctx.result[keyTypeName]) ctx.result[keyTypeName] = parseType(keyType.node, keyTypeName, ctx);
343
+ if (!ctx.result[keyTypeName]) ctx.result[keyTypeName] = parseClassOrTypeDeclaration(keyType.node, keyTypeName, ctx);
292
344
  const enumValues = ctx.result[keyTypeName].enumValues;
293
345
  if (!enumValues) throw new Error(`Unexpected type - ${keyTypeName}`);
294
346
  const newTypeName = `${parentName}_${_lodash.default.upperFirst(fieldName)}`;
@@ -362,11 +414,11 @@ function getEnumValuesFromKeyOf(nodeType, ctx) {
362
414
  throw new Error(`Unexpected type - ${typeReferenceNode.getText(ctx.sourceFile)}`);
363
415
  }
364
416
  const typeName = typeReferenceNode.typeName.text;
365
- const type = ctx.typesMap[typeName];
417
+ const type = ctx.typeNodesMap[typeName];
366
418
  if (!type) {
367
419
  throw new Error(`Unexpected type - ${typeName}`);
368
420
  }
369
- if (!ctx.result[typeName]) ctx.result[typeName] = parseType(type.node, typeName, ctx);
421
+ if (!ctx.result[typeName]) ctx.result[typeName] = parseClassOrTypeDeclaration(type.node, typeName, ctx);
370
422
  if (!ctx.result[typeName].fields) throw new Error(`Unexpected type - ${typeName}`);
371
423
  return _lodash.default.mapValues(ctx.result[typeName].fields || {}, v => ({
372
424
  name: v.name,
@@ -388,23 +440,43 @@ function getRelationDenormFields(ctx, node) {
388
440
  }
389
441
  throw new Error(`Unexpected type - ${node.getText(ctx.sourceFile)}`);
390
442
  }
391
- function verifyDefaultValueType(isArray, defaultValueDescription, type, supportedPrimitiveTypes2, ctx) {
443
+ function verifyDefaultValueType(field, ctx) {
444
+ const {
445
+ isArray,
446
+ defaultValue,
447
+ type
448
+ } = field;
392
449
  if (isArray) {
393
- if (defaultValueDescription.type !== "array") {
394
- throw new Error(`Default value type is different from field type: '${type}'`);
450
+ if (!_lodash.default.isArray(defaultValue)) {
451
+ throw new TypeError(`Default value type is different from field type: '${type}'`);
395
452
  }
396
453
  } else {
397
- if (supportedPrimitiveTypes2.includes(type) && defaultValueDescription.type !== type) {
454
+ if (supportedPrimitiveTypes.includes(type) && getPrimitiveTypeFromDefaultValue(defaultValue) !== type) {
398
455
  throw new Error(`Default value type is different from field type: '${type}'`);
399
456
  }
400
- if (!ctx.result[type] && ctx.typesMap[type]) ctx.result[type] = parseType(ctx.typesMap[type].node, type, ctx);
457
+ if (!ctx.result[type] && ctx.typeNodesMap[type]) ctx.result[type] = parseClassOrTypeDeclaration(ctx.typeNodesMap[type].node, type, ctx);
401
458
  const enumValues = ctx.result[type]?.enumValues;
402
- if (enumValues && !enumValues[defaultValueDescription.value]) {
459
+ if (enumValues && !enumValues[defaultValue]) {
403
460
  const enumValuesStr = _lodash.default.keys(enumValues).map(x => `'x'`).join(", ");
404
461
  throw new Error(`Default value must be one of: ${enumValuesStr}`);
405
462
  }
406
463
  }
407
464
  }
465
+ function verifyDefaultValueTypeCopyFrom(field, sourceField, ctx) {
466
+ const {
467
+ isArray,
468
+ type
469
+ } = field;
470
+ if (isArray) {
471
+ if (!sourceField.isArray) {
472
+ throw new TypeError(`Default value type is not an array: '${field.name}'`);
473
+ }
474
+ } else {
475
+ if (sourceField.type !== type) {
476
+ throw new Error(`Default value type is different from field type: '${field.name}'`);
477
+ }
478
+ }
479
+ }
408
480
  function parseDecorator(decoratorNode, ctx) {
409
481
  const expr = decoratorNode.expression;
410
482
  if (expr.kind !== _typescript.SyntaxKind.CallExpression) throw new Error(`Unexpected decorator format: "${expr.getText(ctx.sourceFile)}"`);
@@ -420,40 +492,35 @@ function parseDecoratorArguments(expr, ctx) {
420
492
  if (args.length === 0) return {};
421
493
  if (args.length > 1) throw new Error(`Too many arguments - one expected: "${expr.getText(ctx.sourceFile)}"`);
422
494
  const arg = args[0];
423
- return parseLiteralNode(arg, ctx)?.value ?? {};
495
+ return parseLiteralNode(arg, ctx) ?? {};
424
496
  }
425
- function parseLiteralNode(expr, ctx) {
426
- if (!expr) return void 0;
497
+ function parseDefaultValueExpression(expr, ctx) {
498
+ if (!expr) return {};
427
499
  if (expr.kind === _typescript.SyntaxKind.NewExpression) {
428
500
  const identifier = expr.expression;
429
501
  const type = identifier?.text;
430
502
  if (type) {
431
503
  return {
432
- type,
433
- value: {}
504
+ defaultValueClass: type,
505
+ defaultValue: {}
434
506
  };
435
507
  }
508
+ } else if (expr.kind === _typescript.SyntaxKind.PropertyAccessExpression && expr.expression.kind === _typescript.SyntaxKind.ThisKeyword) {
509
+ return {
510
+ defaultValueCopyFrom: expr.name?.text
511
+ };
436
512
  }
437
- if (expr.kind === _typescript.SyntaxKind.StringLiteral) return {
438
- type: "string",
439
- value: expr.text
440
- };
441
- if (expr.kind === _typescript.SyntaxKind.FalseKeyword) return {
442
- type: "boolean",
443
- value: false
444
- };
445
- if (expr.kind === _typescript.SyntaxKind.TrueKeyword) return {
446
- type: "boolean",
447
- value: true
448
- };
449
- if (expr.kind === _typescript.SyntaxKind.NumericLiteral) return {
450
- type: "number",
451
- value: Number.parseFloat(expr.text)
452
- };
453
- if (expr.kind === _typescript.SyntaxKind.ObjectLiteralExpression) return {
454
- type: "object",
455
- value: parseObjectLiteral(expr, ctx)
513
+ return {
514
+ defaultValue: parseLiteralNode(expr, ctx)
456
515
  };
516
+ }
517
+ function parseLiteralNode(expr, ctx) {
518
+ if (!expr) return void 0;
519
+ if (expr.kind === _typescript.SyntaxKind.StringLiteral) return expr.text;
520
+ if (expr.kind === _typescript.SyntaxKind.FalseKeyword) return false;
521
+ if (expr.kind === _typescript.SyntaxKind.TrueKeyword) return true;
522
+ if (expr.kind === _typescript.SyntaxKind.NumericLiteral) return Number.parseFloat(expr.text);
523
+ if (expr.kind === _typescript.SyntaxKind.ObjectLiteralExpression) return parseObjectLiteral(expr, ctx);
457
524
  if (expr.kind === _typescript.SyntaxKind.ArrayLiteralExpression) {
458
525
  const defaultValueStr = expr.getText(ctx.sourceFile);
459
526
  let defaultValue;
@@ -463,16 +530,7 @@ function parseLiteralNode(expr, ctx) {
463
530
  throw new Error("Value must be valid array");
464
531
  }
465
532
  if (!_lodash.default.isArray(defaultValue)) throw new Error("Value must be valid array");
466
- return {
467
- type: "array",
468
- value: defaultValue
469
- };
470
- }
471
- if (expr.kind === _typescript.SyntaxKind.PropertyAccessExpression && expr.expression.kind === _typescript.SyntaxKind.ThisKeyword) {
472
- return {
473
- type: "thisReference",
474
- value: expr.name?.text
475
- };
533
+ return defaultValue;
476
534
  }
477
535
  throw new Error(`Unexpected property expression: "${expr.getText(ctx.sourceFile)}"`);
478
536
  }
@@ -485,7 +543,7 @@ function parseObjectLiteral(arg, ctx) {
485
543
  if (p.kind !== _typescript.SyntaxKind.PropertyAssignment) throw new Error(`Unexpected property value: "${p.getText(ctx.sourceFile)}"`);
486
544
  const p2 = p;
487
545
  const valueExpression = p2.initializer;
488
- const value = parseLiteralNode(valueExpression, ctx)?.value;
546
+ const value = parseLiteralNode(valueExpression, ctx);
489
547
  result[name] = value;
490
548
  }
491
549
  return result;
@@ -1 +1 @@
1
- export declare function parseSchema(typescriptFiles: Record<string, string>): Record<string, any>;
1
+ export declare function parseSchema(typescriptFiles: Record<string, string>): Record<string, TypeDefinition>;
@@ -3,8 +3,58 @@ import _ from "lodash";
3
3
  import pluralize from "pluralize";
4
4
  const supportedPrimitiveTypes = ["string", "number", "boolean", "Record<string, string>", "Record<string, any>"];
5
5
  export function parseSchema(typescriptFiles) {
6
+ const typeNodesMap = getTypeNodesMap(typescriptFiles);
7
+ const schema = getSchema(typeNodesMap);
8
+ resolveIsExtending(schema);
9
+ fillComputedDefinitionsForType(schema);
10
+ verifyDefaultValueTypes(schema, typeNodesMap);
11
+ verifyRelationFields(schema);
12
+ return schema;
13
+ }
14
+ function resolveIsExtending(schema) {
15
+ for (const key in schema) {
16
+ const isExtendingType = schema[key].isExtending;
17
+ if (!isExtendingType)
18
+ continue;
19
+ if (!schema[isExtendingType])
20
+ throw new Error(`Unknown type: "${isExtendingType}"`);
21
+ schema[key].fields = { ...schema[isExtendingType].fields, ...schema[key].fields };
22
+ schema[key].decorators = { ...schema[isExtendingType].decorators, ...schema[key].decorators };
23
+ if (schema[key].decorators.entity && !schema[key].fields?.id) {
24
+ throw new Error(`Entity "${key}" must have an id`);
25
+ }
26
+ }
27
+ }
28
+ function getSchema(typeNodesMap) {
6
29
  const result = {};
7
- const typesMap = {};
30
+ for (const key in typeNodesMap) {
31
+ const { node, name } = typeNodesMap[key];
32
+ if (![SyntaxKind.ClassDeclaration, SyntaxKind.TypeAliasDeclaration].includes(node.kind)) {
33
+ throw new Error(`Unexpected type kind - "${name}"`);
34
+ }
35
+ }
36
+ for (const key in typeNodesMap) {
37
+ if (result[key])
38
+ continue;
39
+ const { node, sourceFile, name } = typeNodesMap[key];
40
+ if (node.kind !== SyntaxKind.ClassDeclaration)
41
+ continue;
42
+ const parsedClass = parseClassDeclaration(node, name, { typeNodesMap, sourceFile, result });
43
+ result[key] = parsedClass;
44
+ }
45
+ for (const key in typeNodesMap) {
46
+ if (result[key])
47
+ continue;
48
+ const { node, sourceFile, name } = typeNodesMap[key];
49
+ if (node.kind !== SyntaxKind.TypeAliasDeclaration)
50
+ continue;
51
+ const parsedClass = parseTypeAliasDeclaration(node, name, { typeNodesMap, sourceFile, result });
52
+ result[key] = parsedClass;
53
+ }
54
+ return result;
55
+ }
56
+ function getTypeNodesMap(typescriptFiles) {
57
+ const typeNodesMap = {};
8
58
  for (const key in typescriptFiles) {
9
59
  const text = typescriptFiles[key];
10
60
  const sourceFile = createSourceFile(`${key}.ts`, text, ScriptTarget.Latest);
@@ -14,61 +64,41 @@ export function parseSchema(typescriptFiles) {
14
64
  if (!nameNode || nameNode.kind !== SyntaxKind.Identifier)
15
65
  throw new Error("Cannot detect class name");
16
66
  const name = nameNode.text;
17
- typesMap[name] = { name, node: cd, sourceFile };
67
+ typeNodesMap[name] = { name, node: cd, sourceFile };
18
68
  }
19
- if (!typesMap[key]) {
69
+ if (!typeNodesMap[key]) {
20
70
  throw new Error(`File ${key}.ts must contain class declaration with name "${key}"`);
21
71
  }
22
72
  }
23
- for (const key in typesMap) {
24
- if (result[key])
25
- continue;
26
- const { node, sourceFile, name } = typesMap[key];
27
- const parsedClass = parseType(node, name, { typesMap, sourceFile, result });
28
- if (parsedClass.name !== key)
29
- throw new Error(`File name must correspond to exported class name ("${key}", "${parsedClass.name}")`);
30
- result[key] = parsedClass;
31
- }
32
- for (const key in result) {
33
- const isExtendingType = result[key].isExtending;
34
- if (!isExtendingType)
35
- continue;
36
- if (!result[isExtendingType])
37
- throw new Error(`Unknown type: "${isExtendingType}"`);
38
- result[key].fields = { ...result[isExtendingType].fields, ...result[key].fields };
39
- result[key].decorators = { ...result[isExtendingType].decorators, ...result[key].decorators };
40
- if (result[key].decorators.entity && !result[key].fields?.id) {
41
- throw new Error(`Entity "${key}" must have an id`);
42
- }
43
- }
44
- fillComputedDefinitionsForType(result);
45
- processThisReferenceDefaultValues(result, typesMap);
46
- verifyRelationFields(result);
47
- return result;
73
+ return typeNodesMap;
48
74
  }
49
- function processThisReferenceDefaultValues(result, typesMap) {
50
- for (const key in result) {
51
- const type = result[key];
75
+ function verifyDefaultValueTypes(schema, typeNodesMap) {
76
+ for (const key in schema) {
77
+ const type = schema[key];
52
78
  const fields = type.fields;
53
79
  if (!fields)
54
80
  continue;
55
81
  for (const fName in fields) {
56
82
  const field = fields[fName];
57
- if (field.defaultValueCopyFrom) {
58
- const sourceField = fields[field.defaultValueCopyFrom];
59
- if (!sourceField)
60
- throw new Error(`Cannot find field ${key}.${field.defaultValueCopyFrom}"`);
61
- if (field.type === "thisReference") {
62
- field.type = sourceField.type;
63
- field.isArray = sourceField.isArray;
83
+ if (field.defaultValue) {
84
+ verifyDefaultValueType(field, {
85
+ typeNodesMap,
86
+ result: schema,
87
+ sourceFile: typeNodesMap[key]?.sourceFile
88
+ });
89
+ }
90
+ for (const fName2 in fields) {
91
+ const field2 = fields[fName2];
92
+ if (field2.defaultValueCopyFrom) {
93
+ const sourceField = fields[field2.defaultValueCopyFrom];
94
+ if (!sourceField)
95
+ throw new Error(`Cannot find field ${key}.${field2.defaultValueCopyFrom}"`);
96
+ verifyDefaultValueTypeCopyFrom(field2, sourceField, {
97
+ typeNodesMap,
98
+ result: schema,
99
+ sourceFile: typeNodesMap[key]?.sourceFile
100
+ });
64
101
  }
65
- verifyDefaultValueType(
66
- field.isArray || false,
67
- { type: sourceField.type, value: sourceField.defaultValue },
68
- field.type,
69
- supportedPrimitiveTypes,
70
- { typesMap, result, sourceFile: typesMap[key]?.sourceFile }
71
- );
72
102
  }
73
103
  }
74
104
  }
@@ -98,7 +128,14 @@ function getOrder(f) {
98
128
  };
99
129
  return decorator.order ?? defaultOrders[decorator.preset] ?? 0;
100
130
  }
101
- function parseType(typeDeclaration, typeName, ctx) {
131
+ function parseClassOrTypeDeclaration(typeDeclaration, typeName, ctx) {
132
+ if (typeDeclaration.kind === SyntaxKind.ClassDeclaration)
133
+ return parseClassDeclaration(typeDeclaration, typeName, ctx);
134
+ if (typeDeclaration.kind === SyntaxKind.TypeAliasDeclaration)
135
+ return parseTypeAliasDeclaration(typeDeclaration, typeName, ctx);
136
+ throw new Error(`Unexpected type definition - ${typeName}`);
137
+ }
138
+ function parseClassDeclaration(typeDeclaration, typeName, ctx) {
102
139
  if (ctx.result[typeName])
103
140
  return ctx.result[typeName];
104
141
  const { modifiers } = typeDeclaration;
@@ -108,49 +145,53 @@ function parseType(typeDeclaration, typeName, ctx) {
108
145
  const name = nameNode.text;
109
146
  const comment = typeDeclaration.jsDoc?.[0]?.comment;
110
147
  const decorators = parseDecorators(modifiers, ctx);
111
- if (typeDeclaration.kind === SyntaxKind.ClassDeclaration) {
112
- const classDeclaration = typeDeclaration;
113
- const { members, heritageClauses } = classDeclaration;
114
- const isExtendingExpr = heritageClauses?.[0]?.types?.[0]?.expression;
115
- const isExtending = isExtendingExpr?.text;
116
- for (const m of members) {
117
- if (m.kind !== SyntaxKind.PropertyDeclaration) {
118
- throw new Error(`Unexpected class member - only properties are allowed("${m.getText(ctx.sourceFile)}")`);
119
- }
148
+ const classDeclaration = typeDeclaration;
149
+ const { members, heritageClauses } = classDeclaration;
150
+ const isExtendingExpr = heritageClauses?.[0]?.types?.[0]?.expression;
151
+ const isExtending = isExtendingExpr?.text;
152
+ for (const m of members) {
153
+ if (m.kind !== SyntaxKind.PropertyDeclaration) {
154
+ throw new Error(`Unexpected class member - only properties are allowed("${m.getText(ctx.sourceFile)}")`);
120
155
  }
121
- const fieldsArray = members.map((m) => parseClassMember(m, name, ctx));
122
- const fields = {};
123
- for (const f of fieldsArray) {
124
- fields[f.name] = f;
125
- }
126
- const handle = _.lowerFirst(name);
127
- const handlePlural = pluralize(handle);
128
- const result = {
129
- name,
130
- handle,
131
- handlePlural,
132
- decorators,
133
- fields,
134
- isExtending,
135
- comment
136
- };
137
- return result;
138
156
  }
139
- if (typeDeclaration.kind === SyntaxKind.TypeAliasDeclaration) {
140
- const typeAliasDeclaration = typeDeclaration;
141
- const typeAliasType = typeAliasDeclaration.type;
142
- if (typeAliasType.kind === SyntaxKind.UnionType) {
143
- const typeAliasValue = typeAliasDeclaration.type;
144
- const enumValues = getEnumValues(typeAliasValue, typeDeclaration, ctx);
145
- return { name, decorators, enumValues, comment };
146
- }
147
- if (typeAliasType.kind === SyntaxKind.TypeOperator && typeAliasType.operator === SyntaxKind.KeyOfKeyword) {
148
- const enumValues = getEnumValuesFromKeyOf(typeAliasType, ctx);
149
- return { name, decorators, enumValues, comment };
150
- }
151
- throw new Error(`Unexpected type definition - ${typeDeclaration.getText(ctx.sourceFile)}. Did you mean 'class'?`);
157
+ const fields = {};
158
+ for (const m of members) {
159
+ const field = parseClassMember(m, fields, name, ctx);
160
+ fields[field.name] = field;
152
161
  }
153
- throw new Error(`Unexpected type kind - "${name}"`);
162
+ const handle = _.lowerFirst(name);
163
+ const handlePlural = pluralize(handle);
164
+ const result = {
165
+ name,
166
+ handle,
167
+ handlePlural,
168
+ decorators,
169
+ fields,
170
+ isExtending,
171
+ comment
172
+ };
173
+ return result;
174
+ }
175
+ function parseTypeAliasDeclaration(typeDeclaration, typeName, ctx) {
176
+ if (ctx.result[typeName])
177
+ return ctx.result[typeName];
178
+ const nameNode = typeDeclaration.name;
179
+ if (!nameNode || nameNode.kind !== SyntaxKind.Identifier)
180
+ throw new Error("Cannot detect class name");
181
+ const name = nameNode.text;
182
+ const comment = typeDeclaration.jsDoc?.[0]?.comment;
183
+ const typeAliasDeclaration = typeDeclaration;
184
+ const typeAliasType = typeAliasDeclaration.type;
185
+ if (typeAliasType.kind === SyntaxKind.UnionType) {
186
+ const typeAliasValue = typeAliasDeclaration.type;
187
+ const enumValues = getEnumValues(typeAliasValue, typeDeclaration, ctx);
188
+ return { name, enumValues, comment, decorators: {} };
189
+ }
190
+ if (typeAliasType.kind === SyntaxKind.TypeOperator && typeAliasType.operator === SyntaxKind.KeyOfKeyword) {
191
+ const enumValues = getEnumValuesFromKeyOf(typeAliasType, ctx);
192
+ return { name, enumValues, comment, decorators: {} };
193
+ }
194
+ throw new Error(`Unexpected type definition - ${typeDeclaration.getText(ctx.sourceFile)}. Did you mean 'class'?`);
154
195
  }
155
196
  function parseDecorators(modifiers, ctx) {
156
197
  if (!modifiers)
@@ -175,27 +216,25 @@ function getEnumValues(node, parentNode, ctx) {
175
216
  });
176
217
  return _.keyBy(enumValuesArray, "name");
177
218
  }
178
- function parseClassMember(node, parentName, ctx) {
219
+ function parseClassMember(node, parentFields, parentName, ctx) {
179
220
  const name = node.name.getText(ctx.sourceFile);
180
- const defaultValueDescription = parseLiteralNode(node.initializer, ctx);
181
- let defaultValue;
182
- let defaultValueCopyFrom;
183
- if (defaultValueDescription) {
184
- if (defaultValueDescription.type === "thisReference") {
185
- defaultValueCopyFrom = defaultValueDescription.value;
186
- } else {
187
- defaultValue = defaultValueDescription.value;
188
- }
189
- }
221
+ const { defaultValue, defaultValueCopyFrom, defaultValueClass } = parseDefaultValueExpression(node.initializer, ctx);
190
222
  const isRequired = !node.questionToken;
191
223
  const comment = node.jsDoc?.[0]?.comment;
192
224
  const decorators = parseDecorators(node.modifiers, ctx);
225
+ let defaultValueType = defaultValueClass || getPrimitiveTypeFromDefaultValue(defaultValue);
226
+ if (defaultValueCopyFrom) {
227
+ const parentField = parentFields[defaultValueCopyFrom];
228
+ if (!parentField)
229
+ throw new Error(`Cannot find field ${parentName}.${defaultValueCopyFrom}"`);
230
+ defaultValueType = parentField.type;
231
+ }
193
232
  const { isArray, isRelation, isChange, relationDenormFields, type } = parseFieldType(
194
233
  ctx,
195
234
  parentName,
196
235
  name,
197
236
  node,
198
- defaultValueDescription
237
+ defaultValueType
199
238
  );
200
239
  const result = {
201
240
  type,
@@ -211,9 +250,24 @@ function parseClassMember(node, parentName, ctx) {
211
250
  };
212
251
  if (!_.isEmpty(decorators))
213
252
  result.decorators = decorators;
253
+ if (defaultValueClass)
254
+ result.defaultValueClass = defaultValueClass;
214
255
  return result;
215
256
  }
216
- function parseFieldType(ctx, parentName, fieldName, node, defaultValueDescription) {
257
+ function getPrimitiveTypeFromDefaultValue(value) {
258
+ if (_.isString(value))
259
+ return "string";
260
+ if (_.isNumber(value))
261
+ return "number";
262
+ if (_.isBoolean(value))
263
+ return "boolean";
264
+ if (_.isArray(value))
265
+ return "array";
266
+ if (_.isObject(value))
267
+ return "object";
268
+ return void 0;
269
+ }
270
+ function parseFieldType(ctx, parentName, fieldName, node, defaultValueType) {
217
271
  const parsedType = {
218
272
  isArray: false,
219
273
  isRelation: false,
@@ -228,22 +282,19 @@ function parseFieldType(ctx, parentName, fieldName, node, defaultValueDescriptio
228
282
  parseFieldTypeInlineEnum(parsedType, parentName, fieldName, ctx);
229
283
  parseFieldTypeKeyofEnum(parsedType, parentName, fieldName, ctx);
230
284
  parseFieldTypeRecordEnum(parsedType, parentName, fieldName, ctx);
231
- parsedType.type = parsedType.type ?? parsedType.nodeType?.getText(ctx.sourceFile) ?? defaultValueDescription?.type;
285
+ parsedType.type = parsedType.type ?? parsedType.nodeType?.getText(ctx.sourceFile) ?? defaultValueType;
232
286
  if (!parsedType.type)
233
287
  throw new Error(`Cannot detect property type: '${node.getText(ctx.sourceFile)}'`);
234
288
  if (parsedType.type.startsWith("Change<")) {
235
289
  parsedType.type = parsedType.type.slice(7, -1);
236
- if (!ctx.typesMap[parsedType.type])
290
+ if (!ctx.typeNodesMap[parsedType.type])
237
291
  throw new Error(`Unexpected property type: '${parsedType.type}'`);
238
292
  parsedType.isChange = true;
239
293
  } else {
240
- if (!supportedPrimitiveTypes.includes(parsedType.type) && !ctx.typesMap[parsedType.type] && !ctx.result[parsedType.type] && parsedType.type !== "thisReference") {
294
+ if (!supportedPrimitiveTypes.includes(parsedType.type) && !ctx.typeNodesMap[parsedType.type] && !ctx.result[parsedType.type]) {
241
295
  throw new Error(`Unexpected property type: '${parsedType.type}'`);
242
296
  }
243
297
  }
244
- if (defaultValueDescription && defaultValueDescription.type !== "thisReference") {
245
- verifyDefaultValueType(parsedType.isArray, defaultValueDescription, parsedType.type, supportedPrimitiveTypes, ctx);
246
- }
247
298
  return {
248
299
  isArray: parsedType.isArray || void 0,
249
300
  isRelation: parsedType.isRelation || void 0,
@@ -262,11 +313,11 @@ function parseFieldTypeRecordEnum(parsedType, parentName, fieldName, ctx) {
262
313
  return;
263
314
  const keyTypeName = nt.typeArguments[0].getText(ctx.sourceFile);
264
315
  const valueTypeName = nt.typeArguments[1].getText(ctx.sourceFile);
265
- const keyType = ctx.typesMap[keyTypeName];
316
+ const keyType = ctx.typeNodesMap[keyTypeName];
266
317
  if (!keyType)
267
318
  return;
268
319
  if (!ctx.result[keyTypeName])
269
- ctx.result[keyTypeName] = parseType(keyType.node, keyTypeName, ctx);
320
+ ctx.result[keyTypeName] = parseClassOrTypeDeclaration(keyType.node, keyTypeName, ctx);
270
321
  const enumValues = ctx.result[keyTypeName].enumValues;
271
322
  if (!enumValues)
272
323
  throw new Error(`Unexpected type - ${keyTypeName}`);
@@ -335,12 +386,12 @@ function getEnumValuesFromKeyOf(nodeType, ctx) {
335
386
  throw new Error(`Unexpected type - ${typeReferenceNode.getText(ctx.sourceFile)}`);
336
387
  }
337
388
  const typeName = typeReferenceNode.typeName.text;
338
- const type = ctx.typesMap[typeName];
389
+ const type = ctx.typeNodesMap[typeName];
339
390
  if (!type) {
340
391
  throw new Error(`Unexpected type - ${typeName}`);
341
392
  }
342
393
  if (!ctx.result[typeName])
343
- ctx.result[typeName] = parseType(type.node, typeName, ctx);
394
+ ctx.result[typeName] = parseClassOrTypeDeclaration(type.node, typeName, ctx);
344
395
  if (!ctx.result[typeName].fields)
345
396
  throw new Error(`Unexpected type - ${typeName}`);
346
397
  return _.mapValues(ctx.result[typeName].fields || {}, (v) => ({
@@ -363,24 +414,37 @@ function getRelationDenormFields(ctx, node) {
363
414
  }
364
415
  throw new Error(`Unexpected type - ${node.getText(ctx.sourceFile)}`);
365
416
  }
366
- function verifyDefaultValueType(isArray, defaultValueDescription, type, supportedPrimitiveTypes2, ctx) {
417
+ function verifyDefaultValueType(field, ctx) {
418
+ const { isArray, defaultValue, type } = field;
367
419
  if (isArray) {
368
- if (defaultValueDescription.type !== "array") {
369
- throw new Error(`Default value type is different from field type: '${type}'`);
420
+ if (!_.isArray(defaultValue)) {
421
+ throw new TypeError(`Default value type is different from field type: '${type}'`);
370
422
  }
371
423
  } else {
372
- if (supportedPrimitiveTypes2.includes(type) && defaultValueDescription.type !== type) {
424
+ if (supportedPrimitiveTypes.includes(type) && getPrimitiveTypeFromDefaultValue(defaultValue) !== type) {
373
425
  throw new Error(`Default value type is different from field type: '${type}'`);
374
426
  }
375
- if (!ctx.result[type] && ctx.typesMap[type])
376
- ctx.result[type] = parseType(ctx.typesMap[type].node, type, ctx);
427
+ if (!ctx.result[type] && ctx.typeNodesMap[type])
428
+ ctx.result[type] = parseClassOrTypeDeclaration(ctx.typeNodesMap[type].node, type, ctx);
377
429
  const enumValues = ctx.result[type]?.enumValues;
378
- if (enumValues && !enumValues[defaultValueDescription.value]) {
430
+ if (enumValues && !enumValues[defaultValue]) {
379
431
  const enumValuesStr = _.keys(enumValues).map((x) => `'x'`).join(", ");
380
432
  throw new Error(`Default value must be one of: ${enumValuesStr}`);
381
433
  }
382
434
  }
383
435
  }
436
+ function verifyDefaultValueTypeCopyFrom(field, sourceField, ctx) {
437
+ const { isArray, type } = field;
438
+ if (isArray) {
439
+ if (!sourceField.isArray) {
440
+ throw new TypeError(`Default value type is not an array: '${field.name}'`);
441
+ }
442
+ } else {
443
+ if (sourceField.type !== type) {
444
+ throw new Error(`Default value type is different from field type: '${field.name}'`);
445
+ }
446
+ }
447
+ }
384
448
  function parseDecorator(decoratorNode, ctx) {
385
449
  const expr = decoratorNode.expression;
386
450
  if (expr.kind !== SyntaxKind.CallExpression)
@@ -397,28 +461,35 @@ function parseDecoratorArguments(expr, ctx) {
397
461
  if (args.length > 1)
398
462
  throw new Error(`Too many arguments - one expected: "${expr.getText(ctx.sourceFile)}"`);
399
463
  const arg = args[0];
400
- return parseLiteralNode(arg, ctx)?.value ?? {};
464
+ return parseLiteralNode(arg, ctx) ?? {};
401
465
  }
402
- function parseLiteralNode(expr, ctx) {
466
+ function parseDefaultValueExpression(expr, ctx) {
403
467
  if (!expr)
404
- return void 0;
468
+ return {};
405
469
  if (expr.kind === SyntaxKind.NewExpression) {
406
470
  const identifier = expr.expression;
407
471
  const type = identifier?.text;
408
472
  if (type) {
409
- return { type, value: {} };
473
+ return { defaultValueClass: type, defaultValue: {} };
410
474
  }
475
+ } else if (expr.kind === SyntaxKind.PropertyAccessExpression && expr.expression.kind === SyntaxKind.ThisKeyword) {
476
+ return { defaultValueCopyFrom: expr.name?.text };
411
477
  }
478
+ return { defaultValue: parseLiteralNode(expr, ctx) };
479
+ }
480
+ function parseLiteralNode(expr, ctx) {
481
+ if (!expr)
482
+ return void 0;
412
483
  if (expr.kind === SyntaxKind.StringLiteral)
413
- return { type: "string", value: expr.text };
484
+ return expr.text;
414
485
  if (expr.kind === SyntaxKind.FalseKeyword)
415
- return { type: "boolean", value: false };
486
+ return false;
416
487
  if (expr.kind === SyntaxKind.TrueKeyword)
417
- return { type: "boolean", value: true };
488
+ return true;
418
489
  if (expr.kind === SyntaxKind.NumericLiteral)
419
- return { type: "number", value: Number.parseFloat(expr.text) };
490
+ return Number.parseFloat(expr.text);
420
491
  if (expr.kind === SyntaxKind.ObjectLiteralExpression)
421
- return { type: "object", value: parseObjectLiteral(expr, ctx) };
492
+ return parseObjectLiteral(expr, ctx);
422
493
  if (expr.kind === SyntaxKind.ArrayLiteralExpression) {
423
494
  const defaultValueStr = expr.getText(ctx.sourceFile);
424
495
  let defaultValue;
@@ -429,10 +500,7 @@ function parseLiteralNode(expr, ctx) {
429
500
  }
430
501
  if (!_.isArray(defaultValue))
431
502
  throw new Error("Value must be valid array");
432
- return { type: "array", value: defaultValue };
433
- }
434
- if (expr.kind === SyntaxKind.PropertyAccessExpression && expr.expression.kind === SyntaxKind.ThisKeyword) {
435
- return { type: "thisReference", value: expr.name?.text };
503
+ return defaultValue;
436
504
  }
437
505
  throw new Error(`Unexpected property expression: "${expr.getText(ctx.sourceFile)}"`);
438
506
  }
@@ -447,7 +515,7 @@ function parseObjectLiteral(arg, ctx) {
447
515
  throw new Error(`Unexpected property value: "${p.getText(ctx.sourceFile)}"`);
448
516
  const p2 = p;
449
517
  const valueExpression = p2.initializer;
450
- const value = parseLiteralNode(valueExpression, ctx)?.value;
518
+ const value = parseLiteralNode(valueExpression, ctx);
451
519
  result[name] = value;
452
520
  }
453
521
  return result;
@@ -77,6 +77,11 @@ var _default = {
77
77
  async unlink(filepath) {
78
78
  sanitizeFilepath(filepath);
79
79
  return await _promises.default.unlink(filepath);
80
+ },
81
+ async rename(oldFilepath, newFilepath) {
82
+ sanitizeFilepath(oldFilepath);
83
+ sanitizeFilepath(newFilepath);
84
+ return await _promises.default.rename(oldFilepath, newFilepath);
80
85
  }
81
86
  };
82
87
  module.exports = _default;
@@ -19,5 +19,6 @@ declare const _default: {
19
19
  lstat(filepath: string, options?: any): Promise<any>;
20
20
  /** Delete a file */
21
21
  unlink(filepath: string): Promise<any>;
22
+ rename(oldFilepath: string, newFilepath: string): Promise<any>;
22
23
  };
23
24
  export default _default;
@@ -69,6 +69,11 @@ export default {
69
69
  async unlink(filepath) {
70
70
  sanitizeFilepath(filepath);
71
71
  return await fs.unlink(filepath);
72
+ },
73
+ async rename(oldFilepath, newFilepath) {
74
+ sanitizeFilepath(oldFilepath);
75
+ sanitizeFilepath(newFilepath);
76
+ return await fs.rename(oldFilepath, newFilepath);
72
77
  }
73
78
  };
74
79
  async function dirExists(path2) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rads-db",
3
- "version": "3.0.18",
3
+ "version": "3.0.20",
4
4
  "files": [
5
5
  "dist",
6
6
  "drivers",