okai 0.0.24 → 0.0.25
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/api.d.ts +12 -1
- package/dist/cs-apis.js +5 -0
- package/dist/cs-ast.js +326 -283
- package/dist/cs-gen.js +15 -9
- package/dist/cs-migrations.js +14 -5
- package/dist/index.js +80 -38
- package/dist/info.js +76 -0
- package/dist/ts-ast.js +32 -1
- package/dist/ts-once.js +240 -0
- package/dist/ts-parser.js +36 -27
- package/dist/tsd-gen.js +18 -81
- package/dist/utils.js +26 -1
- package/package.json +1 -1
package/dist/cs-ast.js
CHANGED
@@ -15,6 +15,25 @@ export class CSharpAst {
|
|
15
15
|
"undefined": sys("string"),
|
16
16
|
"bigint": sys("long"),
|
17
17
|
"any": sysObj,
|
18
|
+
"ArrayBuffer": sys("byte[]"),
|
19
|
+
"SharedArrayBuffer": sys("byte[]"),
|
20
|
+
"Int8Array": sys("sbyte[]"),
|
21
|
+
"UInt8Array": sys("byte[]"),
|
22
|
+
"Uint8ClampedArray": sys("byte[]"),
|
23
|
+
"Int16Array": sys("short[]"),
|
24
|
+
"UInt16Array": sys("ushort[]"),
|
25
|
+
"Int32Array": sys("int[]"),
|
26
|
+
"UInt32Array": sys("uint[]"),
|
27
|
+
"Float16Array": sys("float[]"),
|
28
|
+
"Float32Array": sys("float[]"),
|
29
|
+
"Float64Array": sys("double[]"),
|
30
|
+
"BigInt64Array": sys("long[]"),
|
31
|
+
"BigUInt64Array": sys("long[]"),
|
32
|
+
"Array": { name: "List", genericArgs: [], namespace: "System.Collections.Generic" },
|
33
|
+
"Map": { name: "Dictionary", genericArgs: [], namespace: "System.Collections.Generic" },
|
34
|
+
"WeakMap": { name: "Dictionary", genericArgs: [], namespace: "System.Collections.Generic" },
|
35
|
+
"Set": { name: "HashSet", genericArgs: [], namespace: "System.Collections.Generic" },
|
36
|
+
"WeakSet": { name: "HashSet", genericArgs: [], namespace: "System.Collections.Generic" },
|
18
37
|
};
|
19
38
|
decimalTypeProps = [
|
20
39
|
"price", "cost", "amount", "total", "salary", "balance", "rate", "discount", "tax", "fee"
|
@@ -181,24 +200,15 @@ export class CSharpAst {
|
|
181
200
|
].map(x => x.toLowerCase());
|
182
201
|
ignoreReadValidators = this.requestPropAttrs.filter(x => x.startsWith('validate')).map(x => x.toLowerCase());
|
183
202
|
ignoreDeleteValidators = this.requestPropAttrs.filter(x => x.startsWith('validate')).map(x => x.toLowerCase());
|
184
|
-
unwrap(type) {
|
185
|
-
if (type.endsWith("?")) {
|
186
|
-
return type.substring(0, type.length - 1);
|
187
|
-
}
|
188
|
-
return type;
|
189
|
-
}
|
190
|
-
nullable(type) {
|
191
|
-
return type.endsWith('?') ? type : `${type}?`;
|
192
|
-
}
|
193
203
|
isEnum(type) {
|
194
|
-
type =
|
204
|
+
type = unwrap(type);
|
195
205
|
return this.ast.enums.some(x => x.name === type) || this.result.types.find(x => x.name === type && x.isEnum);
|
196
206
|
}
|
197
207
|
isValueType(type) {
|
198
|
-
type =
|
208
|
+
type = unwrap(type);
|
199
209
|
return this.valueTypes.includes(type) || this.isEnum(type);
|
200
210
|
}
|
201
|
-
ast = { classes: [], interfaces: [], enums: [] };
|
211
|
+
ast = { references: [], classes: [], interfaces: [], enums: [] };
|
202
212
|
result = {
|
203
213
|
config: {},
|
204
214
|
namespaces: [],
|
@@ -213,6 +223,13 @@ export class CSharpAst {
|
|
213
223
|
const elType = this.csharpType(type.substring(0, type.length - 2), propName);
|
214
224
|
return Object.assign({}, elType, { name: elType.name + '[]' });
|
215
225
|
}
|
226
|
+
if (type.endsWith('>')) {
|
227
|
+
const start = type.indexOf('<');
|
228
|
+
const genericArgs = type.substring(start + 1, type.length - 1).split(',').map(x => this.csharpType(x.trim()).name);
|
229
|
+
const baseType = this.csharpType(type.substring(0, start), propName);
|
230
|
+
const ret = Object.assign({}, baseType, { genericArgs });
|
231
|
+
return ret;
|
232
|
+
}
|
216
233
|
if (propName) {
|
217
234
|
if (type === "number") {
|
218
235
|
if (this.decimalTypeProps.some(x => propName.toLowerCase().includes(x))) {
|
@@ -269,16 +286,20 @@ export class CSharpAst {
|
|
269
286
|
const type = this.csharpType(p.type, p.name);
|
270
287
|
const prop = {
|
271
288
|
name: this.toCsName(p.name),
|
272
|
-
type: p.optional ?
|
289
|
+
type: p.optional ? nullable(type.name) : type.name,
|
273
290
|
};
|
274
291
|
if (type.namespace) {
|
275
292
|
prop.namespace = type.namespace;
|
276
293
|
}
|
294
|
+
if (type.genericArgs) {
|
295
|
+
prop.genericArgs = type.genericArgs;
|
296
|
+
}
|
277
297
|
if (p.comment) {
|
278
298
|
prop.description = p.comment;
|
279
299
|
}
|
280
300
|
if (prop.name === 'Id') {
|
281
301
|
prop.isPrimaryKey = true;
|
302
|
+
prop.isRequired = true;
|
282
303
|
}
|
283
304
|
const valueType = this.isValueType(prop.type);
|
284
305
|
if (valueType) {
|
@@ -365,196 +386,6 @@ export class CSharpAst {
|
|
365
386
|
get typesWithReferences() {
|
366
387
|
return this.result.types.filter(x => !x.isEnum && !x.isInterface && x.properties?.some(x => x.attributes?.some(x => x.name === 'Reference')));
|
367
388
|
}
|
368
|
-
replaceReferences(references) {
|
369
|
-
// The most important types are the ones with the most references
|
370
|
-
const refCount = (t) => t.properties?.filter(p => this.result.types.find(x => x.name === p.type && p.namespace === 'MyApp')).length || 0;
|
371
|
-
const importantTypes = this.result.types.sort((x, y) => refCount(y) - refCount(x));
|
372
|
-
for (const type of this.result.types) {
|
373
|
-
if (references.includes(type.name)) {
|
374
|
-
const importantType = importantTypes.find(x => x.properties?.some(p => p.type === type.name));
|
375
|
-
if (importantType) {
|
376
|
-
const newName = `${importantType.name}${type.name}`;
|
377
|
-
this.replaceReference(type.name, newName);
|
378
|
-
}
|
379
|
-
}
|
380
|
-
}
|
381
|
-
}
|
382
|
-
replaceReference(fromType, toType) {
|
383
|
-
for (const type of this.result.types) {
|
384
|
-
if (type.name === fromType) {
|
385
|
-
type.name = toType;
|
386
|
-
}
|
387
|
-
if (type.properties) {
|
388
|
-
for (const prop of type.properties) {
|
389
|
-
if (prop.type === fromType) {
|
390
|
-
prop.type = toType;
|
391
|
-
}
|
392
|
-
if (prop.name === fromType) {
|
393
|
-
prop.name = toType;
|
394
|
-
}
|
395
|
-
if (prop.name === `${fromType}Id`) {
|
396
|
-
prop.name = `${toType}Id`;
|
397
|
-
}
|
398
|
-
}
|
399
|
-
}
|
400
|
-
}
|
401
|
-
}
|
402
|
-
replaceIds() {
|
403
|
-
for (const type of this.classes) {
|
404
|
-
const idProp = type.properties?.find(x => x.name === `${type.name}Id`);
|
405
|
-
if (idProp) {
|
406
|
-
type.properties?.forEach(x => delete x.isPrimaryKey);
|
407
|
-
idProp.name = 'Id';
|
408
|
-
idProp.isPrimaryKey = true;
|
409
|
-
}
|
410
|
-
// If using a shortened id for the type e.g. (PerformanceReview, ReviewId)
|
411
|
-
const firstProp = type.properties?.[0];
|
412
|
-
if (firstProp?.name.endsWith('Id') && type.name.includes(firstProp.name.substring(0, firstProp.name.length - 2))) {
|
413
|
-
firstProp.name = 'Id';
|
414
|
-
firstProp.isPrimaryKey = true;
|
415
|
-
}
|
416
|
-
}
|
417
|
-
const anyIntPks = this.classes.some(x => x.properties?.some(p => p.isPrimaryKey && this.integerTypes.includes(p.type)));
|
418
|
-
if (!anyIntPks) {
|
419
|
-
for (const type of this.classes) {
|
420
|
-
const idProp = type.properties?.find(x => x.isPrimaryKey);
|
421
|
-
if (idProp) {
|
422
|
-
idProp.type = 'int';
|
423
|
-
}
|
424
|
-
}
|
425
|
-
}
|
426
|
-
}
|
427
|
-
convertReferenceTypes() {
|
428
|
-
for (const type of this.classes) {
|
429
|
-
for (let i = 0; i < type.properties.length; i++) {
|
430
|
-
const p = type.properties[i];
|
431
|
-
const refType = this.result.types.find(x => x.name === p.type && x.namespace === 'MyApp' && !x.isEnum);
|
432
|
-
if (refType) {
|
433
|
-
const fkId = `${p.name}Id`;
|
434
|
-
let idProp = refType.properties?.find(x => x.name === 'Id');
|
435
|
-
if (!idProp) {
|
436
|
-
idProp = { name: 'Id', type: 'int', isPrimaryKey: true, isValueType: true, namespace: 'System' };
|
437
|
-
refType.properties?.unshift(idProp);
|
438
|
-
}
|
439
|
-
// Only add if FK Id prop does not already exist
|
440
|
-
if (!type.properties.find(x => x.name === fkId)) {
|
441
|
-
const fkProp = {
|
442
|
-
name: fkId,
|
443
|
-
type: idProp.type,
|
444
|
-
namespace: idProp.namespace,
|
445
|
-
attributes: [{
|
446
|
-
name: "References",
|
447
|
-
constructorArgs: [{
|
448
|
-
name: "type",
|
449
|
-
type: "Type",
|
450
|
-
value: `typeof(${p.type})`
|
451
|
-
}],
|
452
|
-
args: []
|
453
|
-
}]
|
454
|
-
};
|
455
|
-
type.properties.splice(i, 0, fkProp);
|
456
|
-
}
|
457
|
-
if (!p.attributes)
|
458
|
-
p.attributes = [];
|
459
|
-
p.attributes.push({ name: "Reference" });
|
460
|
-
i++; // Skip over added fk prop
|
461
|
-
}
|
462
|
-
}
|
463
|
-
}
|
464
|
-
}
|
465
|
-
convertArrayReferenceTypes() {
|
466
|
-
for (const type of this.classes) {
|
467
|
-
for (const prop of type.properties) {
|
468
|
-
if (prop.type.endsWith('[]')) {
|
469
|
-
const elType = prop.type.substring(0, prop.type.length - 2);
|
470
|
-
const refType = this.result.types.find(x => x.name === elType && x.namespace === 'MyApp' && !x.isEnum);
|
471
|
-
if (refType && refType.properties?.find(x => x.name === 'Id' || x.isPrimaryKey)) {
|
472
|
-
prop.namespace = 'System.Collections.Generic';
|
473
|
-
prop.genericArgs = [elType];
|
474
|
-
prop.type = 'List`1';
|
475
|
-
if (!prop.attributes)
|
476
|
-
prop.attributes = [];
|
477
|
-
prop.attributes.push({ name: "Reference" });
|
478
|
-
let fkProp = refType.properties.find(x => x.name === `${type.name}Id`);
|
479
|
-
if (!fkProp) {
|
480
|
-
fkProp = {
|
481
|
-
name: `${type.name}Id`,
|
482
|
-
type: 'int',
|
483
|
-
isValueType: true,
|
484
|
-
namespace: 'System',
|
485
|
-
attributes: [{
|
486
|
-
name: "References",
|
487
|
-
constructorArgs: [{
|
488
|
-
name: "type",
|
489
|
-
type: "Type",
|
490
|
-
value: `typeof(${type.name})`
|
491
|
-
}]
|
492
|
-
}]
|
493
|
-
};
|
494
|
-
// Insert fk prop after last `*Id` prop
|
495
|
-
const lastIdPropIndex = refType.properties.findLastIndex(x => x.name.endsWith('Id'));
|
496
|
-
if (lastIdPropIndex >= 0) {
|
497
|
-
refType.properties.splice(lastIdPropIndex + 1, 0, fkProp);
|
498
|
-
}
|
499
|
-
else {
|
500
|
-
refType.properties.push(fkProp);
|
501
|
-
}
|
502
|
-
}
|
503
|
-
}
|
504
|
-
}
|
505
|
-
}
|
506
|
-
}
|
507
|
-
}
|
508
|
-
convertArraysToLists() {
|
509
|
-
for (const type of this.classes) {
|
510
|
-
for (const prop of type.properties) {
|
511
|
-
const optional = prop.type.endsWith('?');
|
512
|
-
let propType = this.unwrap(prop.type);
|
513
|
-
if (propType.endsWith('[]')) {
|
514
|
-
const elType = propType.substring(0, propType.length - 2);
|
515
|
-
prop.namespace = 'System.Collections.Generic';
|
516
|
-
prop.genericArgs = [elType];
|
517
|
-
prop.type = 'List`1' + (optional ? '?' : '');
|
518
|
-
}
|
519
|
-
}
|
520
|
-
}
|
521
|
-
}
|
522
|
-
addMissingReferencesToForeignKeyProps() {
|
523
|
-
for (const type of this.typesWithPrimaryKeys) {
|
524
|
-
for (const prop of type.properties) {
|
525
|
-
if (prop.name.endsWith('Id') && !prop.isPrimaryKey && !prop.attributes?.some(x => x.name.startsWith('Reference'))) {
|
526
|
-
const refTypeName = prop.name.substring(0, prop.name.length - 2);
|
527
|
-
const refType = this.result.types.find(x => x.name === refTypeName && x.namespace === 'MyApp' && !x.isEnum);
|
528
|
-
if (refType) {
|
529
|
-
if (!prop.attributes)
|
530
|
-
prop.attributes = [];
|
531
|
-
prop.attributes.push({
|
532
|
-
name: "References",
|
533
|
-
constructorArgs: [{
|
534
|
-
name: "type",
|
535
|
-
type: "Type",
|
536
|
-
value: `typeof(${refTypeName})`
|
537
|
-
}]
|
538
|
-
});
|
539
|
-
}
|
540
|
-
}
|
541
|
-
}
|
542
|
-
}
|
543
|
-
}
|
544
|
-
addAutoIncrementAttrs() {
|
545
|
-
for (const type of this.classes) {
|
546
|
-
for (const prop of type.properties) {
|
547
|
-
if (prop.isPrimaryKey) {
|
548
|
-
if (prop.type === 'int' || prop.type === 'long' || prop.type === 'Int32' || prop.type === 'Int64') {
|
549
|
-
if (!prop.attributes)
|
550
|
-
prop.attributes = [];
|
551
|
-
const attr = { name: "AutoIncrement" };
|
552
|
-
prop.attributes.push(attr);
|
553
|
-
}
|
554
|
-
}
|
555
|
-
}
|
556
|
-
}
|
557
|
-
}
|
558
389
|
onlyAttrs(attrs, only) {
|
559
390
|
if (!attrs)
|
560
391
|
return;
|
@@ -683,7 +514,7 @@ export class CSharpAst {
|
|
683
514
|
properties: pk
|
684
515
|
? [
|
685
516
|
Object.assign({}, pk, {
|
686
|
-
type:
|
517
|
+
type: nullable(pk.type),
|
687
518
|
attributes: this.attrsFor("Read", "Prop", pk.attributes),
|
688
519
|
}),
|
689
520
|
idsProp
|
@@ -804,7 +635,7 @@ export class CSharpAst {
|
|
804
635
|
properties: type.properties?.filter(x => !x.attributes?.some(x => this.ignoreUpdateProps.includes(x.name.toLowerCase()))).map(x => Object.assign({}, x, {
|
805
636
|
type: x.isPrimaryKey
|
806
637
|
? x.type
|
807
|
-
: `${
|
638
|
+
: `${nullable(x.type)}`,
|
808
639
|
attributes: this.attrsFor("Update", "Prop", x.attributes),
|
809
640
|
})),
|
810
641
|
attributes: this.attrsFor("Update", "Type", type.attributes),
|
@@ -857,7 +688,7 @@ export class CSharpAst {
|
|
857
688
|
properties: pk
|
858
689
|
? [
|
859
690
|
Object.assign({}, pk, {
|
860
|
-
type:
|
691
|
+
type: nullable(pk.type),
|
861
692
|
attributes: this.attrsFor("Delete", "Prop", pk.attributes),
|
862
693
|
}),
|
863
694
|
idsProp
|
@@ -885,6 +716,8 @@ export class CSharpAst {
|
|
885
716
|
this.result.operations.push(deleteApi);
|
886
717
|
}
|
887
718
|
}
|
719
|
+
this.filterModelAttributes();
|
720
|
+
return this.result;
|
888
721
|
}
|
889
722
|
filterModelAttributes() {
|
890
723
|
for (const type of this.classes) {
|
@@ -898,68 +731,6 @@ export class CSharpAst {
|
|
898
731
|
});
|
899
732
|
}
|
900
733
|
}
|
901
|
-
// Add Icon for BuiltIn UIs and AutoQueryGrid to known type names
|
902
|
-
addIconsToKnownTypes() {
|
903
|
-
for (const type of this.typesWithPrimaryKeys) {
|
904
|
-
const icon = Icons[type.name];
|
905
|
-
if (icon) {
|
906
|
-
if (!type.attributes)
|
907
|
-
type.attributes = [];
|
908
|
-
const existingIcon = type.attributes.find(x => x.name === 'Icon');
|
909
|
-
if (existingIcon) {
|
910
|
-
// remove empty icon
|
911
|
-
if (existingIcon.constructorArgs?.[0]?.value === '') {
|
912
|
-
type.attributes = type.attributes.filter(x => x !== existingIcon);
|
913
|
-
}
|
914
|
-
return;
|
915
|
-
}
|
916
|
-
type.attributes.push({
|
917
|
-
name: "Icon",
|
918
|
-
args: [{ name: "Svg", type: "string", value: icon }]
|
919
|
-
});
|
920
|
-
}
|
921
|
-
}
|
922
|
-
}
|
923
|
-
// Hide Reference Properties from AutoQueryGrid Grid View
|
924
|
-
hideReferenceProperties() {
|
925
|
-
for (const type of this.typesWithReferences) {
|
926
|
-
for (const prop of type.properties.filter(x => x.attributes?.some(x => x.name === 'Reference'))) {
|
927
|
-
if (!prop.attributes)
|
928
|
-
prop.attributes = [];
|
929
|
-
//[Format(FormatMethods.Hidden)]
|
930
|
-
prop.attributes.push({
|
931
|
-
name: "Format",
|
932
|
-
constructorArgs: [{ name: "method", type: "constant", value: "FormatMethods.Hidden" }]
|
933
|
-
});
|
934
|
-
}
|
935
|
-
}
|
936
|
-
}
|
937
|
-
// Replace User Tables and FKs with AuditBase tables and
|
938
|
-
replaceUserReferencesWithAuditTables() {
|
939
|
-
for (const type of this.typesWithPrimaryKeys) {
|
940
|
-
const removeProps = [];
|
941
|
-
for (const prop of type.properties) {
|
942
|
-
if (prop.name === 'UserId') {
|
943
|
-
removeProps.push(prop.name);
|
944
|
-
}
|
945
|
-
if (prop.attributes?.some(a => a.name === 'Reference' && a.constructorArgs?.some(x => x.value === 'typeof(User)'))) {
|
946
|
-
removeProps.push(prop.name);
|
947
|
-
}
|
948
|
-
if (prop.type === 'User') {
|
949
|
-
removeProps.push(prop.name);
|
950
|
-
}
|
951
|
-
if (prop.genericArgs && prop.genericArgs.includes('User')) {
|
952
|
-
removeProps.push(prop.name);
|
953
|
-
}
|
954
|
-
}
|
955
|
-
if (removeProps.length) {
|
956
|
-
type.properties = type.properties.filter(x => !removeProps.includes(x.name));
|
957
|
-
type.inherits = { name: "AuditBase", namespace: "ServiceStack" };
|
958
|
-
}
|
959
|
-
}
|
960
|
-
// Remove User Table
|
961
|
-
this.result.types = this.result.types.filter(x => x.name !== 'User');
|
962
|
-
}
|
963
734
|
parseTypes() {
|
964
735
|
this.ast.classes.forEach(c => {
|
965
736
|
const name = toPascalCase(c.name);
|
@@ -973,23 +744,12 @@ export class CSharpAst {
|
|
973
744
|
return;
|
974
745
|
this.addMetadataEnum(e);
|
975
746
|
});
|
976
|
-
this.replaceReferences(['Service']);
|
977
|
-
this.replaceIds();
|
978
|
-
this.convertReferenceTypes();
|
979
|
-
this.convertArrayReferenceTypes();
|
980
|
-
this.convertArraysToLists();
|
981
|
-
this.addMissingReferencesToForeignKeyProps();
|
982
|
-
this.addAutoIncrementAttrs();
|
983
|
-
this.addIconsToKnownTypes();
|
984
|
-
this.hideReferenceProperties();
|
985
|
-
this.replaceUserReferencesWithAuditTables();
|
986
|
-
this.createAutoCrudApis();
|
987
|
-
this.filterModelAttributes();
|
988
747
|
}
|
989
748
|
parse(ast) {
|
990
749
|
const classes = ast.classes.concat(ast.interfaces);
|
991
750
|
const enums = ast.enums;
|
992
751
|
this.ast = {
|
752
|
+
references: [],
|
993
753
|
classes: classes,
|
994
754
|
interfaces: [],
|
995
755
|
enums: enums ?? [],
|
@@ -1012,7 +772,290 @@ export class CSharpAst {
|
|
1012
772
|
return this.result;
|
1013
773
|
}
|
1014
774
|
}
|
1015
|
-
export
|
1016
|
-
|
1017
|
-
|
775
|
+
export const Transforms = {
|
776
|
+
Default: [
|
777
|
+
convertReferenceTypes,
|
778
|
+
convertArrayReferenceTypes,
|
779
|
+
convertArraysToLists,
|
780
|
+
addMissingReferencesToForeignKeyProps,
|
781
|
+
addAutoIncrementAttrs,
|
782
|
+
addIconsToKnownTypes,
|
783
|
+
hideReferenceProperties,
|
784
|
+
],
|
785
|
+
};
|
786
|
+
export function toMetadataTypes(ast, transforms) {
|
787
|
+
const gen = new CSharpAst();
|
788
|
+
gen.parse(ast);
|
789
|
+
if (!transforms)
|
790
|
+
transforms = Transforms.Default;
|
791
|
+
for (const transform of transforms) {
|
792
|
+
transform(gen);
|
793
|
+
}
|
794
|
+
return gen.createAutoCrudApis();
|
795
|
+
}
|
796
|
+
export function unwrap(type) {
|
797
|
+
if (type.endsWith("?")) {
|
798
|
+
return type.substring(0, type.length - 1);
|
799
|
+
}
|
800
|
+
return type;
|
801
|
+
}
|
802
|
+
export function nullable(type) {
|
803
|
+
return type.endsWith('?') ? type : `${type}?`;
|
804
|
+
}
|
805
|
+
export function replaceReference(gen, fromType, toType) {
|
806
|
+
for (const type of gen.result.types) {
|
807
|
+
if (type.name === fromType) {
|
808
|
+
type.name = toType;
|
809
|
+
}
|
810
|
+
if (type.properties) {
|
811
|
+
for (const prop of type.properties) {
|
812
|
+
if (prop.type === fromType) {
|
813
|
+
prop.type = toType;
|
814
|
+
}
|
815
|
+
if (prop.name === fromType) {
|
816
|
+
prop.name = toType;
|
817
|
+
}
|
818
|
+
if (prop.name === `${fromType}Id`) {
|
819
|
+
prop.name = `${toType}Id`;
|
820
|
+
}
|
821
|
+
}
|
822
|
+
}
|
823
|
+
}
|
824
|
+
}
|
825
|
+
export function replaceServiceReferences(gen) {
|
826
|
+
replaceReferences(gen, ['Service']);
|
827
|
+
}
|
828
|
+
export function replaceReferences(gen, references) {
|
829
|
+
// The most important types are the ones with the most references
|
830
|
+
const refCount = (t) => t.properties?.filter(p => gen.result.types.find(x => x.name === p.type && p.namespace === 'MyApp')).length || 0;
|
831
|
+
const importantTypes = gen.result.types.sort((x, y) => refCount(y) - refCount(x));
|
832
|
+
for (const type of gen.result.types) {
|
833
|
+
if (references.includes(type.name)) {
|
834
|
+
const importantType = importantTypes.find(x => x.properties?.some(p => p.type === type.name));
|
835
|
+
if (importantType) {
|
836
|
+
const newName = `${importantType.name}${type.name}`;
|
837
|
+
replaceReference(gen, type.name, newName);
|
838
|
+
}
|
839
|
+
}
|
840
|
+
}
|
841
|
+
}
|
842
|
+
export function replaceIds(gen) {
|
843
|
+
for (const type of gen.classes) {
|
844
|
+
const idProp = type.properties?.find(x => x.name === `${type.name}Id`);
|
845
|
+
if (idProp) {
|
846
|
+
type.properties?.forEach(x => delete x.isPrimaryKey);
|
847
|
+
idProp.name = 'Id';
|
848
|
+
idProp.isPrimaryKey = true;
|
849
|
+
}
|
850
|
+
// If using a shortened id for the type e.g. (PerformanceReview, ReviewId)
|
851
|
+
const firstProp = type.properties?.[0];
|
852
|
+
if (firstProp?.name.endsWith('Id') && type.name.includes(firstProp.name.substring(0, firstProp.name.length - 2))) {
|
853
|
+
firstProp.name = 'Id';
|
854
|
+
firstProp.isPrimaryKey = true;
|
855
|
+
}
|
856
|
+
}
|
857
|
+
// Replace all string Ids with int Ids
|
858
|
+
const anyIntPks = gen.classes.some(x => x.properties?.some(p => p.isPrimaryKey && gen.integerTypes.includes(p.type)));
|
859
|
+
if (!anyIntPks) {
|
860
|
+
for (const type of gen.classes) {
|
861
|
+
const idProp = type.properties?.find(x => x.isPrimaryKey);
|
862
|
+
if (idProp) {
|
863
|
+
idProp.type = 'int';
|
864
|
+
}
|
865
|
+
}
|
866
|
+
}
|
867
|
+
}
|
868
|
+
export function convertReferenceTypes(gen) {
|
869
|
+
for (const type of gen.classes) {
|
870
|
+
for (let i = 0; i < type.properties.length; i++) {
|
871
|
+
const p = type.properties[i];
|
872
|
+
const refType = gen.result.types.find(x => x.name === p.type && x.namespace === 'MyApp' && !x.isEnum);
|
873
|
+
if (refType) {
|
874
|
+
const fkId = `${p.name}Id`;
|
875
|
+
let idProp = refType.properties?.find(x => x.name === 'Id');
|
876
|
+
if (!idProp) {
|
877
|
+
idProp = { name: 'Id', type: 'int', isPrimaryKey: true, isRequired: true, isValueType: true, namespace: 'System' };
|
878
|
+
refType.properties?.unshift(idProp);
|
879
|
+
}
|
880
|
+
// Only add if FK Id prop does not already exist
|
881
|
+
if (!type.properties.find(x => x.name === fkId)) {
|
882
|
+
const fkProp = {
|
883
|
+
name: fkId,
|
884
|
+
type: idProp.type,
|
885
|
+
namespace: idProp.namespace,
|
886
|
+
attributes: [{
|
887
|
+
name: "References",
|
888
|
+
constructorArgs: [{
|
889
|
+
name: "type",
|
890
|
+
type: "Type",
|
891
|
+
value: `typeof(${p.type})`
|
892
|
+
}],
|
893
|
+
args: []
|
894
|
+
}]
|
895
|
+
};
|
896
|
+
type.properties.splice(i, 0, fkProp);
|
897
|
+
}
|
898
|
+
if (!p.attributes)
|
899
|
+
p.attributes = [];
|
900
|
+
p.attributes.push({ name: "Reference" });
|
901
|
+
i++; // Skip over added fk prop
|
902
|
+
}
|
903
|
+
}
|
904
|
+
}
|
905
|
+
}
|
906
|
+
export function convertArrayReferenceTypes(gen) {
|
907
|
+
for (const type of gen.classes) {
|
908
|
+
for (const prop of type.properties) {
|
909
|
+
if (prop.type.endsWith('[]')) {
|
910
|
+
const elType = prop.type.substring(0, prop.type.length - 2);
|
911
|
+
const refType = gen.result.types.find(x => x.name === elType && x.namespace === 'MyApp' && !x.isEnum);
|
912
|
+
if (refType && refType.properties?.find(x => x.name === 'Id' || x.isPrimaryKey)) {
|
913
|
+
prop.namespace = 'System.Collections.Generic';
|
914
|
+
prop.genericArgs = [elType];
|
915
|
+
prop.type = 'List`1';
|
916
|
+
if (!prop.attributes)
|
917
|
+
prop.attributes = [];
|
918
|
+
prop.attributes.push({ name: "Reference" });
|
919
|
+
let fkProp = refType.properties.find(x => x.name === `${type.name}Id`);
|
920
|
+
if (!fkProp) {
|
921
|
+
fkProp = {
|
922
|
+
name: `${type.name}Id`,
|
923
|
+
type: 'int',
|
924
|
+
isValueType: true,
|
925
|
+
namespace: 'System',
|
926
|
+
attributes: [{
|
927
|
+
name: "References",
|
928
|
+
constructorArgs: [{
|
929
|
+
name: "type",
|
930
|
+
type: "Type",
|
931
|
+
value: `typeof(${type.name})`
|
932
|
+
}]
|
933
|
+
}]
|
934
|
+
};
|
935
|
+
// Insert fk prop after last `*Id` prop
|
936
|
+
const lastIdPropIndex = refType.properties.findLastIndex(x => x.name.endsWith('Id'));
|
937
|
+
if (lastIdPropIndex >= 0) {
|
938
|
+
refType.properties.splice(lastIdPropIndex + 1, 0, fkProp);
|
939
|
+
}
|
940
|
+
else {
|
941
|
+
refType.properties.push(fkProp);
|
942
|
+
}
|
943
|
+
}
|
944
|
+
}
|
945
|
+
}
|
946
|
+
}
|
947
|
+
}
|
948
|
+
}
|
949
|
+
export function convertArraysToLists(gen) {
|
950
|
+
for (const type of gen.classes) {
|
951
|
+
for (const prop of type.properties) {
|
952
|
+
const optional = prop.type.endsWith('?');
|
953
|
+
let propType = unwrap(prop.type);
|
954
|
+
if (propType.endsWith('[]')) {
|
955
|
+
const elType = propType.substring(0, propType.length - 2);
|
956
|
+
prop.namespace = 'System.Collections.Generic';
|
957
|
+
prop.genericArgs = [elType];
|
958
|
+
prop.type = 'List`1' + (optional ? '?' : '');
|
959
|
+
}
|
960
|
+
}
|
961
|
+
}
|
962
|
+
}
|
963
|
+
export function addMissingReferencesToForeignKeyProps(gen) {
|
964
|
+
for (const type of gen.typesWithPrimaryKeys) {
|
965
|
+
for (const prop of type.properties) {
|
966
|
+
if (prop.name.endsWith('Id') && !prop.isPrimaryKey && !prop.attributes?.some(x => x.name.startsWith('Reference'))) {
|
967
|
+
const refTypeName = prop.name.substring(0, prop.name.length - 2);
|
968
|
+
const refType = gen.result.types.find(x => x.name === refTypeName && x.namespace === 'MyApp' && !x.isEnum);
|
969
|
+
if (refType) {
|
970
|
+
if (!prop.attributes)
|
971
|
+
prop.attributes = [];
|
972
|
+
prop.attributes.push({
|
973
|
+
name: "References",
|
974
|
+
constructorArgs: [{
|
975
|
+
name: "type",
|
976
|
+
type: "Type",
|
977
|
+
value: `typeof(${refTypeName})`
|
978
|
+
}]
|
979
|
+
});
|
980
|
+
}
|
981
|
+
}
|
982
|
+
}
|
983
|
+
}
|
984
|
+
}
|
985
|
+
export function addAutoIncrementAttrs(gen) {
|
986
|
+
for (const type of gen.classes) {
|
987
|
+
for (const prop of type.properties) {
|
988
|
+
const hasPkAttr = prop.attributes?.some(x => ['primarykey', 'autoincrement', 'autoid'].includes(x.name.toLowerCase()));
|
989
|
+
if (prop.isPrimaryKey && !hasPkAttr) {
|
990
|
+
if (prop.type === 'int' || prop.type === 'long' || prop.type === 'Int32' || prop.type === 'Int64') {
|
991
|
+
if (!prop.attributes)
|
992
|
+
prop.attributes = [];
|
993
|
+
const attr = { name: "AutoIncrement" };
|
994
|
+
prop.attributes.push(attr);
|
995
|
+
}
|
996
|
+
}
|
997
|
+
}
|
998
|
+
}
|
999
|
+
}
|
1000
|
+
// Add Icon for BuiltIn UIs and AutoQueryGrid to known type names
|
1001
|
+
export function addIconsToKnownTypes(gen) {
|
1002
|
+
for (const type of gen.typesWithPrimaryKeys) {
|
1003
|
+
const icon = Icons[type.name];
|
1004
|
+
if (icon) {
|
1005
|
+
if (!type.attributes)
|
1006
|
+
type.attributes = [];
|
1007
|
+
const existingIcon = type.attributes.find(x => x.name === 'Icon');
|
1008
|
+
if (existingIcon) {
|
1009
|
+
// remove empty icon
|
1010
|
+
if (existingIcon.constructorArgs?.[0]?.value === '') {
|
1011
|
+
type.attributes = type.attributes.filter(x => x !== existingIcon);
|
1012
|
+
}
|
1013
|
+
return;
|
1014
|
+
}
|
1015
|
+
type.attributes.push({
|
1016
|
+
name: "Icon",
|
1017
|
+
args: [{ name: "Svg", type: "string", value: icon }]
|
1018
|
+
});
|
1019
|
+
}
|
1020
|
+
}
|
1021
|
+
}
|
1022
|
+
// Hide Reference Properties from AutoQueryGrid Grid View
|
1023
|
+
export function hideReferenceProperties(gen) {
|
1024
|
+
for (const type of gen.typesWithReferences) {
|
1025
|
+
for (const prop of type.properties.filter(x => x.attributes?.some(x => x.name === 'Reference'))) {
|
1026
|
+
if (!prop.attributes)
|
1027
|
+
prop.attributes = [];
|
1028
|
+
//[Format(FormatMethods.Hidden)]
|
1029
|
+
prop.attributes.push({
|
1030
|
+
name: "Format",
|
1031
|
+
constructorArgs: [{ name: "method", type: "constant", value: "FormatMethods.Hidden" }]
|
1032
|
+
});
|
1033
|
+
}
|
1034
|
+
}
|
1035
|
+
}
|
1036
|
+
// Replace User Tables and FKs with AuditBase tables and
|
1037
|
+
export function replaceUserReferencesWithAuditTables(gen) {
|
1038
|
+
for (const type of gen.typesWithPrimaryKeys) {
|
1039
|
+
const removeProps = [];
|
1040
|
+
for (const prop of type.properties) {
|
1041
|
+
if (prop.name === 'UserId') {
|
1042
|
+
removeProps.push(prop.name);
|
1043
|
+
}
|
1044
|
+
if (prop.attributes?.some(a => a.name === 'Reference' && a.constructorArgs?.some(x => x.value === 'typeof(User)'))) {
|
1045
|
+
removeProps.push(prop.name);
|
1046
|
+
}
|
1047
|
+
if (prop.type === 'User') {
|
1048
|
+
removeProps.push(prop.name);
|
1049
|
+
}
|
1050
|
+
if (prop.genericArgs && prop.genericArgs.includes('User')) {
|
1051
|
+
removeProps.push(prop.name);
|
1052
|
+
}
|
1053
|
+
}
|
1054
|
+
if (removeProps.length) {
|
1055
|
+
type.properties = type.properties.filter(x => !removeProps.includes(x.name));
|
1056
|
+
type.inherits = { name: "AuditBase", namespace: "ServiceStack" };
|
1057
|
+
}
|
1058
|
+
}
|
1059
|
+
// Remove User Table
|
1060
|
+
gen.result.types = gen.result.types.filter(x => x.name !== 'User');
|
1018
1061
|
}
|