effect 3.17.9 → 3.17.10
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/Arbitrary.js +5 -2
- package/dist/cjs/Arbitrary.js.map +1 -1
- package/dist/cjs/Either.js.map +1 -1
- package/dist/cjs/JSONSchema.js +307 -364
- package/dist/cjs/JSONSchema.js.map +1 -1
- package/dist/cjs/ParseResult.js +1 -1
- package/dist/cjs/ParseResult.js.map +1 -1
- package/dist/cjs/Schema.js +17 -14
- package/dist/cjs/Schema.js.map +1 -1
- package/dist/cjs/SchemaAST.js +27 -25
- package/dist/cjs/SchemaAST.js.map +1 -1
- package/dist/cjs/internal/core-effect.js +6 -6
- package/dist/cjs/internal/core-effect.js.map +1 -1
- package/dist/cjs/internal/version.js +1 -1
- package/dist/cjs/internal/version.js.map +1 -1
- package/dist/dts/Effect.d.ts +4 -4
- package/dist/dts/Either.d.ts +96 -96
- package/dist/dts/Either.d.ts.map +1 -1
- package/dist/dts/JSONSchema.d.ts.map +1 -1
- package/dist/dts/STM.d.ts +2 -2
- package/dist/dts/Schema.d.ts.map +1 -1
- package/dist/dts/SchemaAST.d.ts +2 -0
- package/dist/dts/SchemaAST.d.ts.map +1 -1
- package/dist/esm/Arbitrary.js +5 -2
- package/dist/esm/Arbitrary.js.map +1 -1
- package/dist/esm/Either.js.map +1 -1
- package/dist/esm/JSONSchema.js +307 -364
- package/dist/esm/JSONSchema.js.map +1 -1
- package/dist/esm/ParseResult.js +1 -1
- package/dist/esm/ParseResult.js.map +1 -1
- package/dist/esm/Schema.js +17 -14
- package/dist/esm/Schema.js.map +1 -1
- package/dist/esm/SchemaAST.js +27 -25
- package/dist/esm/SchemaAST.js.map +1 -1
- package/dist/esm/internal/core-effect.js +6 -6
- package/dist/esm/internal/core-effect.js.map +1 -1
- package/dist/esm/internal/version.js +1 -1
- package/dist/esm/internal/version.js.map +1 -1
- package/package.json +1 -1
- package/src/Arbitrary.ts +4 -2
- package/src/Effect.ts +4 -4
- package/src/Either.ts +132 -132
- package/src/JSONSchema.ts +373 -332
- package/src/ParseResult.ts +1 -1
- package/src/STM.ts +2 -2
- package/src/Schema.ts +19 -12
- package/src/SchemaAST.ts +24 -31
- package/src/internal/core-effect.ts +6 -6
- package/src/internal/version.ts +1 -1
package/src/JSONSchema.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import * as Arr from "./Array.js"
|
|
6
6
|
import * as errors_ from "./internal/schema/errors.js"
|
|
7
|
+
import * as schemaId_ from "./internal/schema/schemaId.js"
|
|
7
8
|
import * as Option from "./Option.js"
|
|
8
9
|
import * as ParseResult from "./ParseResult.js"
|
|
9
10
|
import * as Predicate from "./Predicate.js"
|
|
@@ -313,42 +314,50 @@ export const fromAST = (ast: AST.AST, options: {
|
|
|
313
314
|
const definitionPath = options.definitionPath ?? "#/$defs/"
|
|
314
315
|
const getRef = (id: string) => definitionPath + id
|
|
315
316
|
const target = options.target ?? "jsonSchema7"
|
|
316
|
-
const handleIdentifier = options.topLevelReferenceStrategy !== "skip"
|
|
317
|
+
const handleIdentifier = options.topLevelReferenceStrategy !== "skip" ? "handle-identifier" : "ignore-identifier"
|
|
317
318
|
const additionalPropertiesStrategy = options.additionalPropertiesStrategy ?? "strict"
|
|
318
|
-
return go(
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
319
|
+
return go(
|
|
320
|
+
ast,
|
|
321
|
+
options.definitions,
|
|
322
|
+
handleIdentifier,
|
|
323
|
+
[],
|
|
324
|
+
{
|
|
325
|
+
getRef,
|
|
326
|
+
target,
|
|
327
|
+
additionalPropertiesStrategy
|
|
328
|
+
},
|
|
329
|
+
"handle-annotation",
|
|
330
|
+
"handle-errors"
|
|
331
|
+
)
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
const constNever: JsonSchema7Never = {
|
|
335
|
+
$id: "/schemas/never",
|
|
336
|
+
not: {}
|
|
328
337
|
}
|
|
329
338
|
|
|
330
|
-
const constAny:
|
|
331
|
-
|
|
339
|
+
const constAny: JsonSchema7Any = {
|
|
340
|
+
$id: "/schemas/any"
|
|
332
341
|
}
|
|
333
342
|
|
|
334
|
-
const constUnknown:
|
|
335
|
-
|
|
343
|
+
const constUnknown: JsonSchema7Unknown = {
|
|
344
|
+
$id: "/schemas/unknown"
|
|
336
345
|
}
|
|
337
346
|
|
|
338
|
-
const constVoid:
|
|
339
|
-
|
|
347
|
+
const constVoid: JsonSchema7Void = {
|
|
348
|
+
$id: "/schemas/void"
|
|
340
349
|
}
|
|
341
350
|
|
|
342
|
-
const
|
|
343
|
-
|
|
351
|
+
const constObject: JsonSchema7object = {
|
|
352
|
+
$id: "/schemas/object",
|
|
344
353
|
"anyOf": [
|
|
345
354
|
{ "type": "object" },
|
|
346
355
|
{ "type": "array" }
|
|
347
356
|
]
|
|
348
357
|
}
|
|
349
358
|
|
|
350
|
-
const
|
|
351
|
-
|
|
359
|
+
const constEmptyStruct: JsonSchema7empty = {
|
|
360
|
+
$id: "/schemas/%7B%7D",
|
|
352
361
|
"anyOf": [
|
|
353
362
|
{ "type": "object" },
|
|
354
363
|
{ "type": "array" }
|
|
@@ -357,49 +366,97 @@ const constEmpty: JsonSchema7 = {
|
|
|
357
366
|
|
|
358
367
|
const $schema = "http://json-schema.org/draft-07/schema#"
|
|
359
368
|
|
|
360
|
-
|
|
361
|
-
annotated
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
369
|
+
function getRawDescription(annotated: AST.Annotated | undefined): string | undefined {
|
|
370
|
+
if (annotated !== undefined) return Option.getOrUndefined(AST.getDescriptionAnnotation(annotated))
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
function getRawTitle(annotated: AST.Annotated | undefined): string | undefined {
|
|
374
|
+
if (annotated !== undefined) return Option.getOrUndefined(AST.getTitleAnnotation(annotated))
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
function getRawDefault(annotated: AST.Annotated | undefined): Option.Option<unknown> {
|
|
378
|
+
if (annotated !== undefined) return AST.getDefaultAnnotation(annotated)
|
|
379
|
+
return Option.none()
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
function getRawExamples(annotated: AST.Annotated | undefined): ReadonlyArray<unknown> | undefined {
|
|
383
|
+
if (annotated !== undefined) return Option.getOrUndefined(AST.getExamplesAnnotation(annotated))
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
function encodeExamples(ast: AST.AST, examples: ReadonlyArray<unknown>): Array<unknown> | undefined {
|
|
387
|
+
const getOption = ParseResult.getOption(ast, false)
|
|
388
|
+
const out = Arr.filterMap(examples, (e) => getOption(e))
|
|
389
|
+
return out.length > 0 ? out : undefined
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
function filterBuiltIn(ast: AST.AST, annotation: string | undefined, key: symbol): string | undefined {
|
|
393
|
+
if (annotation !== undefined) {
|
|
394
|
+
switch (ast._tag) {
|
|
395
|
+
case "StringKeyword":
|
|
396
|
+
return annotation !== AST.stringKeyword.annotations[key] ? annotation : undefined
|
|
397
|
+
case "NumberKeyword":
|
|
398
|
+
return annotation !== AST.numberKeyword.annotations[key] ? annotation : undefined
|
|
399
|
+
case "BooleanKeyword":
|
|
400
|
+
return annotation !== AST.booleanKeyword.annotations[key] ? annotation : undefined
|
|
373
401
|
}
|
|
374
402
|
}
|
|
375
|
-
return
|
|
403
|
+
return annotation
|
|
376
404
|
}
|
|
377
405
|
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
406
|
+
function pruneJsonSchemaAnnotations(
|
|
407
|
+
ast: AST.AST,
|
|
408
|
+
description: string | undefined,
|
|
409
|
+
title: string | undefined,
|
|
410
|
+
def: Option.Option<unknown>,
|
|
411
|
+
examples: ReadonlyArray<unknown> | undefined
|
|
412
|
+
): JsonSchemaAnnotations | undefined {
|
|
413
|
+
const out: JsonSchemaAnnotations = {}
|
|
414
|
+
if (description !== undefined) out.description = description
|
|
415
|
+
if (title !== undefined) out.title = title
|
|
416
|
+
if (Option.isSome(def)) out.default = def.value
|
|
417
|
+
if (examples !== undefined) {
|
|
418
|
+
const encodedExamples = encodeExamples(ast, examples)
|
|
419
|
+
if (encodedExamples !== undefined) {
|
|
420
|
+
out.examples = encodedExamples
|
|
421
|
+
}
|
|
384
422
|
}
|
|
385
|
-
if (
|
|
386
|
-
|
|
423
|
+
if (Object.keys(out).length === 0) {
|
|
424
|
+
return undefined
|
|
387
425
|
}
|
|
388
|
-
return
|
|
426
|
+
return out
|
|
389
427
|
}
|
|
390
428
|
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
429
|
+
function getContextJsonSchemaAnnotations(ast: AST.AST, annotated: AST.Annotated): JsonSchemaAnnotations | undefined {
|
|
430
|
+
return pruneJsonSchemaAnnotations(
|
|
431
|
+
ast,
|
|
432
|
+
getRawDescription(annotated),
|
|
433
|
+
getRawTitle(annotated),
|
|
434
|
+
getRawDefault(annotated),
|
|
435
|
+
getRawExamples(annotated)
|
|
436
|
+
)
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
function getJsonSchemaAnnotations(ast: AST.AST): JsonSchemaAnnotations | undefined {
|
|
440
|
+
return pruneJsonSchemaAnnotations(
|
|
441
|
+
ast,
|
|
442
|
+
filterBuiltIn(ast, getRawDescription(ast), AST.DescriptionAnnotationId),
|
|
443
|
+
filterBuiltIn(ast, getRawTitle(ast), AST.TitleAnnotationId),
|
|
444
|
+
getRawDefault(ast),
|
|
445
|
+
getRawExamples(ast)
|
|
446
|
+
)
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
function mergeJsonSchemaAnnotations(
|
|
450
|
+
jsonSchema: JsonSchema7,
|
|
451
|
+
jsonSchemaAnnotations: JsonSchemaAnnotations | undefined
|
|
452
|
+
): JsonSchema7 {
|
|
453
|
+
if (jsonSchemaAnnotations) {
|
|
454
|
+
if ("$ref" in jsonSchema) {
|
|
455
|
+
return { allOf: [jsonSchema], ...jsonSchemaAnnotations } as any
|
|
456
|
+
}
|
|
457
|
+
return { ...jsonSchema, ...jsonSchemaAnnotations }
|
|
402
458
|
}
|
|
459
|
+
return jsonSchema
|
|
403
460
|
}
|
|
404
461
|
|
|
405
462
|
const pruneUndefined = (ast: AST.AST): AST.AST | undefined => {
|
|
@@ -411,39 +468,18 @@ const pruneUndefined = (ast: AST.AST): AST.AST | undefined => {
|
|
|
411
468
|
const isParseJsonTransformation = (ast: AST.AST): boolean =>
|
|
412
469
|
ast.annotations[AST.SchemaIdAnnotationId] === AST.ParseJsonSchemaId
|
|
413
470
|
|
|
414
|
-
const isOverrideAnnotation = (jsonSchema: JsonSchema7): boolean => {
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
// Returns true if the schema is an enum with no other properties other than the
|
|
420
|
-
// optional "type". This is used to merge enums together.
|
|
421
|
-
const isMergeableEnum = (jsonSchema: JsonSchema7): jsonSchema is JsonSchema7Enum => {
|
|
422
|
-
const len = Object.keys(jsonSchema).length
|
|
423
|
-
return "enum" in jsonSchema && (len === 1 || ("type" in jsonSchema && len === 2))
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
// Some validators do not support enums without a type keyword. This function
|
|
427
|
-
// adds a type keyword to the schema if it is missing and the enum values are
|
|
428
|
-
// homogeneous.
|
|
429
|
-
const addEnumType = (jsonSchema: JsonSchema7): JsonSchema7 => {
|
|
430
|
-
if ("enum" in jsonSchema && !("type" in jsonSchema)) {
|
|
431
|
-
const type: "string" | "number" | "boolean" | undefined = jsonSchema.enum.every(Predicate.isString) ?
|
|
432
|
-
"string" :
|
|
433
|
-
jsonSchema.enum.every(Predicate.isNumber) ?
|
|
434
|
-
"number" :
|
|
435
|
-
jsonSchema.enum.every(Predicate.isBoolean) ?
|
|
436
|
-
"boolean" :
|
|
437
|
-
undefined
|
|
438
|
-
if (type !== undefined) {
|
|
439
|
-
return { type, ...jsonSchema }
|
|
471
|
+
const isOverrideAnnotation = (ast: AST.AST, jsonSchema: JsonSchema7): boolean => {
|
|
472
|
+
if (AST.isRefinement(ast)) {
|
|
473
|
+
const schemaId = ast.annotations[AST.SchemaIdAnnotationId]
|
|
474
|
+
if (schemaId === schemaId_.IntSchemaId) {
|
|
475
|
+
return "type" in jsonSchema && jsonSchema.type !== "integer"
|
|
440
476
|
}
|
|
441
477
|
}
|
|
442
|
-
return jsonSchema
|
|
478
|
+
return ("type" in jsonSchema) || ("oneOf" in jsonSchema) || ("anyOf" in jsonSchema) || ("$ref" in jsonSchema)
|
|
443
479
|
}
|
|
444
480
|
|
|
445
|
-
const mergeRefinements = (from: any, jsonSchema: any,
|
|
446
|
-
const out: any = { ...from, ...
|
|
481
|
+
const mergeRefinements = (from: any, jsonSchema: any, ast: AST.AST): any => {
|
|
482
|
+
const out: any = { ...from, ...getJsonSchemaAnnotations(ast), ...jsonSchema }
|
|
447
483
|
out.allOf ??= []
|
|
448
484
|
|
|
449
485
|
const handle = (name: string, filter: (i: any) => boolean) => {
|
|
@@ -486,27 +522,6 @@ function isContentSchemaSupported(options: GoOptions): boolean {
|
|
|
486
522
|
}
|
|
487
523
|
}
|
|
488
524
|
|
|
489
|
-
function isNullTypeKeywordSupported(options: GoOptions): boolean {
|
|
490
|
-
switch (options.target) {
|
|
491
|
-
case "jsonSchema7":
|
|
492
|
-
case "jsonSchema2019-09":
|
|
493
|
-
return true
|
|
494
|
-
case "openApi3.1":
|
|
495
|
-
return false
|
|
496
|
-
}
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
// https://swagger.io/docs/specification/v3_0/data-models/data-types/#null
|
|
500
|
-
function isNullableKeywordSupported(options: GoOptions): boolean {
|
|
501
|
-
switch (options.target) {
|
|
502
|
-
case "jsonSchema7":
|
|
503
|
-
case "jsonSchema2019-09":
|
|
504
|
-
return false
|
|
505
|
-
case "openApi3.1":
|
|
506
|
-
return true
|
|
507
|
-
}
|
|
508
|
-
}
|
|
509
|
-
|
|
510
525
|
function getAdditionalProperties(options: GoOptions): boolean {
|
|
511
526
|
switch (options.additionalPropertiesStrategy) {
|
|
512
527
|
case "allow":
|
|
@@ -516,139 +531,169 @@ function getAdditionalProperties(options: GoOptions): boolean {
|
|
|
516
531
|
}
|
|
517
532
|
}
|
|
518
533
|
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
const isAnyJSONSchema = (jsonSchema: JsonSchema7): jsonSchema is JsonSchema7Any =>
|
|
523
|
-
"$id" in jsonSchema && jsonSchema.$id === "/schemas/any"
|
|
524
|
-
|
|
525
|
-
const isUnknownJSONSchema = (jsonSchema: JsonSchema7): jsonSchema is JsonSchema7Unknown =>
|
|
526
|
-
"$id" in jsonSchema && jsonSchema.$id === "/schemas/unknown"
|
|
527
|
-
|
|
528
|
-
const isVoidJSONSchema = (jsonSchema: JsonSchema7): jsonSchema is JsonSchema7Void =>
|
|
529
|
-
"$id" in jsonSchema && jsonSchema.$id === "/schemas/void"
|
|
534
|
+
function addASTAnnotations(jsonSchema: JsonSchema7, ast: AST.AST): JsonSchema7 {
|
|
535
|
+
return addAnnotations(jsonSchema, getJsonSchemaAnnotations(ast))
|
|
536
|
+
}
|
|
530
537
|
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
members = [members[i]]
|
|
538
|
+
function addAnnotations(jsonSchema: JsonSchema7, annotations: JsonSchemaAnnotations | undefined): JsonSchema7 {
|
|
539
|
+
if (annotations === undefined || Object.keys(annotations).length === 0) {
|
|
540
|
+
return jsonSchema
|
|
535
541
|
}
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
members = [members[i]]
|
|
542
|
+
if ("$ref" in jsonSchema) {
|
|
543
|
+
return { allOf: [jsonSchema], ...annotations } as any
|
|
539
544
|
}
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
545
|
+
return { ...jsonSchema, ...annotations }
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
function getIdentifierAnnotation(ast: AST.AST): string | undefined {
|
|
549
|
+
const identifier = Option.getOrUndefined(AST.getJSONIdentifier(ast))
|
|
550
|
+
if (identifier === undefined) {
|
|
551
|
+
if (AST.isSuspend(ast)) {
|
|
552
|
+
return getIdentifierAnnotation(ast.f())
|
|
553
|
+
}
|
|
554
|
+
if (AST.isTransformation(ast) && AST.isTypeLiteral(ast.from) && AST.isDeclaration(ast.to)) {
|
|
555
|
+
const to = ast.to
|
|
556
|
+
const surrogate = AST.getSurrogateAnnotation(to)
|
|
557
|
+
if (Option.isSome(surrogate)) {
|
|
558
|
+
return getIdentifierAnnotation(to)
|
|
559
|
+
}
|
|
560
|
+
}
|
|
543
561
|
}
|
|
544
|
-
return
|
|
562
|
+
return identifier
|
|
545
563
|
}
|
|
546
564
|
|
|
547
|
-
|
|
565
|
+
function go(
|
|
548
566
|
ast: AST.AST,
|
|
549
567
|
$defs: Record<string, JsonSchema7>,
|
|
550
|
-
|
|
568
|
+
identifier: "handle-identifier" | "ignore-identifier",
|
|
551
569
|
path: ReadonlyArray<PropertyKey>,
|
|
552
|
-
options: GoOptions
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
570
|
+
options: GoOptions,
|
|
571
|
+
annotation: "handle-annotation" | "ignore-annotation",
|
|
572
|
+
errors: "handle-errors" | "ignore-errors"
|
|
573
|
+
): JsonSchema7 {
|
|
574
|
+
if (identifier === "handle-identifier") {
|
|
575
|
+
const id = getIdentifierAnnotation(ast)
|
|
576
|
+
if (id !== undefined) {
|
|
558
577
|
const escapedId = id.replace(/~/ig, "~0").replace(/\//ig, "~1")
|
|
559
578
|
const out = { $ref: options.getRef(escapedId) }
|
|
560
579
|
if (!Record.has($defs, id)) {
|
|
561
580
|
$defs[id] = out
|
|
562
|
-
$defs[id] = go(ast, $defs,
|
|
581
|
+
$defs[id] = go(ast, $defs, "ignore-identifier", path, options, "handle-annotation", errors)
|
|
563
582
|
}
|
|
564
583
|
return out
|
|
565
584
|
}
|
|
566
585
|
}
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
} else
|
|
579
|
-
|
|
586
|
+
if (annotation === "handle-annotation") {
|
|
587
|
+
const hook = AST.getJSONSchemaAnnotation(ast)
|
|
588
|
+
if (Option.isSome(hook)) {
|
|
589
|
+
const handler = hook.value as JsonSchema7
|
|
590
|
+
if (isOverrideAnnotation(ast, handler)) {
|
|
591
|
+
switch (ast._tag) {
|
|
592
|
+
case "Declaration":
|
|
593
|
+
return addASTAnnotations(handler, ast)
|
|
594
|
+
default:
|
|
595
|
+
return handler
|
|
596
|
+
}
|
|
597
|
+
} else {
|
|
598
|
+
switch (ast._tag) {
|
|
599
|
+
case "Refinement": {
|
|
600
|
+
const t = AST.getTransformationFrom(ast)
|
|
601
|
+
if (t === undefined) {
|
|
602
|
+
return mergeRefinements(
|
|
603
|
+
go(ast.from, $defs, identifier, path, options, "handle-annotation", errors),
|
|
604
|
+
handler,
|
|
605
|
+
ast
|
|
606
|
+
)
|
|
607
|
+
} else {
|
|
608
|
+
return go(t, $defs, identifier, path, options, "handle-annotation", errors)
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
default:
|
|
612
|
+
return {
|
|
613
|
+
...go(ast, $defs, identifier, path, options, "ignore-annotation", errors),
|
|
614
|
+
...handler
|
|
615
|
+
} as any
|
|
616
|
+
}
|
|
580
617
|
}
|
|
581
618
|
}
|
|
582
|
-
if (AST.isDeclaration(ast)) {
|
|
583
|
-
return { ...handler, ...getJsonSchemaAnnotations(ast) }
|
|
584
|
-
}
|
|
585
|
-
return handler
|
|
586
619
|
}
|
|
587
620
|
const surrogate = AST.getSurrogateAnnotation(ast)
|
|
588
621
|
if (Option.isSome(surrogate)) {
|
|
589
|
-
return go(surrogate.value, $defs,
|
|
622
|
+
return go(surrogate.value, $defs, identifier, path, options, "handle-annotation", errors)
|
|
590
623
|
}
|
|
591
624
|
switch (ast._tag) {
|
|
625
|
+
// Unsupported
|
|
592
626
|
case "Declaration":
|
|
627
|
+
case "UndefinedKeyword":
|
|
628
|
+
case "BigIntKeyword":
|
|
629
|
+
case "UniqueSymbol":
|
|
630
|
+
case "SymbolKeyword": {
|
|
631
|
+
if (errors === "ignore-errors") return addASTAnnotations(constAny, ast)
|
|
593
632
|
throw new Error(errors_.getJSONSchemaMissingAnnotationErrorMessage(path, ast))
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
if (
|
|
597
|
-
if (
|
|
598
|
-
|
|
599
|
-
// Section 6.1.1
|
|
600
|
-
return { type: "null", ...getJsonSchemaAnnotations(ast) }
|
|
601
|
-
} else {
|
|
602
|
-
// OpenAPI 3.1 does not support the "null" type keyword
|
|
603
|
-
// https://swagger.io/docs/specification/v3_0/data-models/data-types/#null
|
|
604
|
-
return {
|
|
605
|
-
// @ts-expect-error
|
|
606
|
-
enum: [null],
|
|
607
|
-
...getJsonSchemaAnnotations(ast)
|
|
608
|
-
}
|
|
609
|
-
}
|
|
610
|
-
} else if (Predicate.isString(literal)) {
|
|
611
|
-
return { type: "string", enum: [literal], ...getJsonSchemaAnnotations(ast) }
|
|
612
|
-
} else if (Predicate.isNumber(literal)) {
|
|
613
|
-
return { type: "number", enum: [literal], ...getJsonSchemaAnnotations(ast) }
|
|
614
|
-
} else if (Predicate.isBoolean(literal)) {
|
|
615
|
-
return { type: "boolean", enum: [literal], ...getJsonSchemaAnnotations(ast) }
|
|
633
|
+
}
|
|
634
|
+
case "Suspend": {
|
|
635
|
+
if (identifier === "handle-identifier") {
|
|
636
|
+
if (errors === "ignore-errors") return addASTAnnotations(constAny, ast)
|
|
637
|
+
throw new Error(errors_.getJSONSchemaMissingIdentifierAnnotationErrorMessage(path, ast))
|
|
616
638
|
}
|
|
617
|
-
|
|
639
|
+
return go(ast.f(), $defs, "ignore-identifier", path, options, "handle-annotation", errors)
|
|
618
640
|
}
|
|
619
|
-
|
|
620
|
-
throw new Error(errors_.getJSONSchemaMissingAnnotationErrorMessage(path, ast))
|
|
621
|
-
case "UndefinedKeyword":
|
|
622
|
-
throw new Error(errors_.getJSONSchemaMissingAnnotationErrorMessage(path, ast))
|
|
623
|
-
case "VoidKeyword":
|
|
624
|
-
return { ...constVoid, ...getJsonSchemaAnnotations(ast) }
|
|
641
|
+
// Primitives
|
|
625
642
|
case "NeverKeyword":
|
|
626
|
-
return
|
|
643
|
+
return addASTAnnotations(constNever, ast)
|
|
644
|
+
case "VoidKeyword":
|
|
645
|
+
return addASTAnnotations(constVoid, ast)
|
|
627
646
|
case "UnknownKeyword":
|
|
628
|
-
return
|
|
647
|
+
return addASTAnnotations(constUnknown, ast)
|
|
629
648
|
case "AnyKeyword":
|
|
630
|
-
return
|
|
649
|
+
return addASTAnnotations(constAny, ast)
|
|
631
650
|
case "ObjectKeyword":
|
|
632
|
-
return
|
|
651
|
+
return addASTAnnotations(constObject, ast)
|
|
633
652
|
case "StringKeyword":
|
|
634
|
-
return { type: "string",
|
|
653
|
+
return addASTAnnotations({ type: "string" }, ast)
|
|
635
654
|
case "NumberKeyword":
|
|
636
|
-
return { type: "number",
|
|
655
|
+
return addASTAnnotations({ type: "number" }, ast)
|
|
637
656
|
case "BooleanKeyword":
|
|
638
|
-
return { type: "boolean",
|
|
639
|
-
case "
|
|
640
|
-
|
|
641
|
-
|
|
657
|
+
return addASTAnnotations({ type: "boolean" }, ast)
|
|
658
|
+
case "Literal": {
|
|
659
|
+
const literal = ast.literal
|
|
660
|
+
if (literal === null) {
|
|
661
|
+
return addASTAnnotations({ type: "null" }, ast)
|
|
662
|
+
} else if (Predicate.isString(literal)) {
|
|
663
|
+
return addASTAnnotations({ type: "string", enum: [literal] }, ast)
|
|
664
|
+
} else if (Predicate.isNumber(literal)) {
|
|
665
|
+
return addASTAnnotations({ type: "number", enum: [literal] }, ast)
|
|
666
|
+
} else if (Predicate.isBoolean(literal)) {
|
|
667
|
+
return addASTAnnotations({ type: "boolean", enum: [literal] }, ast)
|
|
668
|
+
}
|
|
669
|
+
if (errors === "ignore-errors") return addASTAnnotations(constAny, ast)
|
|
642
670
|
throw new Error(errors_.getJSONSchemaMissingAnnotationErrorMessage(path, ast))
|
|
671
|
+
}
|
|
672
|
+
case "Enums": {
|
|
673
|
+
const anyOf = ast.enums.map((e) => {
|
|
674
|
+
const type: "string" | "number" = Predicate.isNumber(e[1]) ? "number" : "string"
|
|
675
|
+
return { type, title: e[0], enum: [e[1]] }
|
|
676
|
+
})
|
|
677
|
+
return anyOf.length >= 1 ?
|
|
678
|
+
addASTAnnotations({
|
|
679
|
+
$comment: "/schemas/enums",
|
|
680
|
+
anyOf
|
|
681
|
+
}, ast) :
|
|
682
|
+
addASTAnnotations(constNever, ast)
|
|
683
|
+
}
|
|
643
684
|
case "TupleType": {
|
|
644
|
-
const elements = ast.elements.map((e, i) =>
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
685
|
+
const elements = ast.elements.map((e, i) =>
|
|
686
|
+
mergeJsonSchemaAnnotations(
|
|
687
|
+
go(e.type, $defs, "handle-identifier", path.concat(i), options, "handle-annotation", errors),
|
|
688
|
+
getContextJsonSchemaAnnotations(e.type, e)
|
|
689
|
+
)
|
|
690
|
+
)
|
|
691
|
+
const rest = ast.rest.map((type) =>
|
|
692
|
+
mergeJsonSchemaAnnotations(
|
|
693
|
+
go(type.type, $defs, "handle-identifier", path, options, "handle-annotation", errors),
|
|
694
|
+
getContextJsonSchemaAnnotations(type.type, type)
|
|
695
|
+
)
|
|
696
|
+
)
|
|
652
697
|
const output: JsonSchema7Array = { type: "array" }
|
|
653
698
|
// ---------------------------------------------
|
|
654
699
|
// handle elements
|
|
@@ -675,6 +720,7 @@ const go = (
|
|
|
675
720
|
// handle post rest elements
|
|
676
721
|
// ---------------------------------------------
|
|
677
722
|
if (restLength > 1) {
|
|
723
|
+
if (errors === "ignore-errors") return addASTAnnotations(constAny, ast)
|
|
678
724
|
throw new Error(errors_.getJSONSchemaUnsupportedPostRestElementsErrorMessage(path))
|
|
679
725
|
}
|
|
680
726
|
} else {
|
|
@@ -685,11 +731,11 @@ const go = (
|
|
|
685
731
|
}
|
|
686
732
|
}
|
|
687
733
|
|
|
688
|
-
return
|
|
734
|
+
return addASTAnnotations(output, ast)
|
|
689
735
|
}
|
|
690
736
|
case "TypeLiteral": {
|
|
691
737
|
if (ast.propertySignatures.length === 0 && ast.indexSignatures.length === 0) {
|
|
692
|
-
return
|
|
738
|
+
return addASTAnnotations(constEmptyStruct, ast)
|
|
693
739
|
}
|
|
694
740
|
const output: JsonSchema7Object = {
|
|
695
741
|
type: "object",
|
|
@@ -704,11 +750,19 @@ const go = (
|
|
|
704
750
|
const parameter = is.parameter
|
|
705
751
|
switch (parameter._tag) {
|
|
706
752
|
case "StringKeyword": {
|
|
707
|
-
output.additionalProperties = go(
|
|
753
|
+
output.additionalProperties = go(
|
|
754
|
+
pruned,
|
|
755
|
+
$defs,
|
|
756
|
+
"handle-identifier",
|
|
757
|
+
path,
|
|
758
|
+
options,
|
|
759
|
+
"handle-annotation",
|
|
760
|
+
errors
|
|
761
|
+
)
|
|
708
762
|
break
|
|
709
763
|
}
|
|
710
764
|
case "TemplateLiteral": {
|
|
711
|
-
patternProperties = go(pruned, $defs,
|
|
765
|
+
patternProperties = go(pruned, $defs, "handle-identifier", path, options, "handle-annotation", errors)
|
|
712
766
|
propertyNames = {
|
|
713
767
|
type: "string",
|
|
714
768
|
pattern: AST.getTemplateLiteralRegExp(parameter).source
|
|
@@ -716,14 +770,30 @@ const go = (
|
|
|
716
770
|
break
|
|
717
771
|
}
|
|
718
772
|
case "Refinement": {
|
|
719
|
-
patternProperties = go(pruned, $defs,
|
|
720
|
-
propertyNames = go(parameter, $defs,
|
|
773
|
+
patternProperties = go(pruned, $defs, "handle-identifier", path, options, "handle-annotation", errors)
|
|
774
|
+
propertyNames = go(parameter, $defs, "handle-identifier", path, options, "handle-annotation", errors)
|
|
721
775
|
break
|
|
722
776
|
}
|
|
723
777
|
case "SymbolKeyword": {
|
|
724
778
|
const indexSignaturePath = path.concat("[symbol]")
|
|
725
|
-
output.additionalProperties = go(
|
|
726
|
-
|
|
779
|
+
output.additionalProperties = go(
|
|
780
|
+
pruned,
|
|
781
|
+
$defs,
|
|
782
|
+
"handle-identifier",
|
|
783
|
+
indexSignaturePath,
|
|
784
|
+
options,
|
|
785
|
+
"handle-annotation",
|
|
786
|
+
errors
|
|
787
|
+
)
|
|
788
|
+
propertyNames = go(
|
|
789
|
+
parameter,
|
|
790
|
+
$defs,
|
|
791
|
+
"handle-identifier",
|
|
792
|
+
indexSignaturePath,
|
|
793
|
+
options,
|
|
794
|
+
"handle-annotation",
|
|
795
|
+
errors
|
|
796
|
+
)
|
|
727
797
|
break
|
|
728
798
|
}
|
|
729
799
|
}
|
|
@@ -737,10 +807,10 @@ const go = (
|
|
|
737
807
|
if (Predicate.isString(name)) {
|
|
738
808
|
const pruned = pruneUndefined(ps.type)
|
|
739
809
|
const type = pruned ?? ps.type
|
|
740
|
-
output.properties[name] =
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
810
|
+
output.properties[name] = mergeJsonSchemaAnnotations(
|
|
811
|
+
go(type, $defs, "handle-identifier", path.concat(ps.name), options, "handle-annotation", errors),
|
|
812
|
+
getContextJsonSchemaAnnotations(type, ps)
|
|
813
|
+
)
|
|
744
814
|
// ---------------------------------------------
|
|
745
815
|
// handle optional property signatures
|
|
746
816
|
// ---------------------------------------------
|
|
@@ -748,6 +818,7 @@ const go = (
|
|
|
748
818
|
output.required.push(name)
|
|
749
819
|
}
|
|
750
820
|
} else {
|
|
821
|
+
if (errors === "ignore-errors") return addASTAnnotations(constAny, ast)
|
|
751
822
|
throw new Error(errors_.getJSONSchemaUnsupportedKeyErrorMessage(name, path))
|
|
752
823
|
}
|
|
753
824
|
}
|
|
@@ -762,117 +833,32 @@ const go = (
|
|
|
762
833
|
output.propertyNames = propertyNames
|
|
763
834
|
}
|
|
764
835
|
|
|
765
|
-
return
|
|
836
|
+
return addASTAnnotations(output, ast)
|
|
766
837
|
}
|
|
767
838
|
case "Union": {
|
|
768
|
-
const members: Array<JsonSchema7> =
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
}
|
|
780
|
-
|
|
781
|
-
const anyOf = shrink(members)
|
|
782
|
-
|
|
783
|
-
const finalize = (anyOf: Array<JsonSchema7>) => {
|
|
784
|
-
switch (anyOf.length) {
|
|
785
|
-
case 0:
|
|
786
|
-
return {
|
|
787
|
-
...constNever,
|
|
788
|
-
...getJsonSchemaAnnotations(ast)
|
|
789
|
-
}
|
|
790
|
-
case 1: {
|
|
791
|
-
return {
|
|
792
|
-
...addEnumType(anyOf[0]),
|
|
793
|
-
...getJsonSchemaAnnotations(ast)
|
|
794
|
-
}
|
|
795
|
-
}
|
|
796
|
-
default:
|
|
797
|
-
return {
|
|
798
|
-
anyOf: anyOf.map(addEnumType),
|
|
799
|
-
...getJsonSchemaAnnotations(ast)
|
|
800
|
-
}
|
|
801
|
-
}
|
|
802
|
-
}
|
|
803
|
-
|
|
804
|
-
if (isNullableKeywordSupported(options)) {
|
|
805
|
-
let nullable = false
|
|
806
|
-
const nonNullables: Array<JsonSchema7> = []
|
|
807
|
-
for (const s of anyOf) {
|
|
808
|
-
if ("nullable" in s) {
|
|
809
|
-
nullable = true
|
|
810
|
-
const nn = { ...s }
|
|
811
|
-
delete nn.nullable
|
|
812
|
-
nonNullables.push(nn)
|
|
813
|
-
} else if (isMergeableEnum(s)) {
|
|
814
|
-
const nnes = s.enum.filter((e) => e !== null)
|
|
815
|
-
if (nnes.length < s.enum.length) {
|
|
816
|
-
nullable = true
|
|
817
|
-
if (nnes.length === 0) {
|
|
818
|
-
continue
|
|
819
|
-
}
|
|
820
|
-
const nn = { ...s }
|
|
821
|
-
nn.enum = nnes
|
|
822
|
-
nonNullables.push(nn)
|
|
823
|
-
}
|
|
824
|
-
} else {
|
|
825
|
-
nonNullables.push(s)
|
|
826
|
-
}
|
|
827
|
-
}
|
|
828
|
-
if (nullable) {
|
|
829
|
-
const out = finalize(nonNullables)
|
|
830
|
-
if (!isAnyJSONSchema(out) && !isUnknownJSONSchema(out)) {
|
|
831
|
-
// @ts-expect-error
|
|
832
|
-
out.nullable = nullable
|
|
833
|
-
}
|
|
834
|
-
return out
|
|
835
|
-
}
|
|
839
|
+
const members: Array<JsonSchema7> = ast.types.map((t) =>
|
|
840
|
+
go(t, $defs, "handle-identifier", path, options, "handle-annotation", errors)
|
|
841
|
+
)
|
|
842
|
+
const anyOf = compactUnion(members)
|
|
843
|
+
switch (anyOf.length) {
|
|
844
|
+
case 0:
|
|
845
|
+
return constNever
|
|
846
|
+
case 1:
|
|
847
|
+
return addASTAnnotations(anyOf[0], ast)
|
|
848
|
+
default:
|
|
849
|
+
return addASTAnnotations({ anyOf }, ast)
|
|
836
850
|
}
|
|
837
|
-
|
|
838
|
-
return finalize(anyOf)
|
|
839
|
-
}
|
|
840
|
-
case "Enums": {
|
|
841
|
-
const anyOf = ast.enums.map((e) => addEnumType({ title: e[0], enum: [e[1]] }))
|
|
842
|
-
return anyOf.length >= 1 ?
|
|
843
|
-
{
|
|
844
|
-
$comment: "/schemas/enums",
|
|
845
|
-
anyOf,
|
|
846
|
-
...getJsonSchemaAnnotations(ast)
|
|
847
|
-
} :
|
|
848
|
-
{
|
|
849
|
-
...constNever,
|
|
850
|
-
...getJsonSchemaAnnotations(ast)
|
|
851
|
-
}
|
|
852
|
-
}
|
|
853
|
-
case "Refinement": {
|
|
854
|
-
// The jsonSchema annotation is required only if the refinement does not have a transformation
|
|
855
|
-
if (AST.getTransformationFrom(ast) === undefined) {
|
|
856
|
-
throw new Error(errors_.getJSONSchemaMissingAnnotationErrorMessage(path, ast))
|
|
857
|
-
}
|
|
858
|
-
return go(ast.from, $defs, handleIdentifier, path, options)
|
|
859
851
|
}
|
|
852
|
+
case "Refinement":
|
|
853
|
+
return go(ast.from, $defs, identifier, path, options, "handle-annotation", errors)
|
|
860
854
|
case "TemplateLiteral": {
|
|
861
855
|
const regex = AST.getTemplateLiteralRegExp(ast)
|
|
862
|
-
return {
|
|
856
|
+
return addASTAnnotations({
|
|
863
857
|
type: "string",
|
|
864
858
|
title: String(ast),
|
|
865
859
|
description: "a template literal",
|
|
866
|
-
pattern: regex.source
|
|
867
|
-
|
|
868
|
-
}
|
|
869
|
-
}
|
|
870
|
-
case "Suspend": {
|
|
871
|
-
const identifier = Option.orElse(AST.getJSONIdentifier(ast), () => AST.getJSONIdentifier(ast.f()))
|
|
872
|
-
if (Option.isNone(identifier)) {
|
|
873
|
-
throw new Error(errors_.getJSONSchemaMissingIdentifierAnnotationErrorMessage(path, ast))
|
|
874
|
-
}
|
|
875
|
-
return go(ast.f(), $defs, handleIdentifier, path, options)
|
|
860
|
+
pattern: regex.source
|
|
861
|
+
}, ast)
|
|
876
862
|
}
|
|
877
863
|
case "Transformation": {
|
|
878
864
|
if (isParseJsonTransformation(ast.from)) {
|
|
@@ -881,28 +867,83 @@ const go = (
|
|
|
881
867
|
"contentMediaType": "application/json"
|
|
882
868
|
}
|
|
883
869
|
if (isContentSchemaSupported(options)) {
|
|
884
|
-
out["contentSchema"] = go(ast.to, $defs,
|
|
870
|
+
out["contentSchema"] = go(ast.to, $defs, identifier, path, options, "handle-annotation", errors)
|
|
885
871
|
}
|
|
886
872
|
return out
|
|
887
873
|
}
|
|
888
|
-
|
|
889
|
-
if (
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
874
|
+
const from = go(ast.from, $defs, identifier, path, options, "handle-annotation", errors)
|
|
875
|
+
if (
|
|
876
|
+
ast.transformation._tag === "TypeLiteralTransformation" &&
|
|
877
|
+
isJsonSchema7Object(from)
|
|
878
|
+
) {
|
|
879
|
+
const to = go(ast.to, {}, "ignore-identifier", path, options, "handle-annotation", "ignore-errors")
|
|
880
|
+
if (isJsonSchema7Object(to)) {
|
|
881
|
+
for (const t of ast.transformation.propertySignatureTransformations) {
|
|
882
|
+
const toKey = t.to
|
|
883
|
+
const fromKey = t.from
|
|
884
|
+
if (Predicate.isString(toKey) && Predicate.isString(fromKey)) {
|
|
885
|
+
const toProperty = to.properties[toKey]
|
|
886
|
+
if (Predicate.isRecord(toProperty)) {
|
|
887
|
+
const fromProperty = from.properties[fromKey]
|
|
888
|
+
if (Predicate.isRecord(fromProperty)) {
|
|
889
|
+
const annotations: JsonSchemaAnnotations = {}
|
|
890
|
+
if (Predicate.isString(toProperty.title)) annotations.title = toProperty.title
|
|
891
|
+
if (Predicate.isString(toProperty.description)) annotations.description = toProperty.description
|
|
892
|
+
if (Array.isArray(toProperty.examples)) annotations.examples = toProperty.examples
|
|
893
|
+
if (Object.hasOwn(toProperty, "default")) annotations.default = toProperty.default
|
|
894
|
+
from.properties[fromKey] = addAnnotations(fromProperty, annotations)
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
}
|
|
903
899
|
}
|
|
904
900
|
}
|
|
905
|
-
return
|
|
901
|
+
return addASTAnnotations(from, ast)
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
function isJsonSchema7Object(jsonSchema: unknown): jsonSchema is JsonSchema7Object {
|
|
907
|
+
return Predicate.isRecord(jsonSchema) && jsonSchema.type === "object" && Predicate.isRecord(jsonSchema.properties)
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
function isNeverWithoutCustomAnnotations(jsonSchema: JsonSchema7): boolean {
|
|
911
|
+
return jsonSchema === constNever || (Predicate.hasProperty(jsonSchema, "$id") && jsonSchema.$id === constNever.$id &&
|
|
912
|
+
Object.keys(jsonSchema).length === 3 && jsonSchema.title === AST.neverKeyword.annotations[AST.TitleAnnotationId])
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
function isAny(jsonSchema: JsonSchema7): jsonSchema is JsonSchema7Any {
|
|
916
|
+
return "$id" in jsonSchema && jsonSchema.$id === constAny.$id
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
function isUnknown(jsonSchema: JsonSchema7): jsonSchema is JsonSchema7Unknown {
|
|
920
|
+
return "$id" in jsonSchema && jsonSchema.$id === constUnknown.$id
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
function isVoid(jsonSchema: JsonSchema7): jsonSchema is JsonSchema7Void {
|
|
924
|
+
return "$id" in jsonSchema && jsonSchema.$id === constVoid.$id
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
function isCompactableLiteral(jsonSchema: JsonSchema7 | undefined): jsonSchema is JsonSchema7Enum {
|
|
928
|
+
return Predicate.hasProperty(jsonSchema, "enum") && "type" in jsonSchema && Object.keys(jsonSchema).length === 2
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
function compactUnion(members: Array<JsonSchema7>): Array<JsonSchema7> {
|
|
932
|
+
const out: Array<JsonSchema7> = []
|
|
933
|
+
for (const m of members) {
|
|
934
|
+
if (isNeverWithoutCustomAnnotations(m)) continue
|
|
935
|
+
if (isAny(m) || isUnknown(m) || isVoid(m)) return [m]
|
|
936
|
+
if (isCompactableLiteral(m) && out.length > 0) {
|
|
937
|
+
const last = out[out.length - 1]
|
|
938
|
+
if (isCompactableLiteral(last) && last.type === m.type) {
|
|
939
|
+
out[out.length - 1] = {
|
|
940
|
+
type: last.type,
|
|
941
|
+
enum: [...last.enum, ...m.enum]
|
|
942
|
+
} as JsonSchema7Enum
|
|
943
|
+
continue
|
|
944
|
+
}
|
|
906
945
|
}
|
|
946
|
+
out.push(m)
|
|
907
947
|
}
|
|
948
|
+
return out
|
|
908
949
|
}
|