Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 30 additions & 1 deletion src/normalizer.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {JSONSchemaTypeName, LinkedJSONSchema, NormalizedJSONSchema, Parent} from './types/JSONSchema'
import {appendToDescription, escapeBlockComment, isSchemaLike, justName, toSafeString, traverse} from './utils'
import {appendToDescription, escapeBlockComment, isSchemaLike, justName, toSafeString, traverse, warning} from './utils'
import {Options} from './'
import {DereferencedPaths} from './resolver'
import {isDeepStrictEqual} from 'util'
Expand Down Expand Up @@ -215,6 +215,35 @@ rules.set('Transform definitions to $defs', (schema, fileName) => {
}
})

rules.set('Transform nullable to null type', schema => {
if (schema.nullable !== true) {
return
}

delete schema.nullable

if (schema.const !== undefined) {
if (schema.const !== null) {
warning('normalizer', 'const should be set to null when schema is nullable', schema)
schema.enum = [schema.const, null]
delete schema.const
}
} else if (schema.enum) {
if (!schema.enum.includes(null)) {
warning('normalizer', 'enum should include null when schema is nullable', schema)
schema.enum.push(null)
}
} else if (schema.type) {
if (Array.isArray(schema.type)) {
if (!schema.type.includes('null')) {
schema.type.push('null')
}
} else if (schema.type !== 'null') {
schema.type = [schema.type, 'null']
}
}
})

rules.set('Transform const to singleton enum', schema => {
if (schema.const !== undefined) {
schema.enum = [schema.const]
Expand Down
7 changes: 7 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,13 @@ export function error(...messages: any[]): void {
console.error(getStyledTextForLogging('red')?.('error'), ...messages)
}

export function warning(...messages: any[]): void {
if (!process.env.VERBOSE) {
return console.warn(messages)
}
console.warn(getStyledTextForLogging('yellow')?.('warning'), ...messages)
}

type LogStyle = 'blue' | 'cyan' | 'green' | 'magenta' | 'red' | 'white' | 'yellow'

export function log(style: LogStyle, title: string, ...messages: unknown[]): void {
Expand Down
27 changes: 27 additions & 0 deletions test/__snapshots__/test/test.ts.md
Original file line number Diff line number Diff line change
Expand Up @@ -1883,6 +1883,33 @@ Generated by [AVA](https://avajs.dev).
}␊
`

## nullable.js

> Expected output to match snapshot for e2e test: nullable.js

`/* eslint-disable */␊
/**␊
* This file was automatically generated by json-schema-to-typescript.␊
* DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,␊
* and run json-schema-to-typescript to regenerate this file.␊
*/␊
export interface Nullable {␊
a?: "" | null;␊
b?: null;␊
c?: "a" | "b" | null;␊
d?: "" | null;␊
e?: string | null;␊
f?: null;␊
g?: "" | null;␊
h?: null;␊
i?: "a" | "b" | null;␊
j?: "" | null;␊
k?: string | number | null;␊
l?: string | null;␊
}␊
`

## oneOf.js

> Expected output to match snapshot for e2e test: oneOf.js
Expand Down
Binary file modified test/__snapshots__/test/test.ts.snap
Binary file not shown.
58 changes: 58 additions & 0 deletions test/e2e/nullable.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
export const input = {
type: 'object',
properties: {
a: {
const: '',
nullable: true,
},
b: {
const: null,
nullable: true,
},
c: {
enum: ['a', 'b'],
nullable: true,
},
d: {
enum: ['', null],
nullable: true,
},
e: {
type: 'string',
nullable: true,
},
f: {
type: 'null',
nullable: true,
},
g: {
type: 'string',
const: '',
nullable: true,
},
h: {
type: 'string',
const: null,
nullable: true,
},
Comment on lines +33 to +37

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mdmower-csnw: This might not be directly related to the changes in this PR, but I was wondering if there's a warning for a schema like this where the type and const (or enum values) are inconsistent. I don't know how AJV handles such a schema.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is not a warning output by this tool. You can test this.

i: {
type: 'string',
enum: ['a', 'b'],
nullable: true,
},
j: {
type: 'string',
enum: ['', null],
nullable: true,
},
k: {
type: ['string', 'integer'],
nullable: true,
},
l: {
type: ['string', 'null'],
nullable: true,
},
},
additionalProperties: false,
}
111 changes: 111 additions & 0 deletions test/normalizer/nullableAddsNullToType.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
{
"name": "Nullable adds null to type",
"in": {
"$id": "a",
"type": "object",
"properties": {
"a": {
"const": "",
"nullable": true
},
"b": {
"const": null,
"nullable": true
},
"c": {
"enum": ["a", "b"],
"nullable": true
},
"d": {
"enum": ["", null],
"nullable": true
},
"e": {
"type": "string",
"nullable": true
},
"f": {
"type": "null",
"nullable": true
},
"g": {
"type": "string",
"const": "",
"nullable": true
},
"h": {
"type": "string",
"const": null,
"nullable": true
},
"i": {
"type": "string",
"enum": ["a", "b"],
"nullable": true
},
"j": {
"type": "string",
"enum": ["", null],
"nullable": true
},
"k": {
"type": ["string", "integer"],
"nullable": true
},
"l": {
"type": ["string", "null"],
"nullable": true
}
},
"required": [],
"additionalProperties": false
},
"out": {
"$id": "a",
"type": "object",
"properties": {
"a": {
"enum": ["", null]
},
"b": {
"enum": [null]
},
"c": {
"enum": ["a", "b", null]
},
"d": {
"enum": ["", null]
},
"e": {
"type": ["string", "null"]
},
"f": {
"type": "null"
},
"g": {
"type": "string",
"enum": ["", null]
},
"h": {
"type": "string",
"enum": [null]
},
"i": {
"type": "string",
"enum": ["a", "b", null]
},
"j": {
"type": "string",
"enum": ["", null]
},
"k": {
"type": ["string", "integer", "null"]
},
"l": {
"type": ["string", "null"]
}
},
"required": [],
"additionalProperties": false
}
}