@power-plant/schema 0.0.36 → 0.0.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.
package/dist/index.cjs CHANGED
@@ -1,29 +1,35 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
2
  const require_rolldown_runtime = require('./rolldown-runtime-C_NdSu1c.cjs');
3
3
  const require_constants = require('./constants-CEmLvTDd.cjs');
4
- const require_helpers = require('./helpers-CQS3qnsv.cjs');
4
+ const require_helpers = require('./helpers-DbFdMcOB.cjs');
5
+ const require_codegen = require('./codegen.cjs');
5
6
  const require_storage = require('./storage-B8aDmNpv.cjs');
6
7
  let _stryke_type_checks_is_set_object = require("@stryke/type-checks/is-set-object");
7
8
  let _stryke_type_checks_is_set_string = require("@stryke/type-checks/is-set-string");
8
9
  let _stryke_type_checks = require("@stryke/type-checks");
10
+ let _deepkit_type = require("@deepkit/type");
11
+ let _deepkit_type_compiler = require("@deepkit/type-compiler");
9
12
  let _stryke_convert_extract_file_reference = require("@stryke/convert/extract-file-reference");
10
13
  let _stryke_fs_resolve = require("@stryke/fs/resolve");
11
14
  let _stryke_hash = require("@stryke/hash");
12
15
  let _stryke_helpers_deep_clone = require("@stryke/helpers/deep-clone");
16
+ let _stryke_helpers_omit = require("@stryke/helpers/omit");
13
17
  let _stryke_json = require("@stryke/json");
14
18
  let _stryke_path_append = require("@stryke/path/append");
15
19
  let _stryke_path_find = require("@stryke/path/find");
16
20
  let _stryke_path_join = require("@stryke/path/join");
17
21
  let _stryke_resolve_constants = require("@stryke/resolve/constants");
18
22
  let _stryke_resolve_load = require("@stryke/resolve/load");
19
- let _stryke_resolve_resolve = require("@stryke/resolve/resolve");
20
23
  let _stryke_string_format_list = require("@stryke/string-format/list");
21
24
  let _stryke_zod = require("@stryke/zod");
22
25
  let _valibot_to_json_schema = require("@valibot/to-json-schema");
23
- let ts_json_schema_generator_dist_factory_generator_js = require("ts-json-schema-generator/dist/factory/generator.js");
24
- let ts_json_schema_generator_dist_src_Config_js = require("ts-json-schema-generator/dist/src/Config.js");
26
+ let esbuild = require("esbuild");
27
+ let jiti = require("jiti");
28
+ let node_fs_promises = require("node:fs/promises");
25
29
  let typescript = require("typescript");
26
30
  typescript = require_rolldown_runtime.__toESM(typescript, 1);
31
+ let defu = require("defu");
32
+ defu = require_rolldown_runtime.__toESM(defu, 1);
27
33
 
28
34
  //#region src/compatibility.ts
