@effect/platform 0.70.5 → 0.70.7
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/cjs/OpenApi.js +1 -2
- package/dist/cjs/OpenApi.js.map +1 -1
- package/dist/cjs/OpenApiJsonSchema.js +18 -477
- package/dist/cjs/OpenApiJsonSchema.js.map +1 -1
- package/dist/cjs/Socket.js +1 -1
- package/dist/cjs/Socket.js.map +1 -1
- package/dist/dts/OpenApi.d.ts.map +1 -1
- package/dist/dts/OpenApiJsonSchema.d.ts +34 -5
- package/dist/dts/OpenApiJsonSchema.d.ts.map +1 -1
- package/dist/dts/Socket.d.ts.map +1 -1
- package/dist/esm/OpenApi.js +1 -2
- package/dist/esm/OpenApi.js.map +1 -1
- package/dist/esm/OpenApiJsonSchema.js +18 -477
- package/dist/esm/OpenApiJsonSchema.js.map +1 -1
- package/dist/esm/Socket.js +1 -1
- package/dist/esm/Socket.js.map +1 -1
- package/package.json +2 -2
- package/src/OpenApi.ts +1 -2
- package/src/OpenApiJsonSchema.ts +45 -513
- package/src/Socket.ts +3 -1
package/src/OpenApi.ts
CHANGED
|
@@ -171,8 +171,7 @@ export const fromApi = <A extends HttpApi.HttpApi.Any>(self: A): OpenAPISpec =>
|
|
|
171
171
|
}
|
|
172
172
|
function makeJsonSchemaOrRef(schema: Schema.Schema.All): JsonSchema.JsonSchema {
|
|
173
173
|
return JsonSchema.makeWithDefs(schema as any, {
|
|
174
|
-
defs: jsonSchemaDefs
|
|
175
|
-
defsPath: "#/components/schemas/"
|
|
174
|
+
defs: jsonSchemaDefs
|
|
176
175
|
})
|
|
177
176
|
}
|
|
178
177
|
function registerSecurity(
|
package/src/OpenApiJsonSchema.ts
CHANGED
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @since 1.0.0
|
|
3
3
|
*/
|
|
4
|
-
import * as
|
|
5
|
-
import * as Option from "effect/Option"
|
|
6
|
-
import type * as ParseResult from "effect/ParseResult"
|
|
7
|
-
import * as Predicate from "effect/Predicate"
|
|
4
|
+
import * as JSONSchema from "effect/JSONSchema"
|
|
8
5
|
import * as Record from "effect/Record"
|
|
9
6
|
import type * as Schema from "effect/Schema"
|
|
10
|
-
import * as AST from "effect/SchemaAST"
|
|
7
|
+
import type * as AST from "effect/SchemaAST"
|
|
11
8
|
|
|
12
9
|
/**
|
|
13
10
|
* @category model
|
|
@@ -20,6 +17,15 @@ export interface Annotations {
|
|
|
20
17
|
examples?: globalThis.Array<unknown>
|
|
21
18
|
}
|
|
22
19
|
|
|
20
|
+
/**
|
|
21
|
+
* @category model
|
|
22
|
+
* @since 1.0.0
|
|
23
|
+
*/
|
|
24
|
+
export interface Never extends Annotations {
|
|
25
|
+
$id: "/schemas/never"
|
|
26
|
+
not: {}
|
|
27
|
+
}
|
|
28
|
+
|
|
23
29
|
/**
|
|
24
30
|
* @category model
|
|
25
31
|
* @since 1.0.0
|
|
@@ -86,9 +92,13 @@ export interface String extends Annotations {
|
|
|
86
92
|
maxLength?: number
|
|
87
93
|
pattern?: string
|
|
88
94
|
format?: string
|
|
89
|
-
contentEncoding?: string
|
|
90
95
|
contentMediaType?: string
|
|
91
96
|
contentSchema?: JsonSchema
|
|
97
|
+
allOf?: globalThis.Array<{
|
|
98
|
+
minLength?: number
|
|
99
|
+
maxLength?: number
|
|
100
|
+
pattern?: string
|
|
101
|
+
}>
|
|
92
102
|
}
|
|
93
103
|
|
|
94
104
|
/**
|
|
@@ -100,7 +110,15 @@ export interface Numeric extends Annotations {
|
|
|
100
110
|
exclusiveMinimum?: number
|
|
101
111
|
maximum?: number
|
|
102
112
|
exclusiveMaximum?: number
|
|
113
|
+
multipleOf?: number
|
|
103
114
|
format?: string
|
|
115
|
+
allOf?: globalThis.Array<{
|
|
116
|
+
minimum?: number
|
|
117
|
+
exclusiveMinimum?: number
|
|
118
|
+
maximum?: number
|
|
119
|
+
exclusiveMaximum?: number
|
|
120
|
+
multipleOf?: number
|
|
121
|
+
}>
|
|
104
122
|
}
|
|
105
123
|
|
|
106
124
|
/**
|
|
@@ -185,6 +203,7 @@ export interface Object extends Annotations {
|
|
|
185
203
|
* @since 0.71.0
|
|
186
204
|
*/
|
|
187
205
|
export type JsonSchema =
|
|
206
|
+
| Never
|
|
188
207
|
| Any
|
|
189
208
|
| Unknown
|
|
190
209
|
| Void
|
|
@@ -214,522 +233,35 @@ export type Root = JsonSchema & {
|
|
|
214
233
|
* @since 1.0.0
|
|
215
234
|
*/
|
|
216
235
|
export const make = <A, I, R>(schema: Schema.Schema<A, I, R>): Root => {
|
|
217
|
-
const
|
|
218
|
-
const out = makeWithDefs(schema, { defs
|
|
219
|
-
if (!Record.isEmptyRecord(
|
|
220
|
-
out.$defs =
|
|
236
|
+
const defs: Record<string, JsonSchema> = {}
|
|
237
|
+
const out: Root = makeWithDefs(schema, { defs })
|
|
238
|
+
if (!Record.isEmptyRecord(defs)) {
|
|
239
|
+
out.$defs = defs
|
|
221
240
|
}
|
|
222
241
|
return out
|
|
223
242
|
}
|
|
224
243
|
|
|
225
244
|
/**
|
|
245
|
+
* Creates a schema with additional options and definitions.
|
|
246
|
+
*
|
|
247
|
+
* - `defs`: A record of definitions that are included in the schema.
|
|
248
|
+
* - `defsPath`: The path to the definitions within the schema (defaults to "#/$defs/").
|
|
249
|
+
* - `topLevelReferenceStrategy`: Controls the handling of the top-level reference. Possible values are:
|
|
250
|
+
* - `"keep"`: Keep the top-level reference (default behavior).
|
|
251
|
+
* - `"skip"`: Skip the top-level reference.
|
|
252
|
+
*
|
|
226
253
|
* @category encoding
|
|
227
254
|
* @since 1.0.0
|
|
228
255
|
*/
|
|
229
256
|
export const makeWithDefs = <A, I, R>(schema: Schema.Schema<A, I, R>, options: {
|
|
230
|
-
readonly defs: Record<string,
|
|
257
|
+
readonly defs: Record<string, JsonSchema>
|
|
231
258
|
readonly defsPath?: string
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
return out
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
const constAny: JsonSchema = { $id: "/schemas/any" }
|
|
245
|
-
|
|
246
|
-
const constUnknown: JsonSchema = { $id: "/schemas/unknown" }
|
|
247
|
-
|
|
248
|
-
const constVoid: JsonSchema = { $id: "/schemas/void" }
|
|
249
|
-
|
|
250
|
-
const constAnyObject: JsonSchema = {
|
|
251
|
-
"$id": "/schemas/object",
|
|
252
|
-
"anyOf": [
|
|
253
|
-
{ "type": "object" },
|
|
254
|
-
{ "type": "array" }
|
|
255
|
-
]
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
const constEmpty: JsonSchema = {
|
|
259
|
-
"$id": "/schemas/{}",
|
|
260
|
-
"anyOf": [
|
|
261
|
-
{ "type": "object" },
|
|
262
|
-
{ "type": "array" }
|
|
263
|
-
]
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
const getJsonSchemaAnnotations = (annotated: AST.Annotated): Annotations =>
|
|
267
|
-
Record.getSomes({
|
|
268
|
-
description: AST.getDescriptionAnnotation(annotated),
|
|
269
|
-
title: AST.getTitleAnnotation(annotated),
|
|
270
|
-
examples: AST.getExamplesAnnotation(annotated),
|
|
271
|
-
default: AST.getDefaultAnnotation(annotated)
|
|
259
|
+
readonly topLevelReferenceStrategy?: "skip" | "keep"
|
|
260
|
+
}): JsonSchema => {
|
|
261
|
+
return JSONSchema.fromAST(schema.ast, {
|
|
262
|
+
definitions: options.defs,
|
|
263
|
+
definitionPath: options.defsPath ?? "#/components/schemas/",
|
|
264
|
+
target: "openApi3.1",
|
|
265
|
+
topLevelReferenceStrategy: options.topLevelReferenceStrategy ?? "keep"
|
|
272
266
|
})
|
|
273
|
-
|
|
274
|
-
const removeDefaultJsonSchemaAnnotations = (
|
|
275
|
-
jsonSchemaAnnotations: Annotations,
|
|
276
|
-
ast: AST.AST
|
|
277
|
-
): Annotations => {
|
|
278
|
-
if (jsonSchemaAnnotations["title"] === ast.annotations[AST.TitleAnnotationId]) {
|
|
279
|
-
delete jsonSchemaAnnotations["title"]
|
|
280
|
-
}
|
|
281
|
-
if (jsonSchemaAnnotations["description"] === ast.annotations[AST.DescriptionAnnotationId]) {
|
|
282
|
-
delete jsonSchemaAnnotations["description"]
|
|
283
|
-
}
|
|
284
|
-
return jsonSchemaAnnotations
|
|
285
267
|
}
|
|
286
|
-
|
|
287
|
-
const getASTJsonSchemaAnnotations = (ast: AST.AST): Annotations => {
|
|
288
|
-
const jsonSchemaAnnotations = getJsonSchemaAnnotations(ast)
|
|
289
|
-
switch (ast._tag) {
|
|
290
|
-
case "StringKeyword":
|
|
291
|
-
return removeDefaultJsonSchemaAnnotations(jsonSchemaAnnotations, AST.stringKeyword)
|
|
292
|
-
case "NumberKeyword":
|
|
293
|
-
return removeDefaultJsonSchemaAnnotations(jsonSchemaAnnotations, AST.numberKeyword)
|
|
294
|
-
case "BooleanKeyword":
|
|
295
|
-
return removeDefaultJsonSchemaAnnotations(jsonSchemaAnnotations, AST.booleanKeyword)
|
|
296
|
-
default:
|
|
297
|
-
return jsonSchemaAnnotations
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
const pruneUndefinedFromPropertySignature = (ast: AST.AST): AST.AST | undefined => {
|
|
302
|
-
if (Option.isNone(AST.getJSONSchemaAnnotation(ast))) {
|
|
303
|
-
switch (ast._tag) {
|
|
304
|
-
case "Union": {
|
|
305
|
-
const types = ast.types.filter((type) => !AST.isUndefinedKeyword(type))
|
|
306
|
-
if (types.length < ast.types.length) {
|
|
307
|
-
return AST.Union.make(types, ast.annotations)
|
|
308
|
-
}
|
|
309
|
-
break
|
|
310
|
-
}
|
|
311
|
-
case "Transformation":
|
|
312
|
-
return pruneUndefinedFromPropertySignature(isParseJsonTransformation(ast.from) ? ast.to : ast.from)
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
const getRefinementInnerTransformation = (ast: AST.Refinement): AST.AST | undefined => {
|
|
318
|
-
switch (ast.from._tag) {
|
|
319
|
-
case "Transformation":
|
|
320
|
-
return ast.from
|
|
321
|
-
case "Refinement":
|
|
322
|
-
return getRefinementInnerTransformation(ast.from)
|
|
323
|
-
case "Suspend": {
|
|
324
|
-
const from = ast.from.f()
|
|
325
|
-
if (AST.isRefinement(from)) {
|
|
326
|
-
return getRefinementInnerTransformation(from)
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
const isParseJsonTransformation = (ast: AST.AST): boolean =>
|
|
333
|
-
ast.annotations[AST.SchemaIdAnnotationId] === AST.ParseJsonSchemaId
|
|
334
|
-
|
|
335
|
-
const isOverrideAnnotation = (jsonSchema: JsonSchema): boolean => {
|
|
336
|
-
return ("type" in jsonSchema) || ("oneOf" in jsonSchema) || ("anyOf" in jsonSchema) || ("const" in jsonSchema) ||
|
|
337
|
-
("enum" in jsonSchema) || ("$ref" in jsonSchema)
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
const go = (
|
|
341
|
-
ast: AST.AST,
|
|
342
|
-
$defs: Record<string, JsonSchema>,
|
|
343
|
-
handleIdentifier: boolean,
|
|
344
|
-
path: ReadonlyArray<PropertyKey>,
|
|
345
|
-
options: {
|
|
346
|
-
readonly getRef: (id: string) => string
|
|
347
|
-
}
|
|
348
|
-
): JsonSchema => {
|
|
349
|
-
const hook = AST.getJSONSchemaAnnotation(ast)
|
|
350
|
-
if (Option.isSome(hook)) {
|
|
351
|
-
const handler = hook.value as JsonSchema
|
|
352
|
-
if (AST.isRefinement(ast)) {
|
|
353
|
-
const t = getRefinementInnerTransformation(ast)
|
|
354
|
-
if (t === undefined) {
|
|
355
|
-
try {
|
|
356
|
-
return {
|
|
357
|
-
...go(ast.from, $defs, true, path, options),
|
|
358
|
-
...getJsonSchemaAnnotations(ast),
|
|
359
|
-
...handler
|
|
360
|
-
}
|
|
361
|
-
} catch (e) {
|
|
362
|
-
return {
|
|
363
|
-
...getJsonSchemaAnnotations(ast),
|
|
364
|
-
...handler
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
} else if (!isOverrideAnnotation(handler)) {
|
|
368
|
-
return {
|
|
369
|
-
...go(t, $defs, true, path, options),
|
|
370
|
-
...getJsonSchemaAnnotations(ast)
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
return handler
|
|
375
|
-
}
|
|
376
|
-
const surrogate = AST.getSurrogateAnnotation(ast)
|
|
377
|
-
if (handleIdentifier && !AST.isRefinement(ast)) {
|
|
378
|
-
const identifier = AST.getJSONIdentifier(
|
|
379
|
-
Option.isSome(surrogate) ?
|
|
380
|
-
{
|
|
381
|
-
annotations: {
|
|
382
|
-
...(ast._tag === "Transformation" ? ast.to.annotations : {}),
|
|
383
|
-
...ast.annotations
|
|
384
|
-
}
|
|
385
|
-
} :
|
|
386
|
-
ast
|
|
387
|
-
)
|
|
388
|
-
if (Option.isSome(identifier)) {
|
|
389
|
-
const id = identifier.value
|
|
390
|
-
const out = { $ref: options.getRef(id) }
|
|
391
|
-
if (!Record.has($defs, id)) {
|
|
392
|
-
$defs[id] = out
|
|
393
|
-
$defs[id] = go(ast, $defs, false, path, options)
|
|
394
|
-
}
|
|
395
|
-
return out
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
if (Option.isSome(surrogate)) {
|
|
399
|
-
return {
|
|
400
|
-
...go(surrogate.value, $defs, handleIdentifier, path, options),
|
|
401
|
-
...(ast._tag === "Transformation" ? getJsonSchemaAnnotations(ast.to) : {}),
|
|
402
|
-
...getJsonSchemaAnnotations(ast)
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
switch (ast._tag) {
|
|
406
|
-
case "Declaration":
|
|
407
|
-
throw new Error(getJSONSchemaMissingAnnotationErrorMessage(path, ast))
|
|
408
|
-
case "Literal": {
|
|
409
|
-
const literal = ast.literal
|
|
410
|
-
if (literal === null) {
|
|
411
|
-
return {
|
|
412
|
-
enum: [null],
|
|
413
|
-
...getJsonSchemaAnnotations(ast)
|
|
414
|
-
}
|
|
415
|
-
} else if (Predicate.isString(literal) || Predicate.isNumber(literal) || Predicate.isBoolean(literal)) {
|
|
416
|
-
return {
|
|
417
|
-
enum: [literal],
|
|
418
|
-
...getJsonSchemaAnnotations(ast)
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
throw new Error(getJSONSchemaMissingAnnotationErrorMessage(path, ast))
|
|
422
|
-
}
|
|
423
|
-
case "UniqueSymbol":
|
|
424
|
-
throw new Error(getJSONSchemaMissingAnnotationErrorMessage(path, ast))
|
|
425
|
-
case "UndefinedKeyword":
|
|
426
|
-
throw new Error(getJSONSchemaMissingAnnotationErrorMessage(path, ast))
|
|
427
|
-
case "VoidKeyword":
|
|
428
|
-
return {
|
|
429
|
-
...constVoid,
|
|
430
|
-
...getJsonSchemaAnnotations(ast)
|
|
431
|
-
}
|
|
432
|
-
case "NeverKeyword":
|
|
433
|
-
throw new Error(getJSONSchemaMissingAnnotationErrorMessage(path, ast))
|
|
434
|
-
case "UnknownKeyword":
|
|
435
|
-
return {
|
|
436
|
-
...constUnknown,
|
|
437
|
-
...getJsonSchemaAnnotations(ast)
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
case "AnyKeyword":
|
|
441
|
-
return {
|
|
442
|
-
...constAny,
|
|
443
|
-
...getJsonSchemaAnnotations(ast)
|
|
444
|
-
}
|
|
445
|
-
case "ObjectKeyword":
|
|
446
|
-
return {
|
|
447
|
-
...constAnyObject,
|
|
448
|
-
...getJsonSchemaAnnotations(ast)
|
|
449
|
-
}
|
|
450
|
-
case "StringKeyword":
|
|
451
|
-
return { type: "string", ...getASTJsonSchemaAnnotations(ast) }
|
|
452
|
-
case "NumberKeyword":
|
|
453
|
-
return { type: "number", ...getASTJsonSchemaAnnotations(ast) }
|
|
454
|
-
case "BooleanKeyword":
|
|
455
|
-
return { type: "boolean", ...getASTJsonSchemaAnnotations(ast) }
|
|
456
|
-
case "BigIntKeyword":
|
|
457
|
-
throw new Error(getJSONSchemaMissingAnnotationErrorMessage(path, ast))
|
|
458
|
-
case "SymbolKeyword":
|
|
459
|
-
throw new Error(getJSONSchemaMissingAnnotationErrorMessage(path, ast))
|
|
460
|
-
case "TupleType": {
|
|
461
|
-
const elements = ast.elements.map((e, i) => ({
|
|
462
|
-
...go(e.type, $defs, true, path.concat(i), options),
|
|
463
|
-
...getJsonSchemaAnnotations(e)
|
|
464
|
-
}))
|
|
465
|
-
const rest = ast.rest.map((annotatedAST) => ({
|
|
466
|
-
...go(annotatedAST.type, $defs, true, path, options),
|
|
467
|
-
...getJsonSchemaAnnotations(annotatedAST)
|
|
468
|
-
}))
|
|
469
|
-
const output: Array = { type: "array" }
|
|
470
|
-
// ---------------------------------------------
|
|
471
|
-
// handle elements
|
|
472
|
-
// ---------------------------------------------
|
|
473
|
-
const len = ast.elements.length
|
|
474
|
-
if (len > 0) {
|
|
475
|
-
output.minItems = len - ast.elements.filter((element) => element.isOptional).length
|
|
476
|
-
output.items = elements
|
|
477
|
-
}
|
|
478
|
-
// ---------------------------------------------
|
|
479
|
-
// handle rest element
|
|
480
|
-
// ---------------------------------------------
|
|
481
|
-
const restLength = rest.length
|
|
482
|
-
if (restLength > 0) {
|
|
483
|
-
const head = rest[0]
|
|
484
|
-
const isHomogeneous = restLength === 1 && ast.elements.every((e) => e.type === ast.rest[0].type)
|
|
485
|
-
if (isHomogeneous) {
|
|
486
|
-
output.items = head
|
|
487
|
-
} else {
|
|
488
|
-
output.additionalItems = head
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
// ---------------------------------------------
|
|
492
|
-
// handle post rest elements
|
|
493
|
-
// ---------------------------------------------
|
|
494
|
-
if (restLength > 1) {
|
|
495
|
-
throw new Error(getJSONSchemaUnsupportedPostRestElementsErrorMessage(path))
|
|
496
|
-
}
|
|
497
|
-
} else {
|
|
498
|
-
if (len > 0) {
|
|
499
|
-
output.additionalItems = false
|
|
500
|
-
} else {
|
|
501
|
-
output.maxItems = 0
|
|
502
|
-
}
|
|
503
|
-
}
|
|
504
|
-
|
|
505
|
-
return {
|
|
506
|
-
...output,
|
|
507
|
-
...getJsonSchemaAnnotations(ast)
|
|
508
|
-
}
|
|
509
|
-
}
|
|
510
|
-
case "TypeLiteral": {
|
|
511
|
-
if (ast.propertySignatures.length === 0 && ast.indexSignatures.length === 0) {
|
|
512
|
-
return {
|
|
513
|
-
...constEmpty,
|
|
514
|
-
...getJsonSchemaAnnotations(ast)
|
|
515
|
-
}
|
|
516
|
-
}
|
|
517
|
-
let patternProperties: JsonSchema | undefined = undefined
|
|
518
|
-
let propertyNames: JsonSchema | undefined = undefined
|
|
519
|
-
for (const is of ast.indexSignatures) {
|
|
520
|
-
const parameter = is.parameter
|
|
521
|
-
switch (parameter._tag) {
|
|
522
|
-
case "StringKeyword": {
|
|
523
|
-
patternProperties = go(is.type, $defs, true, path, options)
|
|
524
|
-
break
|
|
525
|
-
}
|
|
526
|
-
case "TemplateLiteral": {
|
|
527
|
-
patternProperties = go(is.type, $defs, true, path, options)
|
|
528
|
-
propertyNames = {
|
|
529
|
-
type: "string",
|
|
530
|
-
pattern: AST.getTemplateLiteralRegExp(parameter).source
|
|
531
|
-
}
|
|
532
|
-
break
|
|
533
|
-
}
|
|
534
|
-
case "Refinement": {
|
|
535
|
-
patternProperties = go(is.type, $defs, true, path, options)
|
|
536
|
-
propertyNames = go(parameter, $defs, true, path, options)
|
|
537
|
-
break
|
|
538
|
-
}
|
|
539
|
-
case "SymbolKeyword":
|
|
540
|
-
throw new Error(getJSONSchemaUnsupportedParameterErrorMessage(path, parameter))
|
|
541
|
-
}
|
|
542
|
-
}
|
|
543
|
-
const output: Object = {
|
|
544
|
-
type: "object",
|
|
545
|
-
required: [],
|
|
546
|
-
properties: {},
|
|
547
|
-
additionalProperties: false
|
|
548
|
-
}
|
|
549
|
-
// ---------------------------------------------
|
|
550
|
-
// handle property signatures
|
|
551
|
-
// ---------------------------------------------
|
|
552
|
-
for (let i = 0; i < ast.propertySignatures.length; i++) {
|
|
553
|
-
const ps = ast.propertySignatures[i]
|
|
554
|
-
const name = ps.name
|
|
555
|
-
if (Predicate.isString(name)) {
|
|
556
|
-
const pruned = pruneUndefinedFromPropertySignature(ps.type)
|
|
557
|
-
output.properties[name] = {
|
|
558
|
-
...go(pruned ? pruned : ps.type, $defs, true, path.concat(ps.name), options),
|
|
559
|
-
...getJsonSchemaAnnotations(ps)
|
|
560
|
-
}
|
|
561
|
-
// ---------------------------------------------
|
|
562
|
-
// handle optional property signatures
|
|
563
|
-
// ---------------------------------------------
|
|
564
|
-
if (!ps.isOptional && pruned === undefined) {
|
|
565
|
-
output.required.push(name)
|
|
566
|
-
}
|
|
567
|
-
} else {
|
|
568
|
-
throw new Error(getJSONSchemaUnsupportedKeyErrorMessage(name, path))
|
|
569
|
-
}
|
|
570
|
-
}
|
|
571
|
-
// ---------------------------------------------
|
|
572
|
-
// handle index signatures
|
|
573
|
-
// ---------------------------------------------
|
|
574
|
-
if (patternProperties !== undefined) {
|
|
575
|
-
delete output.additionalProperties
|
|
576
|
-
output.patternProperties = { "": patternProperties }
|
|
577
|
-
}
|
|
578
|
-
if (propertyNames !== undefined) {
|
|
579
|
-
output.propertyNames = propertyNames
|
|
580
|
-
}
|
|
581
|
-
|
|
582
|
-
return {
|
|
583
|
-
...output,
|
|
584
|
-
...getJsonSchemaAnnotations(ast)
|
|
585
|
-
}
|
|
586
|
-
}
|
|
587
|
-
case "Union": {
|
|
588
|
-
const enums: globalThis.Array<AST.LiteralValue> = []
|
|
589
|
-
const anyOf: globalThis.Array<JsonSchema> = []
|
|
590
|
-
for (const type of ast.types) {
|
|
591
|
-
const schema = go(type, $defs, true, path, options)
|
|
592
|
-
if ("enum" in schema) {
|
|
593
|
-
if (Object.keys(schema).length > 1) {
|
|
594
|
-
anyOf.push(schema)
|
|
595
|
-
} else {
|
|
596
|
-
for (const e of schema.enum) {
|
|
597
|
-
enums.push(e)
|
|
598
|
-
}
|
|
599
|
-
}
|
|
600
|
-
} else {
|
|
601
|
-
anyOf.push(schema)
|
|
602
|
-
}
|
|
603
|
-
}
|
|
604
|
-
if (anyOf.length === 0) {
|
|
605
|
-
return { enum: enums, ...getJsonSchemaAnnotations(ast) }
|
|
606
|
-
} else {
|
|
607
|
-
if (enums.length >= 1) {
|
|
608
|
-
anyOf.push({ enum: enums })
|
|
609
|
-
}
|
|
610
|
-
return { anyOf, ...getJsonSchemaAnnotations(ast) }
|
|
611
|
-
}
|
|
612
|
-
}
|
|
613
|
-
case "Enums": {
|
|
614
|
-
return {
|
|
615
|
-
$comment: "/schemas/enums",
|
|
616
|
-
anyOf: ast.enums.map((e) => ({ title: e[0], enum: [e[1]] })),
|
|
617
|
-
...getJsonSchemaAnnotations(ast)
|
|
618
|
-
}
|
|
619
|
-
}
|
|
620
|
-
case "Refinement": {
|
|
621
|
-
if (AST.encodedBoundAST(ast) === ast) {
|
|
622
|
-
throw new Error(getJSONSchemaMissingAnnotationErrorMessage(path, ast))
|
|
623
|
-
}
|
|
624
|
-
return go(ast.from, $defs, true, path, options)
|
|
625
|
-
}
|
|
626
|
-
case "TemplateLiteral": {
|
|
627
|
-
const regex = AST.getTemplateLiteralRegExp(ast)
|
|
628
|
-
return {
|
|
629
|
-
type: "string",
|
|
630
|
-
description: "a template literal",
|
|
631
|
-
pattern: regex.source,
|
|
632
|
-
...getJsonSchemaAnnotations(ast)
|
|
633
|
-
}
|
|
634
|
-
}
|
|
635
|
-
case "Suspend": {
|
|
636
|
-
const identifier = Option.orElse(AST.getJSONIdentifier(ast), () => AST.getJSONIdentifier(ast.f()))
|
|
637
|
-
if (Option.isNone(identifier)) {
|
|
638
|
-
throw new Error(getJSONSchemaMissingIdentifierAnnotationErrorMessage(path, ast))
|
|
639
|
-
}
|
|
640
|
-
return {
|
|
641
|
-
...go(ast.f(), $defs, true, path, options),
|
|
642
|
-
...getJsonSchemaAnnotations(ast)
|
|
643
|
-
}
|
|
644
|
-
}
|
|
645
|
-
case "Transformation": {
|
|
646
|
-
// Properly handle S.parseJson transformations by focusing on
|
|
647
|
-
// the 'to' side of the AST. This approach prevents the generation of useless schemas
|
|
648
|
-
// derived from the 'from' side (type: string), ensuring the output matches the intended
|
|
649
|
-
// complex schema type.
|
|
650
|
-
if (isParseJsonTransformation(ast.from)) {
|
|
651
|
-
return {
|
|
652
|
-
type: "string",
|
|
653
|
-
contentMediaType: "application/json",
|
|
654
|
-
contentSchema: go(ast.to, $defs, true, path, options),
|
|
655
|
-
...getJsonSchemaAnnotations(ast)
|
|
656
|
-
}
|
|
657
|
-
}
|
|
658
|
-
return {
|
|
659
|
-
...getASTJsonSchemaAnnotations(ast.to),
|
|
660
|
-
...go(ast.from, $defs, true, path, options),
|
|
661
|
-
...getJsonSchemaAnnotations(ast)
|
|
662
|
-
}
|
|
663
|
-
}
|
|
664
|
-
}
|
|
665
|
-
}
|
|
666
|
-
|
|
667
|
-
const getJSONSchemaMissingAnnotationErrorMessage = (
|
|
668
|
-
path: ReadonlyArray<PropertyKey>,
|
|
669
|
-
ast: AST.AST
|
|
670
|
-
) =>
|
|
671
|
-
getMissingAnnotationErrorMessage(
|
|
672
|
-
`Generating a JSON Schema for this schema requires a "jsonSchema" annotation`,
|
|
673
|
-
path,
|
|
674
|
-
ast
|
|
675
|
-
)
|
|
676
|
-
|
|
677
|
-
const getJSONSchemaMissingIdentifierAnnotationErrorMessage = (
|
|
678
|
-
path: ReadonlyArray<PropertyKey>,
|
|
679
|
-
ast: AST.AST
|
|
680
|
-
) =>
|
|
681
|
-
getMissingAnnotationErrorMessage(
|
|
682
|
-
`Generating a JSON Schema for this schema requires an "identifier" annotation`,
|
|
683
|
-
path,
|
|
684
|
-
ast
|
|
685
|
-
)
|
|
686
|
-
|
|
687
|
-
const getJSONSchemaUnsupportedParameterErrorMessage = (
|
|
688
|
-
path: ReadonlyArray<PropertyKey>,
|
|
689
|
-
parameter: AST.AST
|
|
690
|
-
): string => getErrorMessage("Unsupported index signature parameter", undefined, path, parameter)
|
|
691
|
-
|
|
692
|
-
const getJSONSchemaUnsupportedPostRestElementsErrorMessage = (path: ReadonlyArray<PropertyKey>): string =>
|
|
693
|
-
getErrorMessage(
|
|
694
|
-
"Generating a JSON Schema for post-rest elements is not currently supported. You're welcome to contribute by submitting a Pull Request",
|
|
695
|
-
undefined,
|
|
696
|
-
path
|
|
697
|
-
)
|
|
698
|
-
|
|
699
|
-
const getJSONSchemaUnsupportedKeyErrorMessage = (key: PropertyKey, path: ReadonlyArray<PropertyKey>): string =>
|
|
700
|
-
getErrorMessage("Unsupported key", `Cannot encode ${formatPropertyKey(key)} key to JSON Schema`, path)
|
|
701
|
-
|
|
702
|
-
const getMissingAnnotationErrorMessage = (details?: string, path?: ReadonlyArray<PropertyKey>, ast?: AST.AST): string =>
|
|
703
|
-
getErrorMessage("Missing annotation", details, path, ast)
|
|
704
|
-
|
|
705
|
-
const getErrorMessage = (
|
|
706
|
-
reason: string,
|
|
707
|
-
details?: string,
|
|
708
|
-
path?: ReadonlyArray<PropertyKey>,
|
|
709
|
-
ast?: AST.AST
|
|
710
|
-
): string => {
|
|
711
|
-
let out = reason
|
|
712
|
-
|
|
713
|
-
if (path && Arr.isNonEmptyReadonlyArray(path)) {
|
|
714
|
-
out += `\nat path: ${formatPath(path)}`
|
|
715
|
-
}
|
|
716
|
-
|
|
717
|
-
if (details !== undefined) {
|
|
718
|
-
out += `\ndetails: ${details}`
|
|
719
|
-
}
|
|
720
|
-
|
|
721
|
-
if (ast) {
|
|
722
|
-
out += `\nschema (${ast._tag}): ${ast}`
|
|
723
|
-
}
|
|
724
|
-
|
|
725
|
-
return out
|
|
726
|
-
}
|
|
727
|
-
|
|
728
|
-
const formatPathKey = (key: PropertyKey): string => `[${formatPropertyKey(key)}]`
|
|
729
|
-
|
|
730
|
-
const formatPath = (path: ParseResult.Path): string =>
|
|
731
|
-
isNonEmpty(path) ? path.map(formatPathKey).join("") : formatPathKey(path)
|
|
732
|
-
|
|
733
|
-
const isNonEmpty = <A>(x: ParseResult.SingleOrNonEmpty<A>): x is Arr.NonEmptyReadonlyArray<A> => Array.isArray(x)
|
|
734
|
-
|
|
735
|
-
const formatPropertyKey = (name: PropertyKey): string => typeof name === "string" ? JSON.stringify(name) : String(name)
|
package/src/Socket.ts
CHANGED
|
@@ -492,7 +492,9 @@ export const fromWebSocket = <RO>(
|
|
|
492
492
|
runRaw((data) =>
|
|
493
493
|
typeof data === "string"
|
|
494
494
|
? handler(encoder.encode(data))
|
|
495
|
-
:
|
|
495
|
+
: data instanceof Uint8Array
|
|
496
|
+
? handler(data)
|
|
497
|
+
: handler(new Uint8Array(data))
|
|
496
498
|
)
|
|
497
499
|
|
|
498
500
|
const write = (chunk: Uint8Array | string | CloseEvent) =>
|