osury 0.3.0 → 0.5.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/README.md CHANGED
@@ -11,6 +11,7 @@ Generate ReScript types with [Sury](https://github.com/DZakh/sury) schemas from
11
11
  - Automatic deduplication of identical union structures
12
12
  - Generates `module S = Sury` alias (required by sury-ppx)
13
13
  - Generates `Dict.gen.tsx` shim for TypeScript interop
14
+ - Proper JSON `null` support via `@s.nullable option<T>` PPX attribute
14
15
 
15
16
  ## Installation
16
17
 
@@ -23,12 +24,12 @@ npm install -D osury
23
24
  ### CLI
24
25
 
25
26
  ```bash
26
- # Generate to default ./Generated.res + ./Dict.gen.tsx
27
+ # Generate to default ./Generated.res + shims
27
28
  npx osury openapi.json
28
29
 
29
30
  # Generate to specific directory
30
31
  npx osury openapi.json src/API.res
31
- # Creates: src/API.res + src/Dict.gen.tsx
32
+ # Creates: src/API.res, src/Dict.gen.tsx
32
33
 
33
34
  # With explicit output flag
34
35
  npx osury generate openapi.json -o src/Schema.res
@@ -78,7 +79,7 @@ type user = {
78
79
  }
79
80
  ```
80
81
 
81
- Also generates `Dict.gen.tsx`:
82
+ Also generates `Dict.gen.tsx` shim for TypeScript:
82
83
  ```typescript
83
84
  export type t<T> = { [key: string]: T };
84
85
  ```
@@ -111,7 +112,7 @@ For the generated code to compile, your project needs:
111
112
  | `array` | `array<T>` |
112
113
  | `object` | `{ field: T }` |
113
114
  | `$ref` | type reference |
114
- | `anyOf` (nullable) | `option<T>` |
115
+ | `anyOf` (nullable) | `@s.nullable option<T>` |
115
116
  | `anyOf` (union) | variant type |
116
117
  | `oneOf` (tagged) | poly variant |
117
118
  | `additionalProperties` | `Dict.t<T>` |
package/bin/osury.mjs CHANGED
@@ -87,7 +87,7 @@ function generate(inputPath, outputPath) {
87
87
  fs.writeFileSync(dictShimPath, Codegen.generateDictShim());
88
88
 
89
89
  console.log(`Generated ${result._0.length} types to ${outputPath}`);
90
- console.log(`Generated Dict shim to ${dictShimPath}`);
90
+ console.log(`Generated shim: ${dictShimPath}`);
91
91
  } else {
92
92
  console.error("Parse errors:");
93
93
  result._0.forEach((err) => {
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.3.0",
5
+ "version": "0.5.0",
6
6
  "license": "MIT",
7
7
  "bin": {
8
8
  "osury": "./bin/osury.mjs"
@@ -95,6 +95,7 @@ function generateType(schema) {
95
95
  } else {
96
96
  switch (schema._tag) {
97
97
  case "Optional" :
98
+ case "Nullable" :
98
99
  return `option<` + generateType(schema._0) + `>`;
99
100
  case "Object" :
100
101
  return generateRecord(schema._0);
@@ -116,10 +117,23 @@ function generateType(schema) {
116
117
  }
117
118
 
118
119
  function isOptionalType(schema) {
120
+ if (typeof schema !== "object") {
121
+ return false;
122
+ }
123
+ switch (schema._tag) {
124
+ case "Optional" :
125
+ case "Nullable" :
126
+ return true;
127
+ default:
128
+ return false;
129
+ }
130
+ }
131
+
132
+ function isNullableType(schema) {
119
133
  if (typeof schema !== "object") {
120
134
  return false;
121
135
  } else {
122
- return schema._tag === "Optional";
136
+ return schema._tag === "Nullable";
123
137
  }
124
138
  }
125
139
 
@@ -130,11 +144,10 @@ function generateRecord(fields) {
130
144
  let fieldStrs = fields.map(field => {
131
145
  let typeStr = generateType(field.type);
132
146
  let optionalType = field.required || isOptionalType(field.type) ? typeStr : `option<` + typeStr + `>`;
133
- if (reservedKeywords.includes(field.name)) {
134
- return `@as("` + field.name + `") ` + field.name + `_: ` + optionalType;
135
- } else {
136
- return field.name + `: ` + optionalType;
137
- }
147
+ let nullableAttr = isNullableType(field.type) ? "@s.nullable " : "";
148
+ let asAttr = reservedKeywords.includes(field.name) ? `@as("` + field.name + `") ` : "";
149
+ let fieldName = reservedKeywords.includes(field.name) ? field.name + `_` : field.name;
150
+ return nullableAttr + asAttr + fieldName + `: ` + optionalType;
138
151
  });
139
152
  return `{\n ` + fieldStrs.join(",\n ") + `\n}`;
140
153
  }
@@ -174,6 +187,8 @@ function getTagForType(t) {
174
187
  switch (t._tag) {
175
188
  case "Optional" :
176
189
  return `Option` + getTagForType(t._0);
190
+ case "Nullable" :
191
+ return `Null` + getTagForType(t._0);
177
192
  case "Object" :
178
193
  return "Object";
179
194
  case "Array" :
@@ -213,6 +228,7 @@ function hasUnion(_schema) {
213
228
  case "PolyVariant" :
214
229
  return schema._0.some(c => hasUnion(c.payload));
215
230
  case "Optional" :
231
+ case "Nullable" :
216
232
  case "Array" :
217
233
  case "Dict" :
218
234
  _schema = schema._0;
@@ -271,6 +287,7 @@ function extractUnionsFromType(_schema) {
271
287
  case "Object" :
272
288
  return schema._0.flatMap(field => extractUnionsFromType(field.type));
273
289
  case "Optional" :
290
+ case "Nullable" :
274
291
  case "Array" :
275
292
  case "Dict" :
276
293
  _schema = schema._0;
@@ -307,6 +324,11 @@ function replaceUnionInType(schema) {
307
324
  _tag: "Optional",
308
325
  _0: replaceUnionInType(schema._0)
309
326
  };
327
+ case "Nullable" :
328
+ return {
329
+ _tag: "Nullable",
330
+ _0: replaceUnionInType(schema._0)
331
+ };
310
332
  case "Object" :
311
333
  let newFields = schema._0.map(field => {
312
334
  let newType = replaceUnionInType(field.type);
@@ -377,6 +399,7 @@ function getDependencies(_schema) {
377
399
  case "PolyVariant" :
378
400
  return schema._0.flatMap(c => getDependencies(c.payload));
379
401
  case "Optional" :
402
+ case "Nullable" :
380
403
  case "Array" :
381
404
  case "Dict" :
382
405
  _schema = schema._0;
@@ -563,6 +586,7 @@ export {
563
586
  lcFirst,
564
587
  generateType,
565
588
  isOptionalType,
589
+ isNullableType,
566
590
  generateRecord,
567
591
  generatePolyVariant,
568
592
  ucFirst,
@@ -18,6 +18,7 @@ export type schemaType =
18
18
  | "Boolean"
19
19
  | "Null"
20
20
  | { _tag: "Optional"; _0: schemaType }
21
+ | { _tag: "Nullable"; _0: schemaType }
21
22
  | { _tag: "Object"; _0: field[] }
22
23
  | { _tag: "Array"; _0: schemaType }
23
24
  | { _tag: "Ref"; _0: string }
@@ -216,7 +216,7 @@ function parseAnyOf(items) {
216
216
  return {
217
217
  TAG: "Ok",
218
218
  _0: {
219
- _tag: "Optional",
219
+ _tag: "Nullable",
220
220
  _0: innerType._0
221
221
  }
222
222
  };
@@ -294,7 +294,7 @@ function parseAnyOf(items) {
294
294
  return {
295
295
  TAG: "Ok",
296
296
  _0: {
297
- _tag: "Optional",
297
+ _tag: "Nullable",
298
298
  _0: {
299
299
  _tag: "Union",
300
300
  _0: types$1