29
35
  const METADATA_KEYS = /* @__PURE__ */ new Set([
@@ -127,6 +133,412 @@ function assertSchemasDoNotContradict(base, override, label = "schema") {
127
133
  if (issues.length > 0) throw new Error(`The ${label} schema contradicts the generator schema:\n${issues.map((issue) => `- ${issue}`).join("\n")}`);
128
134
  }
129
135
 
136
+ //#endregion
137
+ //#region src/reflection.ts
138
+ /**
139
+ * Maps a Deepkit numeric `brand` to JSON Schema `type` and `format`.
140
+ *
141
+ * @remarks
142
+ * 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.
143
+ *
144
+ * @param brand - The Deepkit numeric brand to convert.
145
+ * @return A JSON Schema fragment representing the numeric type corresponding to the provided brand.
146
+ */
147
+ function numberBrandToJsonSchema(brand) {
148
+ switch (brand) {
149
+ case _deepkit_type.TypeNumberBrand.integer: return {
150
+ type: "integer",
151
+ format: "int32",
152
+ multipleOf: 1
153
+ };
154
+ case _deepkit_type.TypeNumberBrand.int8: return {
155
+ type: "integer",
156
+ format: "int8",
157
+ multipleOf: 1
158
+ };
159
+ case _deepkit_type.TypeNumberBrand.uint8: return {
160
+ type: "integer",
161
+ format: "uint8",
162
+ multipleOf: 1
163
+ };
164
+ case _deepkit_type.TypeNumberBrand.int16: return {
165
+ type: "integer",
166
+ format: "int16",
167
+ multipleOf: 1
168
+ };
169
+ case _deepkit_type.TypeNumberBrand.uint16: return {
170
+ type: "integer",
171
+ format: "uint16",
172
+ multipleOf: 1
173
+ };
174
+ case _deepkit_type.TypeNumberBrand.int32: return {
175
+ type: "integer",
176
+ format: "int32",
177
+ multipleOf: 1
178
+ };
179
+ case _deepkit_type.TypeNumberBrand.uint32: return {
180
+ type: "integer",
181
+ format: "uint32",
182
+ multipleOf: 1
183
+ };
184
+ case _deepkit_type.TypeNumberBrand.float:
185
+ case _deepkit_type.TypeNumberBrand.float32: return {
186
+ type: "number",
187
+ format: "float"
188
+ };
189
+ case _deepkit_type.TypeNumberBrand.float64: return {
190
+ type: "number",
191
+ format: "double"
192
+ };
193
+ case void 0:
194
+ default: return { type: "number" };
195
+ }
196
+ }
197
+ function withReflectionTags(reflection, schema) {
198
+ if (!(0, _stryke_type_checks.isSetObject)(schema) || !(0, _stryke_type_checks.isSetObject)(reflection?.tags)) return schema;
199
+ const updatedSchema = { ...schema };
200
+ const tags = reflection.tags;
201
+ if ((0, _stryke_type_checks.isSetString)(tags.title)) updatedSchema.title = tags.title;
202
+ if ((0, _stryke_type_checks.isSetArray)(tags.alias)) updatedSchema.alias = tags.alias;
203
+ if (!(0, _stryke_type_checks.isUndefined)(tags.hidden)) updatedSchema.hidden = tags.hidden;
204
+ if (!(0, _stryke_type_checks.isUndefined)(tags.ignore)) updatedSchema.ignore = tags.ignore;
205
+ if (!(0, _stryke_type_checks.isUndefined)(tags.internal)) updatedSchema.internal = tags.internal;
206
+ if (!(0, _stryke_type_checks.isUndefined)(tags.runtime)) updatedSchema.runtime = tags.runtime;
207
+ if (!(0, _stryke_type_checks.isUndefined)(tags.readonly)) updatedSchema.readOnly = tags.readonly;
208
+ return updatedSchema;
209
+ }
210
+ function withNullable(schema) {
211
+ if (!(0, _stryke_type_checks.isSetObject)(schema)) return { anyOf: [schema, {
212
+ type: "null",
213
+ default: null
214
+ }] };
215
+ const rawType = schema.type;
216
+ const types = Array.isArray(rawType) ? [...rawType] : rawType ? [rawType] : [];
217
+ if (!types.includes("null")) types.push("null");
218
+ return {
219
+ ...schema,
220
+ type: types.length === 1 ? types[0] : types
221
+ };
222
+ }
223
+ /**
224
+ * Converts a Deepkit type reflection into a JSON Schema (draft-07) fragment.
225
+ */
226
+ function reflectionToJsonSchema(reflection) {
227
+ return reflectionToJsonSchemaInner(reflection);
228
+ }
229
+ function reflectionToJsonSchemaInner(reflection) {
230
+ switch (reflection.kind) {
231
+ case _deepkit_type.ReflectionKind.any:
232
+ case _deepkit_type.ReflectionKind.unknown:
233
+ case _deepkit_type.ReflectionKind.void:
234
+ case _deepkit_type.ReflectionKind.object: return withReflectionTags(reflection, { name: reflection.typeName });
235
+ case _deepkit_type.ReflectionKind.never: return;
236
+ case _deepkit_type.ReflectionKind.undefined:
237
+ case _deepkit_type.ReflectionKind.null: return withReflectionTags(reflection, {
238
+ type: "null",
239
+ name: reflection.typeName,
240
+ default: null
241
+ });
242
+ case _deepkit_type.ReflectionKind.string: return withReflectionTags(reflection, {
243
+ type: "string",
244
+ name: reflection.typeName
245
+ });
246
+ case _deepkit_type.ReflectionKind.boolean: return withReflectionTags(reflection, {
247
+ type: "boolean",
248
+ name: reflection.typeName
249
+ });
250
+ case _deepkit_type.ReflectionKind.number: return withReflectionTags(reflection, numberBrandToJsonSchema(reflection.brand));
251
+ case _deepkit_type.ReflectionKind.bigint: return withReflectionTags(reflection, {
252
+ type: "integer",
253
+ name: reflection.typeName,
254
+ format: "int64"
255
+ });
256
+ case _deepkit_type.ReflectionKind.regexp: return withReflectionTags(reflection, {
257
+ type: "string",
258
+ name: reflection.typeName,
259
+ format: "regex",
260
+ contentMediaType: "text/regex"
261
+ });
262
+ case _deepkit_type.ReflectionKind.literal: {
263
+ const { literal } = reflection;
264
+ if ((0, _stryke_type_checks.isBigInt)(literal)) return withReflectionTags(reflection, {
265
+ type: "integer",
266
+ name: reflection.typeName,
267
+ format: "int64",
268
+ const: literal
269
+ });
270
+ if ((0, _stryke_type_checks.isRegExp)(literal)) return withReflectionTags(reflection, {
271
+ type: "string",
272
+ name: reflection.typeName,
273
+ format: "regex",
274
+ const: literal.source
275
+ });
276
+ return withReflectionTags(reflection, {
277
+ type: require_codegen.getJsonSchemaType(literal),
278
+ name: reflection.typeName,
279
+ const: literal
280
+ });
281
+ }
282
+ case _deepkit_type.ReflectionKind.templateLiteral: return withReflectionTags(reflection, { type: "string" });
283
+ case _deepkit_type.ReflectionKind.enum: {
284
+ const values = reflection.values.filter((value) => (0, _stryke_type_checks.isString)(value) || (0, _stryke_type_checks.isInteger)(value) || (0, _stryke_type_checks.isBigInt)(value) || (0, _stryke_type_checks.isNumber)(value) || (0, _stryke_type_checks.isBoolean)(value) || (0, _stryke_type_checks.isNull)(value));
285
+ if (values.length === 0) return withReflectionTags(reflection, {
286
+ name: reflection.typeName,
287
+ description: reflection.description,
288
+ enum: []
289
+ });
290
+ return withReflectionTags(reflection, {
291
+ type: values.every((value) => (0, _stryke_type_checks.isString)(value)) ? "string" : values.every((value) => (0, _stryke_type_checks.isInteger)(value) || (0, _stryke_type_checks.isBigInt)(value)) ? "integer" : values.every((value) => (0, _stryke_type_checks.isNumber)(value)) ? "number" : values.every((value) => (0, _stryke_type_checks.isBoolean)(value)) ? "boolean" : values.every((value) => (0, _stryke_type_checks.isNull)(value)) ? "null" : values.reduce((ret, value) => {
292
+ const type = require_codegen.getJsonSchemaType(value);
293
+ if (require_helpers.isJsonSchemaPrimitiveType(type) && !ret.includes(type)) ret.push(type);
294
+ return ret;
295
+ }, []),
296
+ name: reflection.typeName,
297
+ description: reflection.description,
298
+ enum: values,
299
+ default: values.length === 1 ? values[0] : void 0
300
+ });
301
+ }
302
+ case _deepkit_type.ReflectionKind.array: {
303
+ const items = reflectionToJsonSchemaInner(reflection.type);
304
+ return withReflectionTags(reflection, {
305
+ type: "array",
306
+ name: reflection.typeName,
307
+ items: items ?? {}
308
+ });
309
+ }
310
+ case _deepkit_type.ReflectionKind.tuple: {
311
+ const items = reflection.types.map((member) => reflectionToJsonSchemaInner(member.type)).filter((item) => item !== void 0);
312
+ if (items.length <= 1) return withReflectionTags(reflection, {
313
+ type: "array",
314
+ name: reflection.typeName,
315
+ items: items.length === 1 ? items[0] : {}
316
+ });
317
+ return withReflectionTags(reflection, {
318
+ type: "array",
319
+ name: reflection.typeName,
320
+ prefixItems: items,
321
+ minItems: items.length,
322
+ maxItems: items.length
323
+ });
324
+ }
325
+ case _deepkit_type.ReflectionKind.union: {
326
+ const branches = reflection.types.map((inner) => reflectionToJsonSchemaInner(inner)).filter((branch) => branch !== void 0);
327
+ if (!reflection.types.some((inner) => inner.kind === _deepkit_type.ReflectionKind.null || inner.kind === _deepkit_type.ReflectionKind.undefined)) return withReflectionTags(reflection, {
328
+ name: reflection.typeName,
329
+ anyOf: branches
330
+ });
331
+ const nonNull = branches.filter((branch) => !require_helpers.isNullOnlyJsonSchema(branch));
332
+ if (nonNull.length === 0) return withReflectionTags(reflection, {
333
+ type: "null",
334
+ default: null
335
+ });
336
+ if (nonNull.length === 1) {
337
+ const first = nonNull[0];
338
+ if (!(0, _stryke_type_checks.isSetObject)(first)) return withNullable(withReflectionTags(reflection, {
339
+ name: reflection.typeName,
340
+ anyOf: [first]
341
+ }));
342
+ return withNullable(withReflectionTags(reflection, {
343
+ name: reflection.typeName,
344
+ ...first
345
+ }));
346
+ }
347
+ const enumValues = nonNull.map((branch) => (0, _stryke_type_checks.isSetObject)(branch) ? branch.const : void 0).filter((value) => value === null || typeof value === "string" || typeof value === "number" || typeof value === "bigint" || typeof value === "boolean");
348
+ if (enumValues.length === nonNull.length) return withNullable(withReflectionTags(reflection, {
349
+ name: reflection.typeName,
350
+ enum: enumValues
351
+ }));
352
+ const discriminator = tryReflectionDiscriminator(reflection.types);
353
+ if (discriminator && (0, _stryke_type_checks.isSetObject)(discriminator)) return withNullable(withReflectionTags(reflection, {
354
+ name: reflection.typeName,
355
+ ...discriminator
356
+ }));
357
+ return withNullable(withReflectionTags(reflection, {
358
+ name: reflection.typeName,
359
+ anyOf: nonNull
360
+ }));
361
+ }
362
+ case _deepkit_type.ReflectionKind.intersection: {
363
+ const members = reflection.types.map((inner) => reflectionToJsonSchemaInner(inner)).filter((item) => item !== void 0);
364
+ if (members.length === 0) return;
365
+ if (members.length === 1) {
366
+ if (!(0, _stryke_type_checks.isSetObject)(members[0])) return members[0];
367
+ return withReflectionTags(reflection, {
368
+ name: reflection.typeName,
369
+ ...members[0]
370
+ });
371
+ }
372
+ if (members.every(require_helpers.isJsonSchemaObject)) return withReflectionTags(reflection, {
373
+ name: reflection.typeName,
374
+ ...mergeObjectSchemas(members)
375
+ });
376
+ return withReflectionTags(reflection, {
377
+ name: reflection.typeName,
378
+ allOf: members
379
+ });
380
+ }
381
+ case _deepkit_type.ReflectionKind.promise: return reflectionToJsonSchemaInner(reflection.type);
382
+ case _deepkit_type.ReflectionKind.objectLiteral: return objectReflectionToJsonSchema(reflection);
383
+ case _deepkit_type.ReflectionKind.class: switch (reflection.classType?.name) {
384
+ case "Date": return withReflectionTags(reflection, {
385
+ type: "string",
386
+ format: "date-time"
387
+ });
388
+ case "RegExp": return withReflectionTags(reflection, {
389
+ type: "string",
390
+ format: "regex"
391
+ });
392
+ case "URL": return withReflectionTags(reflection, {
393
+ type: "string",
394
+ format: "uri"
395
+ });
396
+ case "Set": {
397
+ const itemType = reflection.arguments?.[0];
398
+ return withReflectionTags(reflection, {
399
+ type: "array",
400
+ items: (itemType ? reflectionToJsonSchemaInner(itemType) : void 0) ?? {},
401
+ uniqueItems: true
402
+ });
403
+ }
404
+ case "Map": {
405
+ const valueType = reflection.arguments?.[1];
406
+ return withReflectionTags(reflection, {
407
+ type: "object",
408
+ additionalProperties: (valueType ? reflectionToJsonSchemaInner(valueType) : void 0) ?? true
409
+ });
410
+ }
411
+ case "Uint8Array":
412
+ case "Uint8ClampedArray":
413
+ case "Uint16Array":
414
+ case "Uint32Array":
415
+ case "Int8Array":
416
+ case "Int16Array":
417
+ case "Int32Array":
418
+ case "Float32Array":
419
+ case "Float64Array":
420
+ case "BigInt64Array":
421
+ case "BigUint64Array": return withReflectionTags(reflection, {
422
+ type: "string",
423
+ format: "byte",
424
+ contentEncoding: "base64"
425
+ });
426
+ case void 0:
427
+ default: return withReflectionTags(reflection, {
428
+ name: reflection.typeName,
429
+ description: reflection.description,
430
+ ...objectReflectionToJsonSchema(reflection)
431
+ });
432
+ }
433
+ case _deepkit_type.ReflectionKind.symbol:
434
+ case _deepkit_type.ReflectionKind.property:
435
+ case _deepkit_type.ReflectionKind.method:
436
+ case _deepkit_type.ReflectionKind.function:
437
+ case _deepkit_type.ReflectionKind.parameter:
438
+ case _deepkit_type.ReflectionKind.typeParameter:
439
+ case _deepkit_type.ReflectionKind.tupleMember:
440
+ case _deepkit_type.ReflectionKind.enumMember:
441
+ case _deepkit_type.ReflectionKind.rest:
442
+ case _deepkit_type.ReflectionKind.indexSignature:
443
+ case _deepkit_type.ReflectionKind.propertySignature:
444
+ case _deepkit_type.ReflectionKind.methodSignature:
445
+ case _deepkit_type.ReflectionKind.infer:
446
+ case _deepkit_type.ReflectionKind.callSignature:
447
+ default: return;
448
+ }
449
+ }
450
+ function mergeObjectSchemas(schemas) {
451
+ const merged = {
452
+ type: "object",
453
+ properties: {},
454
+ required: []
455
+ };
456
+ for (const schema of schemas) {
457
+ if (schema.properties) merged.properties = (0, defu.default)(merged.properties, schema.properties);
458
+ if (schema.required) merged.required = Array.from(/* @__PURE__ */ new Set([...merged.required ?? [], ...schema.required]));
459
+ if (schema.additionalProperties !== void 0) merged.additionalProperties = schema.additionalProperties;
460
+ }
461
+ if ((merged.required?.length ?? 0) === 0) delete merged.required;
462
+ return merged;
463
+ }
464
+ function tryReflectionDiscriminator(types) {
465
+ const nonNullTypes = types.filter((t) => t.kind !== _deepkit_type.ReflectionKind.null && t.kind !== _deepkit_type.ReflectionKind.undefined);
466
+ const objectBranches = nonNullTypes.filter((t) => t.kind === _deepkit_type.ReflectionKind.objectLiteral || t.kind === _deepkit_type.ReflectionKind.class);
467
+ if (objectBranches.length < 2 || objectBranches.length !== nonNullTypes.length) return;
468
+ let tagKey;
469
+ const branches = [];
470
+ for (const branch of objectBranches) {
471
+ const literalProps = [];
472
+ for (const member of branch.types) if ((member.kind === _deepkit_type.ReflectionKind.property || member.kind === _deepkit_type.ReflectionKind.propertySignature) && typeof member.name === "string" && member.type.kind === _deepkit_type.ReflectionKind.literal && typeof member.type.literal === "string") literalProps.push({
473
+ name: member.name,
474
+ literal: member.type.literal
475
+ });
476
+ if (literalProps.length === 0) return;
477
+ const first = literalProps[0];
478
+ if (!tagKey) tagKey = first.name;
479
+ else if (tagKey !== first.name) return;
480
+ const body = objectReflectionToJsonSchema({
481
+ ...branch,
482
+ types: branch.types.filter((member) => !((member.kind === _deepkit_type.ReflectionKind.property || member.kind === _deepkit_type.ReflectionKind.propertySignature) && member.name === tagKey))
483
+ });
484
+ if (!body || !require_helpers.isJsonSchemaObject(body)) return;
485
+ branches.push({
486
+ type: "object",
487
+ properties: {
488
+ [tagKey]: { const: first.literal },
489
+ ...body.properties ?? {}
490
+ },
491
+ required: [tagKey, ...body.required ?? []],
492
+ additionalProperties: body.additionalProperties ?? false
493
+ });
494
+ }
495
+ if (!tagKey) return;
496
+ return {
497
+ oneOf: branches,
498
+ discriminator: { propertyName: tagKey }
499
+ };
500
+ }
501
+ function objectReflectionToJsonSchema(type) {
502
+ const reflection = _deepkit_type.ReflectionClass.from(type);
503
+ const schema = {
504
+ type: "object",
505
+ name: reflection.getName(),
506
+ description: reflection.getDescription(),
507
+ properties: {},
508
+ required: [],
509
+ primaryKey: reflection.getPrimaries().map((primary) => primary.getNameAsString()),
510
+ ...(0, _stryke_type_checks.isSetString)(reflection.databaseSchemaName) ? { databaseSchemaName: reflection.databaseSchemaName } : {},
511
+ ...(0, _stryke_type_checks.isSetString)(reflection.getName()) ? { name: reflection.getName() } : {},
512
+ ...(0, _stryke_type_checks.isSetString)(reflection.getDescription()) ? { description: reflection.getDescription() } : {}
513
+ };
514
+ for (const propertyReflection of reflection.getProperties()) {
515
+ if (propertyReflection.getKind() === _deepkit_type.ReflectionKind.indexSignature) {
516
+ schema.additionalProperties = reflectionToJsonSchemaInner(propertyReflection.type) ?? true;
517
+ continue;
518
+ }
519
+ let property = reflectionToJsonSchemaInner(propertyReflection.type);
520
+ if (!property) continue;
521
+ const propertySchema = (0, _stryke_type_checks.isSetObject)(property) ? property : {};
522
+ const groups = propertyReflection.getGroups();
523
+ property = {
524
+ ...propertySchema,
525
+ name: propertyReflection.getNameAsString(),
526
+ description: propertyReflection.getDescription(),
527
+ readOnly: propertyReflection.isReadonly(),
528
+ ...propertyReflection.hasDefault() ? { default: propertyReflection.getDefaultValue() } : {},
529
+ ...(0, _stryke_type_checks.isSetArray)(groups) ? { tags: groups } : {}
530
+ };
531
+ if (propertyReflection.isNullable()) property = withNullable(property);
532
+ schema.properties ??= {};
533
+ schema.properties[propertyReflection.name] = property;
534
+ if (!propertyReflection.isOptional()) {
535
+ schema.required ??= [];
536
+ schema.required.push(propertyReflection.name);
537
+ }
538
+ }
539
+ return schema;
540
+ }
541
+
130
542
  //#endregion
131
543
  //#region src/extract.ts
132
544
  const SCHEMA_BUNDLE_BASE_URI = "https://power-plant.invalid/";
@@ -332,6 +744,10 @@ function extractHash(variant, input) {
332
744
  variant,
333
745
  input: unwrappedConfig._def
334
746
  });
747
+ else if ((0, _deepkit_type.isType)(unwrappedConfig)) return (0, _stryke_hash.murmurhash)({
748
+ variant,
749
+ input: (0, _deepkit_type.stringifyType)(unwrappedConfig)
750
+ });
335
751
  else if ((0, _stryke_json.isStandardJsonSchema)(unwrappedConfig)) return (0, _stryke_hash.murmurhash)({
336
752
  variant,
337
753
  input: unwrappedConfig["~standard"]
@@ -356,6 +772,13 @@ function extractHash(variant, input) {
356
772
  throw new Error(`Failed to create an input hash for the provided schema definition input. The input must be a Zod schema, a Standard JSON Schema, a JSON Schema object, a Valibot BaseSchema, or a reflected Deepkit Type object.`);
357
773
  }
358
774
  /**
775
+ * Converts a reflected Deepkit {@link Type} into a JSON Schema (draft-2020-12) representation.
776
+ */
777
+ function extractReflection(reflection) {
778
+ if (!(0, _deepkit_type.isType)(reflection)) return;
779
+ return reflectionToJsonSchema(reflection);
780
+ }
781
+ /**
359
782
  * Extracts a JSON Schema from Zod, Standard Schema, Valibot, untyped, or JSON Schema inputs.
360
783
  *
361
784
  * @param schema - The schema input to extract a JSON Schema from.
@@ -381,6 +804,7 @@ function extractJsonSchema(schema) {
381
804
  function extractResolvedVariant(input) {
382
805
  if ((0, _stryke_type_checks_is_set_object.isSetObject)(input)) {
383
806
  if ((0, _stryke_zod.isZod3Type)(input)) return "zod3";
807
+ else if ((0, _deepkit_type.isType)(input)) return "reflection";
384
808
  else if (require_helpers.isUntypedConfigStrict(input) || require_helpers.isUntypedSchemaStrict(input)) return "untyped";
385
809
  else if ((0, _stryke_json.isStandardJsonSchema)(input)) return "standard-schema";
386
810
  else if (require_helpers.isJsonSchema(input)) return "json-schema";
@@ -413,6 +837,7 @@ async function extractSchema(input, variant) {
413
837
  const resolvedVariant = variant ?? extractResolvedVariant(input);
414
838
  let schema;
415
839
  if (resolvedVariant === "zod3" || resolvedVariant === "json-schema" || resolvedVariant === "standard-schema" || resolvedVariant === "untyped" || resolvedVariant === "valibot") schema = extractJsonSchema(input);
840
+ else if (resolvedVariant === "reflection") schema = extractReflection(input);
416
841
  if (schema) return bundleReferences(schema);
417
842
  throw new Error(`Failed to extract a valid schema from the provided input. The input must be a Zod schema, a Standard JSON Schema, a JSON Schema object, a Valibot BaseSchema, an untyped schema, or a reflected Deepkit Type object.`);
418
843
  }
@@ -450,123 +875,166 @@ function extractSource(variant, input) {
450
875
  variant: "valibot",
451
876
  schema: input
452
877
  };
878
+ else if (variant === "reflection") return {
879
+ hash: extractHash(variant, input),
880
+ variant: "reflection",
881
+ schema: input
882
+ };
453
883
  throw new Error(`Failed to extract source information from the provided input. The input must be a Zod schema, a Standard JSON Schema, a JSON Schema object, an untyped schema, or a reflected Deepkit Type object.`);
454
884
  }
455
- function getTsCompilerOptions(config) {
456
- if (config.tsconfig) {
457
- const raw = typescript.default.sys.readFile(config.tsconfig);
458
- if (!raw) throw new Error(`Cannot read config file "${config.tsconfig}"`);
459
- const parsedConfig = typescript.default.parseConfigFileTextToJson(config.tsconfig, raw);
460
- if (parsedConfig.error) throw new Error(parsedConfig.error.messageText.toString());
461
- if (!parsedConfig.config) throw new Error(`Invalid parsed config file "${config.tsconfig}"`);
462
- const parseResult = typescript.default.parseJsonConfigFileContent(parsedConfig.config, typescript.default.sys, (0, _stryke_path_find.findFilePath)(config.tsconfig), {}, config.tsconfig);
463
- parseResult.options.noEmit = true;
464
- delete parseResult.options.out;
465
- delete parseResult.options.outDir;
466
- delete parseResult.options.outFile;
467
- delete parseResult.options.declaration;
468
- delete parseResult.options.declarationDir;
469
- delete parseResult.options.declarationMap;
470
- return parseResult.options;
471
- }
885
+ const deepkitCache = new _deepkit_type_compiler.Cache();
886
+ function rewriteTypeOnlyImports(source) {
887
+ return source.replaceAll(/\bimport\s+type\s+/g, "import ").replaceAll(/\bexport\s+type\s+\*\s+from/g, "export * from").replaceAll(/\bexport\s+type\s+\{/g, "export {");
888
+ }
889
+ function resolveReflectionConfig(options) {
890
+ return {
891
+ reflection: options.reflection ?? "default",
892
+ exclude: options.exclude
893
+ };
894
+ }
895
+ function getCompilerOptions(options) {
896
+ const cwd = options.cwd || process.cwd();
897
+ const tsconfigPath = options.tsconfig ? (0, _stryke_path_append.appendPath)(options.tsconfig, cwd) : (0, _stryke_path_join.joinPaths)(cwd, "tsconfig.json");
898
+ try {
899
+ const raw = typescript.default.sys.readFile(tsconfigPath);
900
+ if (raw) {
901
+ const parsed = typescript.default.parseConfigFileTextToJson(tsconfigPath, raw);
902
+ if (parsed.config) return {
903
+ ...typescript.default.parseJsonConfigFileContent(parsed.config, typescript.default.sys, (0, _stryke_path_find.findFilePath)(tsconfigPath) || cwd, {}, tsconfigPath).options,
904
+ noEmit: true,
905
+ experimentalDecorators: true,
906
+ emitDecoratorMetadata: true
907
+ };
908
+ }
909
+ } catch {}
472
910
  return {
473
- noEmit: true,
474
- emitDecoratorMetadata: true,
475
- experimentalDecorators: true,
476
911
  target: typescript.default.ScriptTarget.ES2022,
477
912
  module: typescript.default.ModuleKind.ESNext,
478
913
  moduleResolution: typescript.default.ModuleResolutionKind.Bundler,
479
- strictNullChecks: false,
914
+ strictNullChecks: true,
915
+ experimentalDecorators: true,
916
+ emitDecoratorMetadata: true,
480
917
  skipLibCheck: true,
481
- skipDefaultLibCheck: true,
482
918
  esModuleInterop: true,
483
- types: ["node"]
919
+ noEmit: true
484
920
  };
485
921
  }
486
- function getScriptKind(fileName) {
487
- switch ((0, _stryke_path_find.findFileExtensionSafe)(fileName)?.toLowerCase()) {
488
- case "tsx": return typescript.default.ScriptKind.TSX;
489
- case "jsx": return typescript.default.ScriptKind.JSX;
490
- case "js":
491
- case "cjs":
492
- case "mjs": return typescript.default.ScriptKind.JS;
493
- default: return typescript.default.ScriptKind.TS;
922
+ function transpileWithDeepkit(code, fileName, options) {
923
+ const reflectionConfig = resolveReflectionConfig(options);
924
+ deepkitCache.tick();
925
+ return typescript.default.transpileModule(code, {
926
+ compilerOptions: getCompilerOptions(options),
927
+ fileName,
928
+ transformers: {
929
+ before: [(context) => new _deepkit_type_compiler.ReflectionTransformer(context, deepkitCache).withReflection(reflectionConfig)],
930
+ after: [(context) => new _deepkit_type_compiler.DeclarationTransformer(context, deepkitCache).withReflection(reflectionConfig)]
931
+ }
932
+ });
933
+ }
934
+ async function readSourceFile(path, fs) {
935
+ try {
936
+ if (fs?.promises?.readFile) return await fs.promises.readFile(path, "utf8");
937
+ return await (0, node_fs_promises.readFile)(path, "utf8");
938
+ } catch {
939
+ return;
494
940
  }
495
941
  }
496
- /**
497
- * Builds a TypeScript program from original sources collected during the
498
- * esbuild graph walk so type information remains intact for schema generation.
499
- */
500
- function createProgramFromSources(filePath, source, config) {
501
- const compilerOptions = getTsCompilerOptions(config);
502
- const host = typescript.default.createCompilerHost(compilerOptions, true);
503
- const baseFileExists = host.fileExists.bind(host);
504
- const baseReadFile = host.readFile.bind(host);
505
- const baseGetSourceFile = host.getSourceFile.bind(host);
506
- host.fileExists = (name) => filePath === name || baseFileExists(name);
507
- host.readFile = (name) => filePath === name ? source : baseReadFile(name);
508
- host.getSourceFile = (name, languageVersionOrOptions, onError, shouldCreateNewSourceFile) => {
509
- if (filePath === name) {
510
- const scriptTarget = typeof languageVersionOrOptions === "object" ? languageVersionOrOptions.languageVersion : languageVersionOrOptions;
511
- return typescript.default.createSourceFile(name, source, scriptTarget ?? compilerOptions.target ?? typescript.default.ScriptTarget.ES2022, true, getScriptKind(name));
942
+ function createDeepkitPlugin(options) {
943
+ return {
944
+ name: "power-plant:deepkit",
945
+ setup(pluginBuild) {
946
+ pluginBuild.onLoad({ filter: /\.(m|c)?tsx?$/ }, async (args) => {
947
+ if (args.pluginData?.isReflected) {
948
+ const contents = await readSourceFile(args.path, options.fs);
949
+ if (!contents) return null;
950
+ return {
951
+ contents,
952
+ loader: "ts",
953
+ pluginData: { isReflected: true }
954
+ };
955
+ }
956
+ const raw = await readSourceFile(args.path, options.fs);
957
+ if (!raw) return null;
958
+ const result = transpileWithDeepkit(rewriteTypeOnlyImports(raw), args.path, options);
959
+ if (result.diagnostics?.length) {
960
+ const errors = result.diagnostics.filter((diagnostic) => diagnostic.category === typescript.DiagnosticCategory.Error);
961
+ if (errors.length > 0) {
962
+ const errorMessage = `Deepkit Type reflection transpilation errors: ${args.path} \n ${errors.map((diagnostic) => `-${diagnostic.file ? `${diagnostic.file.fileName}:` : ""} ${typeof diagnostic.messageText === "string" ? diagnostic.messageText : diagnostic.messageText.messageText} (at ${diagnostic.start}:${diagnostic.length})`).join("\n")}`;
963
+ options.logger?.error?.(errorMessage);
964
+ throw new Error(errorMessage);
965
+ }
966
+ }
967
+ return {
968
+ contents: result.outputText,
969
+ loader: "ts",
970
+ pluginData: { isReflected: true }
971
+ };
972
+ });
512
973
  }
513
- return baseGetSourceFile(name, languageVersionOrOptions, onError, shouldCreateNewSourceFile);
514
974
  };
515
- const program = typescript.default.createProgram([filePath], compilerOptions, host);
516
- if (!config.skipTypeCheck) {
517
- const diagnostics = typescript.default.getPreEmitDiagnostics(program);
518
- if (diagnostics.length) throw new Error(`Type check error: ${diagnostics.map((diagnostic) => diagnostic.messageText.toString()).join("\n")}`);
519
- }
520
- return program;
521
975
  }
522
976
  /**
523
- * Resolves a type definition to a JSON Schema. First bundles the TypeScript
524
- * module graph for {@link FileReference.file} with esbuild (preserving original
525
- * sources), then feeds that program to
526
- * [ts-json-schema-generator](https://github.com/vega/ts-json-schema-generator)
527
- * using the referenced export name as the target type when one is provided.
977
+ * Resolves a type definition to a JSON Schema. Bundles the TypeScript module
978
+ * graph with esbuild using `@deepkit/type-compiler` reflection transformers,
979
+ * then converts the reflected Deepkit {@link Type} via {@link reflectionToJsonSchema}.
528
980
  *
529
981
  * @param input - The type definition to compile. This can be either a string or a {@link FileReference} object.
530
- * @param options - Optional overrides reserved for API compatibility.
982
+ * @param options - Optional overrides for reflection and file resolution.
531
983
  * @returns A promise that resolves to the generated JSON Schema.
984
+ * @see https://deepkit.io/en/documentation/runtime-types/reflection
532
985
  */
533
986
  async function extractTSType(input, options = {}) {
534
987
  const fileReference = (0, _stryke_convert_extract_file_reference.extractFileReference)(input);
535
988
  if (!fileReference) throw new Error(`Failed to extract a file reference from the provided input. The input must be a string or an object with a "file" property that specifies the file path and optional export name.`);
536
- const exportName = fileReference.export ?? "*";
989
+ const exportName = fileReference.export ?? "default";
537
990
  const resolvedPath = await (0, _stryke_fs_resolve.resolveSafe)(fileReference.file, { fs: options.fs });
538
991
  const filePath = resolvedPath || fileReference.file;
992
+ const cwd = options.cwd || process.cwd();
539
993
  try {
540
- const tsconfig = options.tsconfig ? (0, _stryke_path_append.appendPath)(options.tsconfig, options.cwd || process.cwd()) : (0, _stryke_path_join.joinPaths)(options.cwd || process.cwd(), "tsconfig.json");
541
- const bundled = await (0, _stryke_resolve_resolve.resolve)(filePath, {
542
- cwd: options.cwd || process.cwd(),
543
- fs: options.fs
544
- });
545
994
  options.logger?.debug?.(`Generating JSON schema for bundled "${filePath}" using the type "${exportName}"`);
546
- const config = {
547
- ...ts_json_schema_generator_dist_src_Config_js.DEFAULT_CONFIG,
548
- expose: "all",
549
- jsDoc: "extended",
550
- markdownDescription: true,
551
- fullDescription: true,
552
- ...options,
553
- tsconfig,
554
- path: filePath,
555
- type: exportName,
556
- skipTypeCheck: true,
557
- functions: "schema"
558
- };
559
- const tsProgram = createProgramFromSources(filePath, bundled, config);
560
- return (0, ts_json_schema_generator_dist_factory_generator_js.createGenerator)({
561
- ...config,
562
- tsProgram
563
- }).createSchema(exportName);
995
+ const result = await (0, esbuild.build)({
996
+ platform: "node",
997
+ format: "esm",
998
+ logLevel: "silent",
999
+ entryPoints: [filePath],
1000
+ write: false,
1001
+ sourcemap: false,
1002
+ splitting: false,
1003
+ treeShaking: true,
1004
+ bundle: true,
1005
+ packages: "bundle",
1006
+ keepNames: true,
1007
+ metafile: false,
1008
+ absWorkingDir: cwd,
1009
+ plugins: [createDeepkitPlugin(options)]
1010
+ });
1011
+ if (result.errors.length > 0) throw new Error(result.errors.map((error) => error.text).join(", "));
1012
+ const bundled = result.outputFiles?.filter(Boolean)[0]?.text;
1013
+ if (!(0, _stryke_type_checks.isSetString)(bundled)) throw new Error(`No output files generated for "${filePath}". Please check the configuration and try again.`);
1014
+ const evaluated = await (0, jiti.createJiti)(cwd).evalModule(bundled, {
1015
+ filename: filePath,
1016
+ ext: (0, _stryke_path_find.findFileDotExtensionSafe)(filePath) || ".ts"
1017
+ });
1018
+ let resolved = evaluated[exportName] ?? evaluated[`__Ω${exportName}`];
1019
+ if (resolved === void 0) throw new Error(`The export "${exportName}" could not be resolved in the "${filePath}" module. ${Object.keys(evaluated).length === 0 ? `After bundling, no exports were found in the module.` : `After bundling, the available exports were: ${Object.keys(evaluated).join(", ")}.`}`);
1020
+ try {
1021
+ const type = (0, _deepkit_type.reflect)(resolved);
1022
+ if ((0, _deepkit_type.isType)(type)) resolved = type;
1023
+ } catch {}
1024
+ if ((0, _deepkit_type.isType)(resolved)) {
1025
+ const schema = extractReflection(resolved);
1026
+ if (!schema) throw new Error(`Failed to convert the reflected Deepkit type for "${exportName}" to JSON Schema.`);
1027
+ return schema;
1028
+ }
1029
+ const schema = extractJsonSchema(resolved);
1030
+ if (!schema) throw new Error(`The export "${exportName}" could not be converted to a JSON Schema.`);
1031
+ return schema;
564
1032
  } catch (error) {
565
1033
  throw new Error(`Failed to generate a JSON schema for "${fileReference.file}"${resolvedPath && resolvedPath !== fileReference.file ? ` (resolved: ${resolvedPath})` : ""} using the type "${exportName}". Error: ${error.message}`);
566
1034
  }
567
1035
  }
568
1036
  /**
569
- * Extracts a JSON Schema from a given schema definition input, which can be a Zod schema, a Valibot schema, any Standard JSON Schema type, a plain JSON Schema object, an untyped schema, or a {@link FileReferenceInput} to an exported TypeScript type definition or any of the previous options. If the input is a {@link FileReferenceInput} (e.g. a file path with an export), the source code will be bundled with [esbuild](esbuild.github.io) using [ts-json-schema-generator](https://github.com/vega/ts-json-schema-generator) to obtain the actual schema definition before extraction.
1037
+ * Extracts a JSON Schema from a given schema definition input, which can be a Zod schema, a Valibot schema, any Standard JSON Schema type, a plain JSON Schema object, an untyped schema, a Deepkit Type object, or a {@link FileReferenceInput} to an exported TypeScript type definition or any of the previous options. If the input is a {@link FileReferenceInput} (e.g. a file path with an export), the source code will be bundled with [esbuild](https://esbuild.github.io) using [@deepkit/type-compiler](https://deepkit.io/en/documentation/runtime-types/getting-started) reflection to obtain the actual schema definition before extraction.
570
1038
  *
571
1039
  * @example
572
1040
  * ```ts
@@ -580,8 +1048,8 @@ async function extractTSType(input, options = {}) {
580
1048
  * const schema4 = await extract(context, zodSchema);
581
1049
  * // Resolve a schema definition from a Valibot schema
582
1050
  * const schema5 = await extract(context, valibotSchema);
583
- * // Resolve a schema definition from an untyped schema
584
- * const schema6 = await extract(context, untypedSchema);
1051
+ * // Resolve a schema definition from a reflected Deepkit Type object
1052
+ * const schema6 = await extract(context, reflectionType);
585
1053
  * ```
586
1054
  *
587
1055
  * @see https://zod.dev/
@@ -589,7 +1057,7 @@ async function extractTSType(input, options = {}) {
589
1057
  * @see https://standardschema.dev/json-schema#what-schema-libraries-support-this-spec
590
1058
  * @see https://json-schema.org/
591
1059
  * @see https://ajv.js.org/json-type-definition.html
592
- * @see https://github.com/vega/ts-json-schema-generator
1060
+ * @see https://deepkit.io/en/documentation/runtime-types/reflection
593
1061
  * @see https://github.com/unjs/untyped
594
1062
  * @see https://www.typescriptlang.org/docs/handbook/2/types-from-types.html
595
1063
  *
@@ -620,13 +1088,22 @@ async function extractSchemaWithSource(input, options = {}) {
620
1088
  let fs;
621
1089
  if (options.storage) fs = require_storage.mapStorageToFileSystem(options.storage);
622
1090
  let resolved = await (0, _stryke_resolve_load.loadSafe)(unwrappedConfig, {
623
- ...options,
624
- fs
1091
+ ...(0, _stryke_helpers_omit.omit)(options, [
1092
+ "storage",
1093
+ "logger",
1094
+ "tsconfig"
1095
+ ]),
1096
+ fs,
1097
+ cwd: options.cwd ?? void 0
625
1098
  });
626
1099
  resolved ??= await extractTSType(unwrappedConfig, {
627
1100
  ...options,
628
1101
  fs
629
1102
  });
1103
+ try {
1104
+ const type = (0, _deepkit_type.reflect)(resolved);
1105
+ if ((0, _deepkit_type.isType)(type)) resolved = type;
1106
+ } catch {}
630
1107
  const resolvedConfig = unwrapSchemaConfig(resolved);
631
1108
  if (require_helpers.isSchemaWithSource(resolvedConfig)) source = resolvedConfig.source;
632
1109
  else if (require_helpers.isSchema(resolvedConfig)) source = {
@@ -652,7 +1129,7 @@ async function extractSchemaWithSource(input, options = {}) {
652
1129
  };
653
1130
  }
654
1131
  /**
655
- * Extracts a JSON Schema from a given schema definition input, which can be a Zod schema, a Valibot schema, any Standard JSON Schema type, a plain JSON Schema object, an untyped schema, or a {@link FileReferenceInput} to an exported TypeScript type definition or any of the previous options. If the input is a {@link FileReferenceInput} (e.g. a file path with an export), the source code will be bundled with [esbuild](esbuild.github.io) using [ts-json-schema-generator](https://github.com/vega/ts-json-schema-generator) to obtain the actual schema definition before extraction.
1132
+ * Extracts a JSON Schema from a given schema definition input, which can be a Zod schema, a Valibot schema, any Standard JSON Schema type, a plain JSON Schema object, an untyped schema, a Deepkit Type object, or a {@link FileReferenceInput} to an exported TypeScript type definition or any of the previous options. If the input is a {@link FileReferenceInput} (e.g. a file path with an export), the source code will be bundled with [esbuild](https://esbuild.github.io) using [@deepkit/type-compiler](https://deepkit.io/en/documentation/runtime-types/getting-started) reflection to obtain the actual schema definition before extraction.
656
1133
  *
657
1134
  * @example
658
1135
  * ```ts
@@ -666,8 +1143,8 @@ async function extractSchemaWithSource(input, options = {}) {
666
1143
  * const schema4 = await extract(context, zodSchema);
667
1144
  * // Resolve a schema definition from a Valibot schema
668
1145
  * const schema5 = await extract(context, valibotSchema);
669
- * // Resolve a schema definition from an untyped schema
670
- * const schema6 = await extract(context, untypedSchema);
1146
+ * // Resolve a schema definition from a reflected Deepkit Type object
1147
+ * const schema6 = await extract(context, reflectionType);
671
1148
  * ```
672
1149
  *
673
1150
  * @see https://zod.dev/
@@ -675,7 +1152,7 @@ async function extractSchemaWithSource(input, options = {}) {
675
1152
  * @see https://standardschema.dev/json-schema#what-schema-libraries-support-this-spec
676
1153
  * @see https://json-schema.org/
677
1154
  * @see https://ajv.js.org/json-type-definition.html
678
- * @see https://github.com/vega/ts-json-schema-generator
1155
+ * @see https://deepkit.io/en/documentation/runtime-types/reflection
679
1156
  * @see https://github.com/unjs/untyped
680
1157
  * @see https://www.typescriptlang.org/docs/handbook/2/types-from-types.html
681
1158
  *
@@ -709,6 +1186,7 @@ exports.createStoragePromises = require_storage.createStoragePromises;
709
1186
  exports.extract = extract;
710
1187
  exports.extractHash = extractHash;
711
1188
  exports.extractJsonSchema = extractJsonSchema;
1189
+ exports.extractReflection = extractReflection;
712
1190
  exports.extractResolvedVariant = extractResolvedVariant;
713
1191
  exports.extractSchema = extractSchema;
714
1192
  exports.extractSchemaWithSource = extractSchemaWithSource;