@powerlines/schema 0.11.28 → 0.11.38

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.
Files changed (82) hide show
  1. package/dist/bundle.cjs +34 -20
  2. package/dist/bundle.d.cts +3 -3
  3. package/dist/bundle.d.cts.map +1 -1
  4. package/dist/bundle.d.mts +3 -3
  5. package/dist/bundle.d.mts.map +1 -1
  6. package/dist/bundle.mjs +35 -21
  7. package/dist/bundle.mjs.map +1 -1
  8. package/dist/codegen.cjs +55 -8
  9. package/dist/codegen.d.cts +12 -6
  10. package/dist/codegen.d.cts.map +1 -1
  11. package/dist/codegen.d.mts +12 -6
  12. package/dist/codegen.d.mts.map +1 -1
  13. package/dist/codegen.mjs +52 -8
  14. package/dist/codegen.mjs.map +1 -1
  15. package/dist/constants.cjs +42 -0
  16. package/dist/constants.d.cts +15 -0
  17. package/dist/constants.d.cts.map +1 -0
  18. package/dist/constants.d.mts +15 -0
  19. package/dist/constants.d.mts.map +1 -0
  20. package/dist/constants.mjs +39 -0
  21. package/dist/constants.mjs.map +1 -0
  22. package/dist/extract.cjs +144 -95
  23. package/dist/extract.d.cts +34 -69
  24. package/dist/extract.d.cts.map +1 -1
  25. package/dist/extract.d.mts +34 -69
  26. package/dist/extract.d.mts.map +1 -1
  27. package/dist/extract.mjs +144 -95
  28. package/dist/extract.mjs.map +1 -1
  29. package/dist/helpers.cjs +87 -0
  30. package/dist/helpers.d.cts +48 -0
  31. package/dist/helpers.d.cts.map +1 -0
  32. package/dist/helpers.d.mts +48 -0
  33. package/dist/helpers.d.mts.map +1 -0
  34. package/dist/helpers.mjs +84 -0
  35. package/dist/helpers.mjs.map +1 -0
  36. package/dist/index.cjs +29 -5
  37. package/dist/index.d.cts +8 -5
  38. package/dist/index.d.mts +8 -5
  39. package/dist/index.mjs +7 -4
  40. package/dist/metadata.cjs +80 -0
  41. package/dist/metadata.d.cts +52 -0
  42. package/dist/metadata.d.cts.map +1 -0
  43. package/dist/metadata.d.mts +52 -0
  44. package/dist/metadata.d.mts.map +1 -0
  45. package/dist/metadata.mjs +76 -0
  46. package/dist/metadata.mjs.map +1 -0
  47. package/dist/persistence.cjs +75 -0
  48. package/dist/persistence.d.cts +47 -0
  49. package/dist/persistence.d.cts.map +1 -0
  50. package/dist/persistence.d.mts +47 -0
  51. package/dist/persistence.d.mts.map +1 -0
  52. package/dist/persistence.mjs +71 -0
  53. package/dist/persistence.mjs.map +1 -0
  54. package/dist/reflection.cjs +292 -299
  55. package/dist/reflection.d.cts +3 -16
  56. package/dist/reflection.d.cts.map +1 -1
  57. package/dist/reflection.d.mts +3 -16
  58. package/dist/reflection.d.mts.map +1 -1
  59. package/dist/reflection.mjs +291 -299
  60. package/dist/reflection.mjs.map +1 -1
  61. package/dist/resolve.cjs +7 -7
  62. package/dist/resolve.mjs +7 -7
  63. package/dist/resolve.mjs.map +1 -1
  64. package/dist/type-checks.cjs +126 -25
  65. package/dist/type-checks.d.cts +45 -23
  66. package/dist/type-checks.d.cts.map +1 -1
  67. package/dist/type-checks.d.mts +45 -23
  68. package/dist/type-checks.d.mts.map +1 -1
  69. package/dist/type-checks.mjs +125 -25
  70. package/dist/type-checks.mjs.map +1 -1
  71. package/dist/types.d.cts +237 -95
  72. package/dist/types.d.cts.map +1 -1
  73. package/dist/types.d.mts +237 -95
  74. package/dist/types.d.mts.map +1 -1
  75. package/package.json +24 -8
  76. package/dist/jtd.cjs +0 -385
  77. package/dist/jtd.d.cts +0 -15
  78. package/dist/jtd.d.cts.map +0 -1
  79. package/dist/jtd.d.mts +0 -15
  80. package/dist/jtd.d.mts.map +0 -1
  81. package/dist/jtd.mjs +0 -384
  82. package/dist/jtd.mjs.map +0 -1
@@ -1,238 +1,262 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
2
  const require_runtime = require('./_virtual/_rolldown/runtime.cjs');
3
- let _powerlines_deepkit_vendor_type = require("@powerlines/deepkit/vendor/type");
3
+ const require_type_checks = require('./type-checks.cjs');
4
+ let defu = require("defu");
5
+ defu = require_runtime.__toESM(defu, 1);
4
6
  let _stryke_type_checks = require("@stryke/type-checks");
