osury 0.22.0 → 0.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "osury",
3
3
  "type": "module",
4
4
  "description": "Generate ReScript types with Sury schemas from OpenAPI specifications",
5
- "version": "0.22.0",
5
+ "version": "0.24.0",
6
6
  "license": "MIT",
7
7
  "bin": {
8
8
  "osury": "bin/osury.mjs"
@@ -3,6 +3,18 @@
3
3
  import * as Core__Array from "@rescript/core/src/Core__Array.res.mjs";
4
4
  import * as Core__Option from "@rescript/core/src/Core__Option.res.mjs";
5
5
 
6
+ function quoteTag(tag) {
7
+ let needsQuoting = tag.split("").some(c => {
8
+ let code = c.charCodeAt(0);
9
+ return !(code >= 97.0 && code <= 122.0 || code >= 65.0 && code <= 90.0 || code >= 48.0 && code <= 57.0 || code === 95.0);
10
+ });
11
+ if (needsQuoting) {
12
+ return `"` + tag + `"`;
13
+ } else {
14
+ return tag;
15
+ }
16
+ }
17
+
6
18
  function printPrimitive(p) {
7
19
  switch (p) {
8
20
  case "PString" :
@@ -36,7 +48,7 @@ function printType(t) {
36
48
  case "Named" :
37
49
  return t._0;
38
50
  case "Enum" :
39
- let variants = t._0.map(v => `#` + v).join(" | ");
51
+ let variants = t._0.map(v => `#` + quoteTag(v)).join(" | ");
40
52
  return `[` + variants + `]`;
41
53
  case "InlineRecord" :
42
54
  return printRecord(t._0);
@@ -79,7 +91,7 @@ function printVariantCase(c) {
79
91
 
80
92
  function printVariantCases(cases) {
81
93
  let caseStrs = cases.map(printVariantCase);
82
- return `[` + caseStrs.map(c => `#` + c).join(" | ") + `]`;
94
+ return `[` + caseStrs.map(c => `#` + quoteTag(c)).join(" | ") + `]`;
83
95
  }
84
96
 
85
97
  function printAnnotation(ann) {
@@ -130,6 +142,7 @@ function print(module_) {
130
142
  }
131
143
 
132
144
  export {
145
+ quoteTag,
133
146
  printPrimitive,
134
147
  printType,
135
148
  printField,
@@ -196,7 +196,7 @@ function hasUnknown(_schema) {
196
196
  }
197
197
 
198
198
  function isPrimitiveOnlyUnion(types) {
199
- return types.every(t => {
199
+ let allPrimitive = types.every(t => {
200
200
  if (typeof t === "object") {
201
201
  return false;
202
202
  }
@@ -210,6 +210,12 @@ function isPrimitiveOnlyUnion(types) {
210
210
  return false;
211
211
  }
212
212
  });
213
+ if (!allPrimitive) {
214
+ return false;
215
+ }
216
+ let hasFloat = types.some(t => t === "Number");
217
+ let hasInt = types.some(t => t === "Integer");
218
+ return !(hasFloat && hasInt);
213
219
  }
214
220
 
215
221
  export {
@@ -95,102 +95,161 @@ function parseSchema(json) {
95
95
  function parsePrimitiveType(dict) {
96
96
  let match = dict["type"];
97
97
  if (match !== undefined) {
98
- if (typeof match === "string") {
99
- switch (match) {
100
- case "array" :
101
- return parseArrayType(dict);
102
- case "boolean" :
103
- return {
104
- TAG: "Ok",
105
- _0: "Boolean"
106
- };
107
- case "integer" :
108
- return {
109
- TAG: "Ok",
110
- _0: "Integer"
111
- };
112
- case "null" :
113
- return {
114
- TAG: "Ok",
115
- _0: "Null"
116
- };
117
- case "number" :
118
- return {
119
- TAG: "Ok",
120
- _0: "Number"
121
- };
122
- case "object" :
123
- return parseObjectType(dict);
124
- case "string" :
125
- let match$1 = dict["const"];
126
- let exit = 0;
127
- if (match$1 !== undefined) {
128
- if (typeof match$1 === "string") {
129
- return {
130
- TAG: "Ok",
131
- _0: {
132
- _tag: "Enum",
133
- _0: [match$1]
134
- }
135
- };
136
- }
137
- exit = 2;
138
- } else {
139
- exit = 2;
98
+ if (Array.isArray(match)) {
99
+ let typeStrings = Core__Array.filterMap(match, t => {
100
+ if (typeof t === "string") {
101
+ return t;
102
+ }
103
+ });
104
+ let hasNull = typeStrings.includes("null");
105
+ let nonNullTypes = typeStrings.filter(t => t !== "null");
106
+ if (!hasNull) {
107
+ return {
108
+ TAG: "Error",
109
+ _0: [Errors.makeError({
110
+ TAG: "UnsupportedFeature",
111
+ _0: "type array without null"
112
+ }, undefined, undefined, undefined)]
113
+ };
114
+ }
115
+ if (nonNullTypes.length !== 1) {
116
+ return {
117
+ TAG: "Error",
118
+ _0: [Errors.makeError({
119
+ TAG: "InvalidJson",
120
+ _0: "type array must have exactly one non-null type"
121
+ }, undefined, undefined, undefined)]
122
+ };
123
+ }
124
+ let nonNullType = nonNullTypes[0];
125
+ let newDict = Object.fromEntries(Object.entries(dict).map(param => {
126
+ let k = param[0];
127
+ if (k === "type") {
128
+ return [
129
+ k,
130
+ nonNullType
131
+ ];
132
+ } else {
133
+ return [
134
+ k,
135
+ param[1]
136
+ ];
137
+ }
138
+ }));
139
+ let inner = parsePrimitiveType(newDict);
140
+ if (inner.TAG === "Ok") {
141
+ return {
142
+ TAG: "Ok",
143
+ _0: {
144
+ _tag: "Nullable",
145
+ _0: inner._0
140
146
  }
141
- if (exit === 2) {
142
- let match$2 = dict["enum"];
143
- if (match$2 === undefined) {
144
- return {
145
- TAG: "Ok",
146
- _0: "String"
147
- };
148
- }
149
- let exit$1 = 0;
150
- if (Array.isArray(match$2)) {
151
- let values = parseEnumValues(match$2);
152
- if (values !== undefined) {
147
+ };
148
+ } else {
149
+ return {
150
+ TAG: "Error",
151
+ _0: inner._0
152
+ };
153
+ }
154
+ }
155
+ switch (typeof match) {
156
+ case "string" :
157
+ switch (match) {
158
+ case "array" :
159
+ return parseArrayType(dict);
160
+ case "boolean" :
161
+ return {
162
+ TAG: "Ok",
163
+ _0: "Boolean"
164
+ };
165
+ case "integer" :
166
+ return {
167
+ TAG: "Ok",
168
+ _0: "Integer"
169
+ };
170
+ case "null" :
171
+ return {
172
+ TAG: "Ok",
173
+ _0: "Null"
174
+ };
175
+ case "number" :
176
+ return {
177
+ TAG: "Ok",
178
+ _0: "Number"
179
+ };
180
+ case "object" :
181
+ return parseObjectType(dict);
182
+ case "string" :
183
+ let match$1 = dict["const"];
184
+ let exit = 0;
185
+ if (match$1 !== undefined) {
186
+ if (typeof match$1 === "string") {
153
187
  return {
154
188
  TAG: "Ok",
155
189
  _0: {
156
190
  _tag: "Enum",
157
- _0: values
191
+ _0: [match$1]
158
192
  }
159
193
  };
160
- } else {
194
+ }
195
+ exit = 2;
196
+ } else {
197
+ exit = 2;
198
+ }
199
+ if (exit === 2) {
200
+ let match$2 = dict["enum"];
201
+ if (match$2 === undefined) {
202
+ return {
203
+ TAG: "Ok",
204
+ _0: "String"
205
+ };
206
+ }
207
+ let exit$1 = 0;
208
+ if (Array.isArray(match$2)) {
209
+ let values = parseEnumValues(match$2);
210
+ if (values !== undefined) {
211
+ return {
212
+ TAG: "Ok",
213
+ _0: {
214
+ _tag: "Enum",
215
+ _0: values
216
+ }
217
+ };
218
+ } else {
219
+ return {
220
+ TAG: "Error",
221
+ _0: [Errors.makeError({
222
+ TAG: "InvalidJson",
223
+ _0: "enum values must be strings"
224
+ }, undefined, undefined, undefined)]
225
+ };
226
+ }
227
+ }
228
+ exit$1 = 3;
229
+ if (exit$1 === 3) {
161
230
  return {
162
231
  TAG: "Error",
163
232
  _0: [Errors.makeError({
164
233
  TAG: "InvalidJson",
165
- _0: "enum values must be strings"
234
+ _0: "enum must be an array"
166
235
  }, undefined, undefined, undefined)]
167
236
  };
168
237
  }
169
238
  }
170
- exit$1 = 3;
171
- if (exit$1 === 3) {
172
- return {
173
- TAG: "Error",
174
- _0: [Errors.makeError({
175
- TAG: "InvalidJson",
176
- _0: "enum must be an array"
177
- }, undefined, undefined, undefined)]
178
- };
179
- }
180
- }
181
- break;
182
- default:
183
- return {
184
- TAG: "Error",
185
- _0: [Errors.unknownType(match, undefined, undefined, undefined)]
186
- };
187
- }
239
+ break;
240
+ default:
241
+ return {
242
+ TAG: "Error",
243
+ _0: [Errors.unknownType(match, undefined, undefined, undefined)]
244
+ };
245
+ }
246
+ break;
188
247
  }
189
248
  return {
190
249
  TAG: "Error",
191
250
  _0: [Errors.makeError({
192
251
  TAG: "InvalidJson",
193
- _0: "type must be a string"
252
+ _0: "type must be a string or array"
194
253
  }, undefined, undefined, undefined)]
195
254
  };
196
255
  }
@@ -639,17 +698,48 @@ function parseOneOf(items, discriminatorPropertyNameOpt) {
639
698
  };
640
699
  }
641
700
 
701
+ function applyNullable(dict, result) {
702
+ let match = dict["nullable"];
703
+ if (match === undefined) {
704
+ return result;
705
+ }
706
+ if (typeof match !== "boolean") {
707
+ return result;
708
+ }
709
+ if (!match) {
710
+ return result;
711
+ }
712
+ if (result.TAG !== "Ok") {
713
+ return result;
714
+ }
715
+ let t = result._0;
716
+ if (typeof t !== "object" || t._tag !== "Nullable") {
717
+ return {
718
+ TAG: "Ok",
719
+ _0: {
720
+ _tag: "Nullable",
721
+ _0: t
722
+ }
723
+ };
724
+ } else {
725
+ return {
726
+ TAG: "Ok",
727
+ _0: t
728
+ };
729
+ }
730
+ }
731
+
642
732
  function parseObject(dict) {
643
733
  let match = dict["$ref"];
644
734
  if (match !== undefined) {
645
735
  if (typeof match === "string") {
646
- return {
736
+ return applyNullable(dict, {
647
737
  TAG: "Ok",
648
738
  _0: {
649
739
  _tag: "Ref",
650
740
  _0: extractRefName(match)
651
741
  }
652
- };
742
+ });
653
743
  }
654
744
  return {
655
745
  TAG: "Error",
@@ -662,8 +752,69 @@ function parseObject(dict) {
662
752
  let match$1 = dict["oneOf"];
663
753
  if (match$1 !== undefined) {
664
754
  if (Array.isArray(match$1)) {
665
- let discriminatorPropName = extractDiscriminatorPropertyName(dict);
666
- return parseOneOf(match$1, Primitive_option.some(discriminatorPropName));
755
+ let hasNull = match$1.some(isNullType);
756
+ let nonNullItems = match$1.filter(item => !isNullType(item));
757
+ if (hasNull && nonNullItems.length === 1) {
758
+ let match$2 = nonNullItems[0];
759
+ if (match$2 === undefined) {
760
+ return {
761
+ TAG: "Error",
762
+ _0: [Errors.makeError({
763
+ TAG: "InvalidJson",
764
+ _0: "oneOf with only null types"
765
+ }, undefined, undefined, undefined)]
766
+ };
767
+ }
768
+ let exit = 0;
769
+ if (typeof match$2 === "object" && match$2 !== null && !Array.isArray(match$2)) {
770
+ let innerType = parseObject(match$2);
771
+ if (innerType.TAG === "Ok") {
772
+ return {
773
+ TAG: "Ok",
774
+ _0: {
775
+ _tag: "Nullable",
776
+ _0: innerType._0
777
+ }
778
+ };
779
+ } else {
780
+ return {
781
+ TAG: "Error",
782
+ _0: innerType._0
783
+ };
784
+ }
785
+ }
786
+ exit = 2;
787
+ if (exit === 2) {
788
+ return {
789
+ TAG: "Error",
790
+ _0: [Errors.makeError({
791
+ TAG: "InvalidJson",
792
+ _0: "oneOf item must be object"
793
+ }, undefined, undefined, undefined)]
794
+ };
795
+ }
796
+ } else {
797
+ if (hasNull && nonNullItems.length >= 2) {
798
+ let discriminatorPropName = extractDiscriminatorPropertyName(dict);
799
+ let inner = parseOneOf(nonNullItems, Primitive_option.some(discriminatorPropName));
800
+ if (inner.TAG === "Ok") {
801
+ return {
802
+ TAG: "Ok",
803
+ _0: {
804
+ _tag: "Nullable",
805
+ _0: inner._0
806
+ }
807
+ };
808
+ } else {
809
+ return {
810
+ TAG: "Error",
811
+ _0: inner._0
812
+ };
813
+ }
814
+ }
815
+ let discriminatorPropName$1 = extractDiscriminatorPropertyName(dict);
816
+ return parseOneOf(match$1, Primitive_option.some(discriminatorPropName$1));
817
+ }
667
818
  }
668
819
  return {
669
820
  TAG: "Error",
@@ -673,10 +824,10 @@ function parseObject(dict) {
673
824
  }, undefined, undefined, undefined)]
674
825
  };
675
826
  }
676
- let match$2 = dict["allOf"];
677
- if (match$2 !== undefined) {
678
- if (Array.isArray(match$2)) {
679
- return parseAllOf(match$2);
827
+ let match$3 = dict["allOf"];
828
+ if (match$3 !== undefined) {
829
+ if (Array.isArray(match$3)) {
830
+ return parseAllOf(match$3);
680
831
  }
681
832
  return {
682
833
  TAG: "Error",
@@ -686,12 +837,12 @@ function parseObject(dict) {
686
837
  }, undefined, undefined, undefined)]
687
838
  };
688
839
  }
689
- let match$3 = dict["anyOf"];
690
- if (match$3 === undefined) {
691
- return parsePrimitiveType(dict);
840
+ let match$4 = dict["anyOf"];
841
+ if (match$4 === undefined) {
842
+ return applyNullable(dict, parsePrimitiveType(dict));
692
843
  }
693
- if (Array.isArray(match$3)) {
694
- return parseAnyOf(match$3);
844
+ if (Array.isArray(match$4)) {
845
+ return parseAnyOf(match$4);
695
846
  }
696
847
  return {
697
848
  TAG: "Error",
@@ -719,6 +870,7 @@ export {
719
870
  parseObjectType,
720
871
  parseAllOf,
721
872
  parseOneOf,
873
+ applyNullable,
722
874
  parseObject,
723
875
  parse,
724
876
  }