okai 0.0.23 → 0.0.24

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 CHANGED
@@ -98,9 +98,9 @@ declare global {
98
98
  export function validateExactLength(length:number) : ClassFieldDecoratorDef
99
99
  export function validateMinimumLength(min:number) : ClassFieldDecoratorDef
100
100
  export function validateMaximumLength(max:number) : ClassFieldDecoratorDef
101
- export function validateLessThanLength(value:number) : ClassFieldDecoratorDef
101
+ export function validateLessThan(value:number) : ClassFieldDecoratorDef
102
102
  export function validateLessThanOrEqual(value:number) : ClassFieldDecoratorDef
103
- export function validateGreaterThanLength(value:number) : ClassFieldDecoratorDef
103
+ export function validateGreaterThan(value:number) : ClassFieldDecoratorDef
104
104
  export function validateGreaterThanOrEqual(value:number) : ClassFieldDecoratorDef
105
105
  export function validateScalePrecision(scale:number, precision:number) : ClassFieldDecoratorDef
106
106
  export function validateRegularExpression(pattern:string) : ClassFieldDecoratorDef
@@ -264,9 +264,9 @@ declare global {
264
264
  validateExactLength:typeof validateExactLength
265
265
  validateMinimumLength:typeof validateMinimumLength
266
266
  validateMaximumLength:typeof validateMaximumLength
267
- validateLessThanLength:typeof validateLessThanLength
267
+ validateLessThan:typeof validateLessThan
268
268
  validateLessThanOrEqual:typeof validateLessThanOrEqual
269
- validateGreaterThanLength:typeof validateGreaterThanLength
269
+ validateGreaterThan:typeof validateGreaterThan
270
270
  validateGreaterThanOrEqual:typeof validateGreaterThanOrEqual
271
271
  validateScalePrecision:typeof validateScalePrecision
272
272
  validateRegularExpression:typeof validateRegularExpression
package/dist/cs-apis.js CHANGED
@@ -1,4 +1,4 @@
1
- import { getGroupName, splitCase } from "./utils.js";
1
+ import { getGroupName } from "./utils.js";
2
2
  import { CSharpGenerator } from "./cs-gen.js";
3
3
  export class CSharpApiGenerator extends CSharpGenerator {
4
4
  toApiClass(op) {
@@ -78,14 +78,6 @@ export class CSharpApiGenerator extends CSharpGenerator {
78
78
  }
79
79
  generate(ast) {
80
80
  const groupName = getGroupName(ast);
81
- const friendlyGroupName = splitCase(groupName);
82
- ast.operations.forEach(op => {
83
- if (op.request.attributes?.find(x => x.name === 'Tag'))
84
- return;
85
- if (!op.tags)
86
- op.tags = [];
87
- op.tags.push(friendlyGroupName);
88
- });
89
81
  this.namespaces = Array.from(ast.namespaces);
90
82
  this.apis = ast.operations.map(x => this.toApiClass(x));
91
83
  this.classes = ast.types.filter(t => !t.isEnum).map(x => this.toClass(x));
package/dist/cs-ast.js CHANGED
@@ -1,4 +1,4 @@
1
- import { leftPart, plural, rightPart, toPascalCase } from "./utils.js";
1
+ import { getGroupName, leftPart, plural, rightPart, splitCase, toPascalCase } from "./utils.js";
2
2
  import { Icons } from "./icons.js";
3
3
  const sys = (name, genericArgs) => ({ name, namespace: "System", genericArgs });
4
4
  const sysObj = sys("object");
@@ -84,9 +84,9 @@ export class CSharpAst {
84
84
  'validateExactLength',
85
85
  'validateMinimumLength',
86
86
  'validateMaximumLength',
87
- 'validateLessThanLength',
87
+ 'validateLessThan',
88
88
  'validateLessThanOrEqual',
89
- 'validateGreaterThanLength',
89
+ 'validateGreaterThan',
90
90
  'validateGreaterThanOrEqual',
91
91
  'validateScalePrecision',
92
92
  'validateRegularExpression',
@@ -110,6 +110,9 @@ export class CSharpAst {
110
110
  'fieldCss',
111
111
  'uploadTo',
112
112
  ].map(x => x.toLowerCase());
113
+ get requestPropAttrsWithoutValidators() {
114
+ return this.requestPropAttrs.filter(x => !x.startsWith('validate'));
115
+ }
113
116
  modelPropAttrs = [
114
117
  'alias',
115
118
  'meta',
@@ -157,6 +160,27 @@ export class CSharpAst {
157
160
  'intlDateTime',
158
161
  'intlRelativeTime',
159
162
  ].map(x => x.toLowerCase());
163
+ // Ignore properties with these attributes on APIs
164
+ ignoreCreateProps = [
165
+ 'autoIncrement',
166
+ 'references',
167
+ 'compute',
168
+ 'computed',
169
+ ].map(x => x.toLowerCase());
170
+ ignoreUpdateProps = [
171
+ 'references',
172
+ 'compute',
173
+ 'computed',
174
+ ].map(x => x.toLowerCase());
175
+ // Validators that should be on Create but not optional Update APIs
176
+ ignoreUpdateValidators = [
177
+ 'validateNull',
178
+ 'validateNotNull',
179
+ 'validateEmpty',
180
+ 'validateNotEmpty',
181
+ ].map(x => x.toLowerCase());
182
+ ignoreReadValidators = this.requestPropAttrs.filter(x => x.startsWith('validate')).map(x => x.toLowerCase());
183
+ ignoreDeleteValidators = this.requestPropAttrs.filter(x => x.startsWith('validate')).map(x => x.toLowerCase());
160
184
  unwrap(type) {
161
185
  if (type.endsWith("?")) {
162
186
  return type.substring(0, type.length - 1);
@@ -531,12 +555,36 @@ export class CSharpAst {
531
555
  }
532
556
  }
533
557
  }
534
- attrsFor(dtoType, attrs) {
558
+ onlyAttrs(attrs, only) {
559
+ if (!attrs)
560
+ return;
561
+ return attrs.filter(x => only.includes(x.name.toLowerCase()));
562
+ }
563
+ attrsFor(dtoType, attrType, attrs) {
535
564
  const requestAttrs = this.requestAttrs;
536
565
  const requestPropAttrs = this.requestPropAttrs;
537
566
  const modelAttrs = this.modelAttrs;
538
567
  const modelPropAttrs = this.modelPropAttrs;
568
+ const isRequest = ["Read", "Create", "Update", "Delete"].includes(dtoType);
569
+ const validAttrs = attrType === "Type"
570
+ ? isRequest
571
+ ? requestAttrs
572
+ : modelAttrs
573
+ : isRequest
574
+ ? requestPropAttrs
575
+ : modelPropAttrs;
576
+ const ignoreValidators = attrType === "Prop"
577
+ ? dtoType === "Update"
578
+ ? this.ignoreUpdateValidators
579
+ : dtoType === "Read"
580
+ ? this.ignoreReadValidators
581
+ : dtoType === "Delete"
582
+ ? this.ignoreDeleteValidators
583
+ : []
584
+ : [];
539
585
  function shouldInclude(attr, dtoType) {
586
+ if (!validAttrs.includes(attr.name.toLowerCase()))
587
+ return false;
540
588
  const ns = attr.namespace;
541
589
  if (ns) {
542
590
  if (ns == "All")
@@ -551,15 +599,27 @@ export class CSharpAst {
551
599
  return dtoType == "Delete";
552
600
  if (ns == "Write")
553
601
  return ["Create", "Update", "Delete"].includes(dtoType);
602
+ return false;
554
603
  }
555
604
  else {
556
- const isRequest = dtoType != "Model";
557
605
  const nameLower = attr.name.toLowerCase();
558
606
  if (isRequest) {
559
- return requestAttrs.includes(nameLower) || requestPropAttrs.includes(nameLower);
607
+ if (attrType === "Type") {
608
+ return requestAttrs.includes(nameLower);
609
+ }
610
+ else if (attrType === "Prop") {
611
+ if (ignoreValidators.length && ignoreValidators.includes(nameLower))
612
+ return false;
613
+ return requestPropAttrs.includes(nameLower);
614
+ }
560
615
  }
561
616
  else {
562
- return modelAttrs.includes(nameLower) || modelPropAttrs.includes(nameLower);
617
+ if (attrType === "Type") {
618
+ return modelAttrs.includes(nameLower);
619
+ }
620
+ else if (attrType === "Prop") {
621
+ return modelPropAttrs.includes(nameLower);
622
+ }
563
623
  }
564
624
  }
565
625
  return true;
@@ -573,6 +633,8 @@ export class CSharpAst {
573
633
  return to;
574
634
  }
575
635
  createAutoCrudApis() {
636
+ const groupName = getGroupName(this.result);
637
+ const friendlyGroupName = splitCase(groupName);
576
638
  for (const type of this.classes) {
577
639
  const hasPk = type.properties?.some(x => x.isPrimaryKey);
578
640
  if (!hasPk)
@@ -583,6 +645,12 @@ export class CSharpAst {
583
645
  const pk = type.properties?.find(x => x.isPrimaryKey);
584
646
  const dataModel = { name: type.name, namespace: type.name };
585
647
  const isAuditBase = type.inherits?.name === 'AuditBase';
648
+ const existingTag = type.attributes?.find(x => x.name.toLowerCase() === 'tag');
649
+ const tags = !existingTag ? [friendlyGroupName] : undefined;
650
+ const emptyTag = existingTag?.constructorArgs?.[0]?.value === '';
651
+ if (emptyTag) {
652
+ type.attributes = type.attributes.filter(x => x !== existingTag);
653
+ }
586
654
  const inputTagAttrs = [{
587
655
  name: "Input",
588
656
  args: [{ name: "Type", type: "string", value: "tag" }]
@@ -591,11 +659,6 @@ export class CSharpAst {
591
659
  name: "FieldCss",
592
660
  args: [{ name: "Field", type: "string", value: "col-span-12" }]
593
661
  }];
594
- function onlyAttrs(attrs, only) {
595
- if (!attrs)
596
- return;
597
- return attrs.filter(x => only.includes(x.name));
598
- }
599
662
  const idsProp = pk
600
663
  ? {
601
664
  name: `${pk.name}s`,
@@ -620,13 +683,13 @@ export class CSharpAst {
620
683
  properties: pk
621
684
  ? [
622
685
  Object.assign({}, pk, {
623
- type: `${this.nullable(pk.type)}`,
624
- attributes: onlyAttrs(pk.attributes, this.requestPropAttrs),
686
+ type: this.nullable(pk.type),
687
+ attributes: this.attrsFor("Read", "Prop", pk.attributes),
625
688
  }),
626
689
  idsProp
627
690
  ]
628
691
  : [],
629
- attributes: this.attrsFor("Read", type.attributes),
692
+ attributes: this.attrsFor("Read", "Type", type.attributes),
630
693
  },
631
694
  returnType: {
632
695
  name: "QueryResponse`1",
@@ -653,7 +716,6 @@ export class CSharpAst {
653
716
  let createName = `Create${type.name}`;
654
717
  let createApi = this.result.operations.find(x => x.request.name === createName);
655
718
  if (!createApi) {
656
- const ignorePropsWithAttrs = ['AutoIncrement', 'Reference'];
657
719
  createApi = {
658
720
  method: "POST",
659
721
  actions: ["ANY"],
@@ -666,13 +728,13 @@ export class CSharpAst {
666
728
  genericArgs: [type.name]
667
729
  }],
668
730
  properties: type.properties
669
- .filter(x => !x.attributes?.some(a => ignorePropsWithAttrs.includes(a.name))).map(x => Object.assign({}, x, {
731
+ .filter(x => !x.attributes?.some(a => this.ignoreCreateProps.includes(a.name.toLowerCase()))).map(x => Object.assign({}, x, {
670
732
  type: x.isPrimaryKey
671
733
  ? x.type
672
734
  : `${x.type}`,
673
- attributes: onlyAttrs(x.attributes, this.requestPropAttrs),
735
+ attributes: this.attrsFor("Create", "Prop", x.attributes),
674
736
  })),
675
- attributes: this.attrsFor("Create", type.attributes),
737
+ attributes: this.attrsFor("Create", "Type", type.attributes),
676
738
  },
677
739
  returnType: {
678
740
  name: "IdResponse",
@@ -684,20 +746,29 @@ export class CSharpAst {
684
746
  if (prop.isRequired) {
685
747
  if (!prop.attributes)
686
748
  prop.attributes = [];
749
+ var hasAnyValidateAttrs = prop.attributes.some(x => x.name.toLowerCase().startsWith('validate'));
687
750
  if (prop.type === 'string') {
688
- prop.attributes.push({
689
- name: "ValidateNotEmpty",
690
- });
751
+ if (!hasAnyValidateAttrs) {
752
+ prop.attributes.push({
753
+ name: "ValidateNotEmpty",
754
+ });
755
+ }
691
756
  }
692
757
  else if (this.integerTypes.includes(prop.type)) {
693
- prop.attributes.push({
694
- name: "ValidateGreaterThan",
695
- constructorArgs: [{ name: "value", type: "int", value: "0" }]
696
- });
758
+ if (!hasAnyValidateAttrs) {
759
+ prop.attributes.push({
760
+ name: "ValidateGreaterThan",
761
+ constructorArgs: [{ name: "value", type: "int", value: "0" }]
762
+ });
763
+ }
697
764
  }
698
765
  else if (prop.type === 'List`1' && this.commonValueTypes.includes(prop.genericArgs[0])) {
699
766
  prop.attributes.push(...inputTagAttrs);
700
767
  }
768
+ const emptyValidateAttr = prop.attributes.find(x => x.name.toLowerCase() === 'validate');
769
+ if (emptyValidateAttr && emptyValidateAttr.constructorArgs?.[0]?.value === '') {
770
+ prop.attributes = prop.attributes.filter(x => x !== emptyValidateAttr);
771
+ }
701
772
  }
702
773
  }
703
774
  if (isAuditBase) {
@@ -719,7 +790,6 @@ export class CSharpAst {
719
790
  let updateName = `Update${type.name}`;
720
791
  let updateApi = this.result.operations.find(x => x.request.name === updateName);
721
792
  if (!updateApi) {
722
- const ignoreAttrs = ['AutoIncrement'];
723
793
  updateApi = {
724
794
  method: "PATCH",
725
795
  actions: ["ANY"],
@@ -731,13 +801,13 @@ export class CSharpAst {
731
801
  namespace: "ServiceStack",
732
802
  genericArgs: [type.name]
733
803
  }],
734
- properties: type.properties?.filter(x => !x.attributes?.some(x => x.name === 'References')).map(x => Object.assign({}, x, {
804
+ properties: type.properties?.filter(x => !x.attributes?.some(x => this.ignoreUpdateProps.includes(x.name.toLowerCase()))).map(x => Object.assign({}, x, {
735
805
  type: x.isPrimaryKey
736
806
  ? x.type
737
807
  : `${this.nullable(x.type)}`,
738
- attributes: onlyAttrs(x.attributes?.filter(a => !ignoreAttrs.includes(a.name)), this.requestPropAttrs),
808
+ attributes: this.attrsFor("Update", "Prop", x.attributes),
739
809
  })),
740
- attributes: this.attrsFor("Update", type.attributes),
810
+ attributes: this.attrsFor("Update", "Type", type.attributes),
741
811
  },
742
812
  returnType: {
743
813
  name: "IdResponse",
@@ -787,13 +857,13 @@ export class CSharpAst {
787
857
  properties: pk
788
858
  ? [
789
859
  Object.assign({}, pk, {
790
- type: `${this.nullable(pk.type)}`,
791
- attributes: onlyAttrs(pk.attributes, this.requestPropAttrs),
860
+ type: this.nullable(pk.type),
861
+ attributes: this.attrsFor("Delete", "Prop", pk.attributes),
792
862
  }),
793
863
  idsProp
794
864
  ]
795
865
  : [],
796
- attributes: this.attrsFor("Delete", type.attributes),
866
+ attributes: this.attrsFor("Delete", "Type", type.attributes),
797
867
  },
798
868
  returnsVoid: true,
799
869
  dataModel,
@@ -818,7 +888,14 @@ export class CSharpAst {
818
888
  }
819
889
  filterModelAttributes() {
820
890
  for (const type of this.classes) {
821
- type.attributes = this.attrsFor("Model", type.attributes);
891
+ if (type.attributes?.length) {
892
+ type.attributes = this.attrsFor("Model", "Type", type.attributes);
893
+ }
894
+ type.properties?.forEach(p => {
895
+ if (p.attributes?.length) {
896
+ p.attributes = this.attrsFor("Model", "Prop", p.attributes);
897
+ }
898
+ });
822
899
  }
823
900
  }
824
901
  // Add Icon for BuiltIn UIs and AutoQueryGrid to known type names
@@ -828,8 +905,14 @@ export class CSharpAst {
828
905
  if (icon) {
829
906
  if (!type.attributes)
830
907
  type.attributes = [];
831
- if (type.attributes.some(x => x.name === 'Icon'))
832
- continue;
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
+ }
833
916
  type.attributes.push({
834
917
  name: "Icon",
835
918
  args: [{ name: "Svg", type: "string", value: icon }]
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "okai",
3
3
  "type": "module",
4
- "version": "0.0.23",
4
+ "version": "0.0.24",
5
5
  "bin": "./dist/okai.js",
6
6
  "main": "./dist/index.js",
7
7
  "module": "./dist/index.js",