7
+ let _powerlines_deepkit_vendor_type = require("@powerlines/deepkit/vendor/type");
5
8
 
6
9
  //#region src/reflection.ts
7
10
  /**
8
- * Maps a Deepkit numeric `brand` to the JTD numeric `type` keyword that best preserves the underlying width and signedness.
11
+ * Maps a Deepkit numeric `brand` to JSON Schema `type` and `format`.
9
12
  *
10
- * @param brand - The Deepkit `TypeNumberBrand` of a numeric reflection, or `undefined` when no brand is set.
11
- * @returns The JTD numeric `type` keyword to use.
13
+ * @remarks
14
+ * This function takes a `TypeNumberBrand` (which represents specific numeric types in Deepkit, such as `integer`, `float`, `int8`, etc.) and returns a corresponding JSON Schema fragment that includes the appropriate `type`, `format`, and any relevant keywords (like `multipleOf` for integers). If the brand is not recognized, it defaults to a generic JSON Schema for numbers.
15
+ *
16
+ * @param brand - The Deepkit numeric brand to convert.
17
+ * @return A JSON Schema fragment representing the numeric type corresponding to the provided brand.
12
18
  */
13
- function numberBrandToJtdType(brand) {
19
+ function numberBrandToJsonSchema(brand) {
14
20
  switch (brand) {
15
- case _powerlines_deepkit_vendor_type.TypeNumberBrand.integer: return "int32";
16
- case _powerlines_deepkit_vendor_type.TypeNumberBrand.int8: return "int8";
17
- case _powerlines_deepkit_vendor_type.TypeNumberBrand.uint8: return "uint8";
18
- case _powerlines_deepkit_vendor_type.TypeNumberBrand.int16: return "int16";
19
- case _powerlines_deepkit_vendor_type.TypeNumberBrand.uint16: return "uint16";
20
- case _powerlines_deepkit_vendor_type.TypeNumberBrand.int32: return "int32";
21
- case _powerlines_deepkit_vendor_type.TypeNumberBrand.uint32: return "uint32";
21
+ case _powerlines_deepkit_vendor_type.TypeNumberBrand.integer: return {
22
+ type: "integer",
23
+ format: "int32",
24
+ multipleOf: 1
25
+ };
26
+ case _powerlines_deepkit_vendor_type.TypeNumberBrand.int8: return {
27
+ type: "integer",
28
+ format: "int8",
29
+ multipleOf: 1
30
+ };
31
+ case _powerlines_deepkit_vendor_type.TypeNumberBrand.uint8: return {
32
+ type: "integer",
33
+ format: "uint8",
34
+ multipleOf: 1
35
+ };
36
+ case _powerlines_deepkit_vendor_type.TypeNumberBrand.int16: return {
37
+ type: "integer",
38
+ format: "int16",
39
+ multipleOf: 1
40
+ };
41
+ case _powerlines_deepkit_vendor_type.TypeNumberBrand.uint16: return {
42
+ type: "integer",
43
+ format: "uint16",
44
+ multipleOf: 1
45
+ };
46
+ case _powerlines_deepkit_vendor_type.TypeNumberBrand.int32: return {
47
+ type: "integer",
48
+ format: "int32",
49
+ multipleOf: 1
50
+ };
51
+ case _powerlines_deepkit_vendor_type.TypeNumberBrand.uint32: return {
52
+ type: "integer",
53
+ format: "uint32",
54
+ multipleOf: 1
55
+ };
22
56
  case _powerlines_deepkit_vendor_type.TypeNumberBrand.float:
23
- case _powerlines_deepkit_vendor_type.TypeNumberBrand.float32: return "float32";
24
- case _powerlines_deepkit_vendor_type.TypeNumberBrand.float64: return "float64";
57
+ case _powerlines_deepkit_vendor_type.TypeNumberBrand.float32: return {
58
+ type: "number",
59
+ format: "float"
60
+ };
61
+ case _powerlines_deepkit_vendor_type.TypeNumberBrand.float64: return {
62
+ type: "number",
63
+ format: "double"
64
+ };
25
65
  case void 0:
26
- default: return "float64";
66
+ default: return { type: "number" };
27
67
  }
28
68
  }
69
+ function withReflectionTags(reflection, schema) {
70
+ if (!(0, _stryke_type_checks.isSetObject)(reflection?.tags)) return schema;
71
+ const tags = reflection.tags;
72
+ if ((0, _stryke_type_checks.isSetString)(tags.title)) schema.title = tags.title;
73
+ if ((0, _stryke_type_checks.isSetArray)(tags.alias)) schema.alias = tags.alias;
74
+ if (!(0, _stryke_type_checks.isUndefined)(tags.hidden)) schema.hidden = tags.hidden;
75
+ if (!(0, _stryke_type_checks.isUndefined)(tags.ignore)) schema.ignore = tags.ignore;
76
+ if (!(0, _stryke_type_checks.isUndefined)(tags.internal)) schema.internal = tags.internal;
77
+ if (!(0, _stryke_type_checks.isUndefined)(tags.runtime)) schema.runtime = tags.runtime;
78
+ if (!(0, _stryke_type_checks.isUndefined)(tags.readonly)) schema.readOnly = tags.readonly;
79
+ return schema;
80
+ }
81
+ function withNullable(schema, nullable) {
82
+ if (!nullable) return schema;
83
+ const types = Array.isArray(schema.type) ? [...schema.type] : schema.type ? [schema.type] : [];
84
+ if (!types.includes("null")) types.push("null");
85
+ return {
86
+ ...schema,
87
+ type: types.length === 1 ? types[0] : types
88
+ };
89
+ }
29
90
  /**
30
- * Converts a Deepkit type reflection into a JSON Type Definition (RFC 8927) form suitable for AJV's JTD validator.
31
- *
32
- * @remarks
33
- * Some TypeScript constructs have no direct JTD equivalent and are handled with the closest available form:
34
- *
35
- * - `null` and `undefined` become the empty JTD form with `nullable: true`.
36
- * - Unions of primitives that cannot be expressed as a JTD enum collapse to the empty form (which validates any value).
37
- * - String/number/bigint literal unions are emitted as a JTD enum (non-string members are stringified, as JTD requires string enum members).
38
- * - Tuples are emitted as a JTD elements form whose element schema is the single tuple member type, or the empty schema for mixed tuples.
39
- * - `Date` is emitted as `{ type: "timestamp" }`.
40
- * - Discriminated unions of object literals (a shared string-literal tag property) are emitted as a JTD discriminator form.
41
- *
42
- * @param reflection - The Deepkit type reflection to convert.
43
- * @returns The corresponding JTD form, or `undefined` if the type cannot be represented.
91
+ * Converts a Deepkit type reflection into a JSON Schema (draft-07) fragment.
44
92
  */
45
93
  function reflectionToJsonSchema(reflection) {
46
- return reflectionToJtd(reflection);
94
+ return reflectionToJsonSchemaInner(reflection);
47
95
  }
48
- /**
49
- * Internal worker that performs the recursive Deepkit reflection → JTD conversion.
50
- *
51
- * @param reflection - The Deepkit type reflection to convert.
52
- * @returns The corresponding JTD form, or `undefined` if the type cannot be represented.
53
- */
54
- function reflectionToJtd(reflection) {
55
- const schema = {};
56
- if ((0, _stryke_type_checks.isSetObject)(reflection?.tags)) {
57
- const tags = reflection.tags;
58
- schema.metadata = schema.metadata ?? {};
59
- if (tags.readonly === true) schema.metadata.isReadonly = true;
60
- if (tags.ignore === true) schema.metadata.isIgnored = true;
61
- if (tags.internal === true) schema.metadata.isInternal = true;
62
- if (tags.runtime === true) schema.metadata.isRuntime = true;
63
- if (tags.hidden === true) schema.metadata.isHidden = true;
64
- if ((0, _stryke_type_checks.isSetArray)(tags.alias)) schema.metadata.alias = tags.alias;
65
- if ((0, _stryke_type_checks.isSetString)(tags.title)) schema.metadata.title = tags.title;
66
- }
96
+ function reflectionToJsonSchemaInner(reflection) {
67
97
  switch (reflection.kind) {
68
98
  case _powerlines_deepkit_vendor_type.ReflectionKind.any:
69
99
  case _powerlines_deepkit_vendor_type.ReflectionKind.unknown:
70
100
  case _powerlines_deepkit_vendor_type.ReflectionKind.void:
71
- case _powerlines_deepkit_vendor_type.ReflectionKind.object: return {};
101
+ case _powerlines_deepkit_vendor_type.ReflectionKind.object: return withReflectionTags(reflection, { name: reflection.typeName });
72
102
  case _powerlines_deepkit_vendor_type.ReflectionKind.never: return;
73
103
  case _powerlines_deepkit_vendor_type.ReflectionKind.undefined:
74
- case _powerlines_deepkit_vendor_type.ReflectionKind.null: return { nullable: true };
75
- case _powerlines_deepkit_vendor_type.ReflectionKind.string: return {
76
- ...schema,
77
- type: "string"
78
- };
79
- case _powerlines_deepkit_vendor_type.ReflectionKind.boolean: return {
80
- ...schema,
81
- type: "boolean"
82
- };
83
- case _powerlines_deepkit_vendor_type.ReflectionKind.number: return {
84
- ...schema,
85
- type: numberBrandToJtdType(reflection.brand)
86
- };
87
- case _powerlines_deepkit_vendor_type.ReflectionKind.bigint: return {
88
- ...schema,
89
- type: "float64"
90
- };
91
- case _powerlines_deepkit_vendor_type.ReflectionKind.regexp: return {
92
- ...schema,
93
- type: "string"
94
- };
104
+ case _powerlines_deepkit_vendor_type.ReflectionKind.null: return withReflectionTags(reflection, {
105
+ type: "null",
106
+ name: reflection.typeName,
107
+ nullable: true
108
+ });
109
+ case _powerlines_deepkit_vendor_type.ReflectionKind.string: return withReflectionTags(reflection, {
110
+ type: "string",
111
+ name: reflection.typeName
112
+ });
113
+ case _powerlines_deepkit_vendor_type.ReflectionKind.boolean: return withReflectionTags(reflection, {
114
+ type: "boolean",
115
+ name: reflection.typeName
116
+ });
117
+ case _powerlines_deepkit_vendor_type.ReflectionKind.number: return withReflectionTags(reflection, numberBrandToJsonSchema(reflection.brand));
118
+ case _powerlines_deepkit_vendor_type.ReflectionKind.bigint: return withReflectionTags(reflection, {
119
+ type: "integer",
120
+ name: reflection.typeName,
121
+ format: "int64",
122
+ multipleOf: 1
123
+ });
124
+ case _powerlines_deepkit_vendor_type.ReflectionKind.regexp: return withReflectionTags(reflection, {
125
+ type: "string",
126
+ name: reflection.typeName,
127
+ format: "regex",
128
+ contentMediaType: "text/regex"
129
+ });
95
130
  case _powerlines_deepkit_vendor_type.ReflectionKind.literal: {
96
131
  const { literal } = reflection;
97
- if (typeof literal === "string") return {
98
- ...schema,
99
- enum: [literal]
100
- };
101
- if (typeof literal === "number" || typeof literal === "bigint") return {
102
- ...schema,
103
- enum: [String(literal)]
104
- };
105
- if (typeof literal === "boolean") return {
106
- ...schema,
107
- type: "boolean"
108
- };
109
- if (literal instanceof RegExp) return {
110
- ...schema,
111
- type: "string"
112
- };
113
- return schema;
132
+ if (typeof literal === "string" || typeof literal === "number" || typeof literal === "boolean") return withReflectionTags(reflection, {
133
+ type: typeof literal,
134
+ name: reflection.typeName,
135
+ const: literal
136
+ });
137
+ if (typeof literal === "bigint") return withReflectionTags(reflection, {
138
+ type: "integer",
139
+ name: reflection.typeName,
140
+ format: "int64",
141
+ multipleOf: 1,
142
+ const: String(literal)
143
+ });
144
+ if (literal instanceof RegExp) return withReflectionTags(reflection, {
145
+ type: "string",
146
+ name: reflection.typeName,
147
+ format: "regex",
148
+ const: literal.source
149
+ });
150
+ return withReflectionTags(reflection, { name: reflection.typeName });
114
151
  }
115
- case _powerlines_deepkit_vendor_type.ReflectionKind.templateLiteral: return {
116
- ...schema,
117
- type: "string"
118
- };
152
+ case _powerlines_deepkit_vendor_type.ReflectionKind.templateLiteral: return withReflectionTags(reflection, { type: "string" });
119
153
  case _powerlines_deepkit_vendor_type.ReflectionKind.enum: {
120
- const values = reflection.values.filter((value) => typeof value === "string" || typeof value === "number").map((value) => String(value));
121
- const unique = Array.from(new Set(values));
122
- if (unique.length === 0) return schema;
123
- return {
124
- ...schema,
125
- enum: unique
126
- };
154
+ const values = reflection.values.filter((value) => typeof value === "string" || typeof value === "number" || typeof value === "boolean");
155
+ if (values.length === 0) return withReflectionTags(reflection, {
156
+ name: reflection.typeName,
157
+ description: reflection.description
158
+ });
159
+ return withReflectionTags(reflection, {
160
+ name: reflection.typeName,
161
+ description: reflection.description,
162
+ enum: values
163
+ });
127
164
  }
128
165
  case _powerlines_deepkit_vendor_type.ReflectionKind.array: {
129
- const items = reflectionToJtd(reflection.type);
130
- return {
131
- ...schema,
132
- elements: items ?? {}
133
- };
166
+ const items = reflectionToJsonSchemaInner(reflection.type);
167
+ return withReflectionTags(reflection, {
168
+ type: "array",
169
+ name: reflection.typeName,
170
+ items: items ?? {}
171
+ });
134
172
  }
135
173
  case _powerlines_deepkit_vendor_type.ReflectionKind.tuple: {
136
- const items = reflection.types.map((member) => reflectionToJtd(member.type)).filter((item) => item !== void 0);
137
- if (items.length === 0) return {
138
- ...schema,
139
- elements: {}
140
- };
141
- if (items.length === 1) return {
142
- ...schema,
143
- elements: items[0]
144
- };
145
- return {
146
- ...schema,
147
- elements: {}
148
- };
174
+ const items = reflection.types.map((member) => reflectionToJsonSchemaInner(member.type)).filter((item) => item !== void 0);
175
+ if (items.length <= 1) return withReflectionTags(reflection, {
176
+ type: "array",
177
+ name: reflection.typeName,
178
+ items: items[0] ?? {}
179
+ });
180
+ return withReflectionTags(reflection, {
181
+ type: "array",
182
+ name: reflection.typeName,
183
+ items,
184
+ minItems: items.length,
185
+ maxItems: items.length
186
+ });
149
187
  }
150
188
  case _powerlines_deepkit_vendor_type.ReflectionKind.union: {
151
- const branches = reflection.types.map((inner) => reflectionToJtd(inner)).filter((item) => item !== void 0);
189
+ const branches = reflection.types.map((inner) => reflectionToJsonSchemaInner(inner)).filter(require_type_checks.isJsonSchema);
152
190
  const nullable = reflection.types.some((inner) => inner.kind === _powerlines_deepkit_vendor_type.ReflectionKind.null || inner.kind === _powerlines_deepkit_vendor_type.ReflectionKind.undefined);
153
- const nonNull = branches.filter((b) => !isPureNullable(b));
154
- if (nonNull.length === 0) return {
155
- ...schema,
191
+ const nonNull = branches.filter((branch) => branch.type !== "null" && !require_type_checks.isNullOnlyJsonSchema(branch));
192
+ if (nonNull.length === 0) return withReflectionTags(reflection, {
193
+ type: "null",
156
194
  nullable: true
157
- };
158
- if (nonNull.length === 1) {
159
- const only = nonNull[0];
160
- if (nullable) only.nullable = true;
161
- return {
162
- ...schema,
163
- ...only
164
- };
165
- }
166
- if (nonNull.every(isEnumForm)) {
167
- const merged = Array.from(new Set(nonNull.flatMap((b) => b.enum)));
168
- const form = {
169
- ...schema,
170
- enum: merged
171
- };
172
- if (nullable) form.nullable = true;
173
- return {
174
- ...schema,
175
- ...form
176
- };
177
- }
195
+ });
196
+ if (nonNull.length === 1) return withNullable(withReflectionTags(reflection, {
197
+ name: reflection.typeName,
198
+ ...nonNull[0]
199
+ }), nullable);
200
+ const enumValues = nonNull.map((branch) => branch.const).filter((value) => value !== void 0);
201
+ if (enumValues.length === nonNull.length) return withNullable(withReflectionTags(reflection, {
202
+ name: reflection.typeName,
203
+ enum: enumValues
204
+ }), nullable);
178
205
  const discriminator = tryReflectionDiscriminator(reflection.types);
179
- if (discriminator) {
180
- if (nullable) discriminator.nullable = true;
181
- return {
182
- ...schema,
183
- ...discriminator
184
- };
185
- }
186
- const fallback = {};
187
- if (nullable) fallback.nullable = true;
188
- return {
189
- ...schema,
190
- ...fallback
191
- };
206
+ if (discriminator) return withNullable(withReflectionTags(reflection, {
207
+ name: reflection.typeName,
208
+ ...discriminator
209
+ }), nullable);
210
+ return withNullable(withReflectionTags(reflection, {
211
+ name: reflection.typeName,
212
+ anyOf: nonNull
213
+ }), nullable);
192
214
  }
193
215
  case _powerlines_deepkit_vendor_type.ReflectionKind.intersection: {
194
- const members = reflection.types.map((inner) => reflectionToJtd(inner)).filter((item) => item !== void 0);
216
+ const members = reflection.types.map((inner) => reflectionToJsonSchemaInner(inner)).filter((item) => item !== void 0);
195
217
  if (members.length === 0) return;
196
- if (members.length === 1) return {
197
- ...schema,
218
+ if (members.length === 1) return withReflectionTags(reflection, {
219
+ name: reflection.typeName,
198
220
  ...members[0]
199
- };
200
- if (members.every((member) => member && isPropertiesForm(member))) return mergePropertiesForms(members);
201
- return {
202
- ...schema,
203
- ...members[0]
204
- };
221
+ });
222
+ if (members.every(require_type_checks.isJsonSchemaObject)) return withReflectionTags(reflection, {
223
+ name: reflection.typeName,
224
+ ...mergeObjectSchemas(members)
225
+ });
226
+ return withReflectionTags(reflection, {
227
+ name: reflection.typeName,
228
+ allOf: members
229
+ });
205
230
  }
206
- case _powerlines_deepkit_vendor_type.ReflectionKind.promise: return reflectionToJtd(reflection.type);
207
- case _powerlines_deepkit_vendor_type.ReflectionKind.objectLiteral: return objectReflectionToJtd(reflection);
231
+ case _powerlines_deepkit_vendor_type.ReflectionKind.promise: return reflectionToJsonSchemaInner(reflection.type);
232
+ case _powerlines_deepkit_vendor_type.ReflectionKind.objectLiteral: return objectReflectionToJsonSchema(reflection);
208
233
  case _powerlines_deepkit_vendor_type.ReflectionKind.class: switch (reflection.classType?.name) {
209
- case "Date": return {
210
- ...schema,
211
- type: "timestamp"
212
- };
213
- case "RegExp": return {
214
- ...schema,
215
- type: "string"
216
- };
217
- case "URL": return {
218
- ...schema,
219
- type: "string"
220
- };
234
+ case "Date": return withReflectionTags(reflection, {
235
+ type: "string",
236
+ format: "date-time"
237
+ });
238
+ case "RegExp": return withReflectionTags(reflection, {
239
+ type: "string",
240
+ format: "regex"
241
+ });
242
+ case "URL": return withReflectionTags(reflection, {
243
+ type: "string",
244
+ format: "uri"
245
+ });
221
246
  case "Set": {
222
247
  const itemType = reflection.arguments?.[0];
223
- const items = itemType ? reflectionToJtd(itemType) : void 0;
224
- return {
225
- ...schema,
226
- elements: items ?? {}
227
- };
248
+ return withReflectionTags(reflection, {
249
+ type: "array",
250
+ items: (itemType ? reflectionToJsonSchemaInner(itemType) : void 0) ?? {},
251
+ uniqueItems: true
252
+ });
228
253
  }
229
254
  case "Map": {
230
255
  const valueType = reflection.arguments?.[1];
231
- const values = valueType ? reflectionToJtd(valueType) : void 0;
232
- return {
233
- ...schema,
234
- values: values ?? {}
235
- };
256
+ return withReflectionTags(reflection, {
257
+ type: "object",
258
+ additionalProperties: (valueType ? reflectionToJsonSchemaInner(valueType) : void 0) ?? true
259
+ });
236
260
  }
237
261
  case "Uint8Array":
238
262
  case "Uint8ClampedArray":
@@ -244,12 +268,17 @@ function reflectionToJtd(reflection) {
244
268
  case "Float32Array":
245
269
  case "Float64Array":
246
270
  case "BigInt64Array":
247
- case "BigUint64Array": return {
248
- ...schema,
249
- type: "string"
250
- };
271
+ case "BigUint64Array": return withReflectionTags(reflection, {
272
+ type: "string",
273
+ format: "byte",
274
+ contentEncoding: "base64"
275
+ });
251
276
  case void 0:
252
- default: return objectReflectionToJtd(reflection);
277
+ default: return withReflectionTags(reflection, {
278
+ name: reflection.typeName,
279
+ description: reflection.description,
280
+ ...objectReflectionToJsonSchema(reflection)
281
+ });
253
282
  }
254
283
  case _powerlines_deepkit_vendor_type.ReflectionKind.symbol:
255
284
  case _powerlines_deepkit_vendor_type.ReflectionKind.property:
@@ -268,72 +297,26 @@ function reflectionToJtd(reflection) {
268
297
  default: return;
269
298
  }
270
299
  }
271
- /**
272
- * Tests whether a JTD form is an enum form.
273
- *
274
- * @param form - The JTD form to inspect.
275
- * @returns `true` if the form is a JTD enum form.
276
- */
277
- function isEnumForm(form) {
278
- return Array.isArray(form.enum);
279
- }
280
- /**
281
- * Tests whether a JTD form is a properties form (object).
282
- *
283
- * @param form - The JTD form to inspect.
284
- * @returns `true` if the form is a JTD properties form.
285
- */
286
- function isPropertiesForm(form) {
287
- return "properties" in form || "optionalProperties" in form;
288
- }
289
- /**
290
- * Tests whether a JTD form is the empty `{ nullable: true }` placeholder.
291
- *
292
- * @param form - The JTD form to inspect.
293
- * @returns `true` if the form has no shape constraints beyond `nullable`.
294
- */
295
- function isPureNullable(form) {
296
- return Object.keys(form).filter((k) => k !== "nullable" && k !== "metadata").length === 0 && form.nullable === true;
297
- }
298
- /**
299
- * Shallow-merges two JTD properties forms, unioning their `properties` and `optionalProperties` maps.
300
- *
301
- * @param forms - The JTD properties forms to merge.
302
- * @returns The merged JTD properties form.
303
- */
304
- function mergePropertiesForms(forms) {
300
+ function mergeObjectSchemas(schemas) {
305
301
  const merged = {
302
+ type: "object",
306
303
  properties: {},
307
- optionalProperties: {}
304
+ required: []
308
305
  };
309
- for (const form of forms) {
310
- const p = form.properties;
311
- const o = form.optionalProperties;
312
- if (p) Object.assign(merged.properties, p);
313
- if (o) Object.assign(merged.optionalProperties, o);
314
- if (form.additionalProperties) merged.additionalProperties = true;
306
+ for (const schema of schemas) {
307
+ if (schema.properties) merged.properties = (0, defu.default)(merged.properties, schema.properties);
308
+ if (schema.required) merged.required = Array.from(new Set([...merged.required ?? [], ...schema.required]));
309
+ if (schema.additionalProperties !== void 0) merged.additionalProperties = schema.additionalProperties;
315
310
  }
316
- const hasProperties = Object.keys(merged.properties).length > 0;
317
- const hasOptional = Object.keys(merged.optionalProperties).length > 0;
318
- const result = {};
319
- if (hasProperties) result.properties = merged.properties;
320
- else if (!hasOptional) result.properties = {};
321
- if (hasOptional) result.optionalProperties = merged.optionalProperties;
322
- if (merged.additionalProperties) result.additionalProperties = true;
323
- return result;
311
+ if ((merged.required?.length ?? 0) === 0) delete merged.required;
312
+ return merged;
324
313
  }
325
- /**
326
- * Detects whether a Deepkit union represents a tagged union and, when so, emits the corresponding JTD discriminator form.
327
- *
328
- * @param types - The Deepkit reflection types that make up the union branches.
329
- * @returns A JTD discriminator form if every non-null branch is an object literal that shares a string-literal tag property, otherwise `undefined`.
330
- */
331
314
  function tryReflectionDiscriminator(types) {
332
315
  const nonNullTypes = types.filter((t) => t.kind !== _powerlines_deepkit_vendor_type.ReflectionKind.null && t.kind !== _powerlines_deepkit_vendor_type.ReflectionKind.undefined);
333
316
  const objectBranches = nonNullTypes.filter((t) => t.kind === _powerlines_deepkit_vendor_type.ReflectionKind.objectLiteral || t.kind === _powerlines_deepkit_vendor_type.ReflectionKind.class);
334
317
  if (objectBranches.length < 2 || objectBranches.length !== nonNullTypes.length) return;
335
318
  let tagKey;
336
- const mapping = {};
319
+ const branches = [];
337
320
  for (const branch of objectBranches) {
338
321
  const literalProps = [];
339
322
  for (const member of branch.types) if ((member.kind === _powerlines_deepkit_vendor_type.ReflectionKind.property || member.kind === _powerlines_deepkit_vendor_type.ReflectionKind.propertySignature) && typeof member.name === "string" && member.type.kind === _powerlines_deepkit_vendor_type.ReflectionKind.literal && typeof member.type.literal === "string") literalProps.push({
@@ -344,67 +327,77 @@ function tryReflectionDiscriminator(types) {
344
327
  const first = literalProps[0];
345
328
  if (!tagKey) tagKey = first.name;
346
329
  else if (tagKey !== first.name) return;
347
- const body = objectReflectionToJtd({
330
+ const body = objectReflectionToJsonSchema({
348
331
  ...branch,
349
332
  types: branch.types.filter((member) => !((member.kind === _powerlines_deepkit_vendor_type.ReflectionKind.property || member.kind === _powerlines_deepkit_vendor_type.ReflectionKind.propertySignature) && member.name === tagKey))
350
333
  });
351
- if (!body || !isPropertiesForm(body)) return;
352
- mapping[first.literal] = body;
334
+ if (!body || !require_type_checks.isJsonSchemaObject(body)) return;
335
+ branches.push({
336
+ type: "object",
337
+ properties: {
338
+ [tagKey]: { const: first.literal },
339
+ ...body.properties ?? {}
340
+ },
341
+ required: [tagKey, ...body.required ?? []],
342
+ additionalProperties: body.additionalProperties ?? false
343
+ });
353
344
  }
354
345
  if (!tagKey) return;
355
346
  return {
356
- discriminator: tagKey,
357
- mapping
347
+ oneOf: branches,
348
+ discriminator: { propertyName: tagKey }
358
349
  };
359
350
  }
360
- /**
361
- * Internal worker that produces a JTD properties form (or `values` form for index signatures alone) from a Deepkit object-like type.
362
- *
363
- * @param type - The class or object literal type whose members should be serialized.
364
- * @returns A JTD properties or values form describing the type's members.
365
- */
366
- function objectReflectionToJtd(type) {
351
+ function objectReflectionToJsonSchema(type) {
367
352
  const reflection = _powerlines_deepkit_vendor_type.ReflectionClass.from(type);
368
- const schema = {};
369
- schema.metadata = schema.metadata ?? {};
370
- schema.metadata.isReadonly = reflection.isReadonly();
371
- schema.metadata.isIgnored = reflection.isIgnored();
372
- schema.metadata.isInternal = reflection.isInternal();
373
- schema.metadata.isRuntime = reflection.isRuntime();
374
- schema.metadata.isHidden = reflection.isHidden();
375
- if ((0, _stryke_type_checks.isSetString)(reflection.databaseSchemaName)) schema.metadata.table = reflection.databaseSchemaName;
376
- if ((0, _stryke_type_checks.isSetString)(reflection.getDescription())) schema.metadata.description = reflection.getDescription();
377
- if ((0, _stryke_type_checks.isSetArray)(reflection.getAlias())) schema.metadata.alias = reflection.getAlias();
378
- if ((0, _stryke_type_checks.isSetString)(reflection.getTitle())) schema.metadata.title = reflection.getTitle();
379
- const properties = {};
380
- const optionalProperties = {};
381
- for (const propertyReflection of reflection.getProperties()) if (propertyReflection.getKind() === _powerlines_deepkit_vendor_type.ReflectionKind.indexSignature) {
382
- const valueSchema = reflectionToJtd(propertyReflection.type);
383
- if (valueSchema) return {
384
- ...schema,
385
- values: valueSchema,
386
- additionalProperties: true
387
- };
388
- } else {
389
- const property = reflectionToJtd(propertyReflection.type);
353
+ const schema = {
354
+ type: "object",
355
+ name: reflection.getName(),
356
+ description: reflection.getDescription(),
357
+ properties: {},
358
+ required: [],
359
+ readOnly: reflection.isReadonly(),
360
+ ignore: reflection.isIgnored(),
361
+ internal: reflection.isInternal(),
362
+ runtime: reflection.isRuntime(),
363
+ hidden: reflection.isHidden(),
364
+ primaryKey: reflection.getPrimaries().map((primary) => primary.getNameAsString()),
365
+ ...(0, _stryke_type_checks.isSetString)(reflection.databaseSchemaName) ? { databaseSchemaName: reflection.databaseSchemaName } : {},
366
+ ...(0, _stryke_type_checks.isSetString)(reflection.getName()) ? { name: reflection.getName() } : {},
367
+ ...(0, _stryke_type_checks.isSetString)(reflection.getDescription()) ? { description: reflection.getDescription() } : {},
368
+ ...(0, _stryke_type_checks.isSetArray)(reflection.getAlias()) ? { alias: reflection.getAlias() } : {},
369
+ ...(0, _stryke_type_checks.isSetString)(reflection.getTitle()) ? { title: reflection.getTitle() } : {}
370
+ };
371
+ for (const propertyReflection of reflection.getProperties()) {
372
+ if (propertyReflection.getKind() === _powerlines_deepkit_vendor_type.ReflectionKind.indexSignature) {
373
+ schema.additionalProperties = reflectionToJsonSchemaInner(propertyReflection.type) ?? true;
374
+ continue;
375
+ }
376
+ let property = reflectionToJsonSchemaInner(propertyReflection.type);
390
377
  if (!property) continue;
391
- property.metadata = property.metadata ?? {};
392
- property.metadata.isReadonly = propertyReflection.isReadonly();
393
- property.metadata.isIgnored = propertyReflection.isIgnored();
394
- property.metadata.isInternal = propertyReflection.isInternal();
395
- property.metadata.isRuntime = propertyReflection.isRuntime();
396
- property.metadata.isPrimaryKey = propertyReflection.isPrimaryKey();
397
- property.metadata.isHidden = propertyReflection.isHidden();
398
- if (propertyReflection.hasDefault()) property.metadata.default = propertyReflection.getDefaultValue();
399
- if ((0, _stryke_type_checks.isSetString)(propertyReflection.getDescription())) property.metadata.description = propertyReflection.getDescription();
400
- if ((0, _stryke_type_checks.isSetArray)(propertyReflection.getAlias())) property.metadata.alias = propertyReflection.getAlias();
401
- if ((0, _stryke_type_checks.isSetString)(propertyReflection.getTitle())) property.metadata.title = propertyReflection.getTitle();
402
- if (propertyReflection.isOptional()) optionalProperties[propertyReflection.name] = property;
403
- else properties[propertyReflection.name] = property;
378
+ property = {
379
+ ...property,
380
+ name: propertyReflection.getNameAsString(),
381
+ description: propertyReflection.getDescription(),
382
+ readOnly: propertyReflection.isReadonly(),
383
+ ignore: propertyReflection.isIgnored(),
384
+ internal: propertyReflection.isInternal(),
385
+ runtime: propertyReflection.isRuntime(),
386
+ hidden: propertyReflection.isHidden(),
387
+ visibility: propertyReflection.isPublic() ? "public" : propertyReflection.isProtected() ? "protected" : propertyReflection.isPrivate() ? "private" : void 0,
388
+ ...propertyReflection.hasDefault() ? { default: propertyReflection.getDefaultValue() } : {},
389
+ ...(0, _stryke_type_checks.isSetArray)(propertyReflection.getGroups()) ? { tags: propertyReflection.getGroups() } : {},
390
+ ...(0, _stryke_type_checks.isSetArray)(propertyReflection.getAlias()) ? { alias: propertyReflection.getAlias() } : {},
391
+ ...(0, _stryke_type_checks.isSetString)(propertyReflection.getTitle()) ? { title: propertyReflection.getTitle() } : {}
392
+ };
393
+ if (propertyReflection.isNullable()) property = withNullable(property, true);
394
+ schema.properties ??= {};
395
+ schema.properties[propertyReflection.name] = property;
396
+ if (!propertyReflection.isOptional()) {
397
+ schema.required ??= [];
398
+ schema.required.push(propertyReflection.name);
399
+ }
404
400
  }
405
- if (Object.keys(properties).length > 0) schema.properties = properties;
406
- else if (Object.keys(optionalProperties).length > 0) schema.optionalProperties = optionalProperties;
407
- else schema.properties = {};
408
401
  return schema;
409
402
  }
410
403