diff --git a/packages/input_schema/src/schema.json b/packages/input_schema/src/schema.json index d522cd270..6f3bb5592 100644 --- a/packages/input_schema/src/schema.json +++ b/packages/input_schema/src/schema.json @@ -53,13 +53,12 @@ "stringEnumProperty": { "title": "Enum property", "type": "object", - "additionalProperties": false, + "unevaluatedProperties": false, "properties": { "type": { "enum": ["string"] }, "editor": { "enum": ["select"] }, "title": { "type": "string" }, "description": { "type": "string" }, - "default": { "type": "string" }, "prefill": { "type": "string" }, "example": { "type": "string" }, "nullable": { "type": "boolean" }, @@ -77,7 +76,16 @@ "minItems": 1 } }, - "required": ["type", "title", "description", "enum"] + "required": ["type", "title", "description", "enum"], + "if": { + "properties": { "nullable": { "const": false } } + }, + "then": { + "properties": { "default": { "type": "string" } } + }, + "else": { + "properties": { "default": { "type": ["string", "null"] } } + } }, "stringProperty": { "title": "String property", @@ -102,49 +110,52 @@ } }, "then": { - "if": { - "properties": { - "editor": { "const": "datepicker" } - } - }, - "then": { - "additionalProperties": false, - "properties": { - "type": { "enum": ["string"] }, - "title": { "type": "string" }, - "description": { "type": "string" }, - "default": { "type": "string" }, - "prefill": { "type": "string" }, - "example": { "type": "string" }, - "pattern": { "type": "string" }, - "nullable": { "type": "boolean" }, - "minLength": { "type": "integer" }, - "maxLength": { "type": "integer" }, - "editor": { "enum": ["datepicker"] }, - "sectionCaption": { "type": "string" }, - "sectionDescription": { "type": "string" }, - "dateType": { "enum": ["absolute", "relative", "absoluteOrRelative"] } - } + "properties": { + "type": { "enum": ["string"] }, + "title": { "type": "string" }, + "description": { "type": "string" }, + "prefill": { "type": "string" }, + "example": { "type": "string" }, + "pattern": { "type": "string" }, + "nullable": { "type": "boolean" }, + "minLength": { "type": "integer" }, + "maxLength": { "type": "integer" }, + "sectionCaption": { "type": "string" }, + "sectionDescription": { "type": "string" }, + "isSecret": { "enum": [false] } }, - "else": { - "additionalProperties": false, - "properties": { - "type": { "enum": ["string"] }, - "title": { "type": "string" }, - "description": { "type": "string" }, - "default": { "type": "string" }, - "prefill": { "type": "string" }, - "example": { "type": "string" }, - "pattern": { "type": "string" }, - "nullable": { "type": "boolean" }, - "minLength": { "type": "integer" }, - "maxLength": { "type": "integer" }, - "editor": { "enum": ["javascript", "python", "textfield", "textarea", "hidden", "fileupload"] }, - "isSecret": { "enum": [false] }, - "sectionCaption": { "type": "string" }, - "sectionDescription": { "type": "string" } + "unevaluatedProperties": false, + "allOf": [ + { + "if": { + "properties": { + "editor": { "const": "datepicker" } + } + }, + "then": { + "properties": { + "editor": { "enum": ["datepicker"] }, + "dateType": { "enum": ["absolute", "relative", "absoluteOrRelative"] } + } + }, + "else": { + "properties": { + "editor": { "enum": ["javascript", "python", "textfield", "textarea", "hidden", "fileupload"] } + } + } + }, + { + "if": { + "properties": { "nullable": { "const": false } } + }, + "then": { + "properties": { "default": { "type": "string" } } + }, + "else": { + "properties": { "default": { "type": ["string", "null"] } } + } } - } + ] }, "else": { "additionalProperties": false, @@ -181,7 +192,6 @@ "type": { "enum": ["array"] }, "title": { "type": "string" }, "description": { "type": "string" }, - "default": { "type": "array" }, "prefill": { "type": "array" }, "example": { "type": "array" }, "nullable": { "type": "boolean" }, @@ -197,59 +207,74 @@ "isSecret": { "enum": [false] } }, "unevaluatedProperties": false, - "oneOf": [ - { - "required": ["editor"], - "properties": { - "editor": { "enum": ["select"] }, - "items": { "$ref": "#/definitions/arrayItemsSelect" } - } - }, - { - "required": ["editor"], - "properties": { - "editor": { "enum": ["keyValue"] }, - "items": { "$ref": "#/definitions/arrayItemsKeyValue" } - } - }, - { - "required": ["editor"], - "properties": { - "editor": { "enum": ["stringList"] }, - "items": { "$ref": "#/definitions/arrayItemsStringList" } - } - }, - { - "required": ["editor"], - "properties": { - "editor": { "enum": ["globs"] }, - "items": { "$ref": "#/definitions/arrayItemsGlobs" } - } - }, + "allOf": [ { - "required": ["editor"], - "properties": { - "editor": { "enum": ["pseudoUrls"] }, - "items": { "$ref": "#/definitions/arrayItemsPseudoUrls" } - } - }, - { - "required": ["editor"], - "properties": { - "editor": { "enum": ["requestListSources"] }, - "items": { "$ref": "#/definitions/arrayItemsRequestListSources" } - } + "oneOf": [ + { + "required": ["editor"], + "properties": { + "editor": { "enum": ["select"] }, + "items": { "$ref": "#/definitions/arrayItemsSelect" } + } + }, + { + "required": ["editor"], + "properties": { + "editor": { "enum": ["keyValue"] }, + "items": { "$ref": "#/definitions/arrayItemsKeyValue" } + } + }, + { + "required": ["editor"], + "properties": { + "editor": { "enum": ["stringList"] }, + "items": { "$ref": "#/definitions/arrayItemsStringList" } + } + }, + { + "required": ["editor"], + "properties": { + "editor": { "enum": ["globs"] }, + "items": { "$ref": "#/definitions/arrayItemsGlobs" } + } + }, + { + "required": ["editor"], + "properties": { + "editor": { "enum": ["pseudoUrls"] }, + "items": { "$ref": "#/definitions/arrayItemsPseudoUrls" } + } + }, + { + "required": ["editor"], + "properties": { + "editor": { "enum": ["requestListSources"] }, + "items": { "$ref": "#/definitions/arrayItemsRequestListSources" } + } + }, + { + "required": ["editor"], + "properties": { + "editor": { "enum": ["json", "schemaBased", "hidden"] }, + "items": { "$ref": "#/definitions/arrayItems" } + } + }, + { + "not": { "required": ["editor"] }, + "properties": { "items": { "$ref": "#/definitions/arrayItems" } } + } + ] }, { - "required": ["editor"], - "properties": { - "editor": { "enum": ["json", "schemaBased", "hidden"] }, - "items": { "$ref": "#/definitions/arrayItems" } + "if": { + "properties": { "nullable": { "const": false } } + }, + "then": { + "properties": { "default": { "type": "array" } } + }, + "else": { + "properties": { "default": { "type": ["array", "null"] } } } - }, - { - "not": { "required": ["editor"] }, - "properties": { "items": { "$ref": "#/definitions/arrayItems" } } } ] }, @@ -294,7 +319,6 @@ "type": { "enum": ["object"] }, "title": { "type": "string" }, "description": { "type": "string" }, - "default": { "type": "object" }, "prefill": { "type": "object" }, "example": { "type": "object" }, "patternKey": { "type": "string" }, @@ -317,15 +341,30 @@ } }, "unevaluatedProperties": false, - "oneOf": [ - { "properties": { - "editor": { "enum": ["proxy"] }, - "properties": { "$ref": "#/definitions/subObjectPropertiesProxy" } - }}, - { "properties": { - "editor": { "enum": ["json", "schemaBased", "hidden"] }, - "properties": { "$ref": "#/definitions/subObjectProperties" } - }} + "allOf": [ + { + "oneOf": [ + { "properties": { + "editor": { "enum": ["proxy"] }, + "properties": { "$ref": "#/definitions/subObjectPropertiesProxy" } + }}, + { "properties": { + "editor": { "enum": ["json", "schemaBased", "hidden"] }, + "properties": { "$ref": "#/definitions/subObjectProperties" } + }} + ] + }, + { + "if": { + "properties": { "nullable": { "const": false } } + }, + "then": { + "properties": { "default": { "type": "object" } } + }, + "else": { + "properties": { "default": { "type": ["object", "null"] } } + } + } ] }, "else": { @@ -361,12 +400,11 @@ "integerProperty": { "title": "Integer property", "type": "object", - "additionalProperties": false, + "unevaluatedProperties": false, "properties": { "type": { "enum": ["integer"] }, "title": { "type": "string" }, "description": { "type": "string" }, - "default": { "type": "integer" }, "prefill": { "type": "integer" }, "example": { "type": "integer" }, "nullable": { "type": "boolean" }, @@ -377,17 +415,25 @@ "sectionCaption": { "type": "string" }, "sectionDescription": { "type": "string" } }, - "required": ["type", "title", "description"] + "required": ["type", "title", "description"], + "if": { + "properties": { "nullable": { "const": false } } + }, + "then": { + "properties": { "default": { "type": "integer" } } + }, + "else": { + "properties": { "default": { "type": ["integer", "null"] } } + } }, "booleanProperty": { "title": "Boolean property", "type": "object", - "additionalProperties": false, + "unevaluatedProperties": false, "properties": { "type": { "enum": ["boolean"] }, "title": { "type": "string" }, "description": { "type": "string" }, - "default": { "type": "boolean" }, "prefill": { "type": "boolean" }, "example": { "type": "boolean" }, "nullable": { "type": "boolean" }, @@ -397,12 +443,21 @@ "sectionCaption": { "type": "string" }, "sectionDescription": { "type": "string" } }, - "required": ["type", "title", "description"] + "required": ["type", "title", "description"], + "if": { + "properties": { "nullable": { "const": false } } + }, + "then": { + "properties": { "default": { "type": "boolean" } } + }, + "else": { + "properties": { "default": { "type": ["boolean", "null"] } } + } }, "resourceProperty": { "title": "Resource property", "type": "object", - "additionalProperties": false, + "unevaluatedProperties": false, "properties": { "type": { "enum": ["string"] }, "title": { "type": "string" }, @@ -421,7 +476,6 @@ "const": "READ" } }, - "default": { "type": "string" }, "prefill": { "type": "string" }, "example": { "type": "string" }, "nullable": { "type": "boolean" }, @@ -442,13 +496,24 @@ ] } } + }, + { + "if": { + "properties": { "nullable": { "const": false } } + }, + "then": { + "properties": { "default": { "type": "string" } } + }, + "else": { + "properties": { "default": { "type": ["string", "null"] } } + } } ] }, "resourceArrayProperty": { "title": "Resource array property", "type": "object", - "additionalProperties": false, + "unevaluatedProperties": false, "properties": { "type": { "enum": ["array"] }, "title": { "type": "string" }, @@ -466,7 +531,6 @@ "const": "READ" } }, - "default": { "type": "array" }, "prefill": { "type": "array" }, "example": { "type": "array" }, "nullable": { "type": "boolean" }, @@ -491,13 +555,24 @@ ] } } + }, + { + "if": { + "properties": { "nullable": { "const": false } } + }, + "then": { + "properties": { "default": { "type": "array" } } + }, + "else": { + "properties": { "default": { "type": ["array", "null"] } } + } } ] }, "anyProperty": { "title": "Any property", "type": "object", - "additionalProperties": false, + "unevaluatedProperties": false, "properties": { "type": { "type": ["array"], @@ -511,7 +586,6 @@ }, "title": { "type": "string" }, "description": { "type": "string" }, - "default": { "type": ["object", "array", "string", "integer", "boolean"] }, "prefill": { "type": ["object", "array", "string", "integer", "boolean"] }, "example": { "type": ["object", "array", "string", "integer", "boolean"] }, "nullable": { "type": "boolean" }, @@ -519,7 +593,16 @@ "sectionCaption": { "type": "string" }, "sectionDescription": { "type": "string" } }, - "required": ["type", "title", "description", "editor"] + "required": ["type", "title", "description", "editor"], + "if": { + "properties": { "nullable": { "const": false } } + }, + "then": { + "properties": { "default": { "type": ["object", "array", "string", "integer", "boolean"] } } + }, + "else": { + "properties": { "default": { "type": ["object", "array", "string", "integer", "boolean", "null"] } } + } }, "subSchemaStringEnumProperty": { "title": "Sub-schema: Enum property", diff --git a/test/input_schema.test.ts b/test/input_schema.test.ts index a37229dcf..f2eee80ea 100644 --- a/test/input_schema.test.ts +++ b/test/input_schema.test.ts @@ -835,5 +835,84 @@ describe('input_schema.json', () => { expect(() => validateInputSchema(validator, schema)).not.toThrow(); }); }); + + describe('nullable field influence default type', () => { + it('should allow default null if nullable', () => { + const types = [ + { type: 'string', editor: 'textfield' }, + { type: 'integer', editor: 'number' }, + { type: 'boolean', editor: 'checkbox' }, + { type: 'array', editor: 'json' }, + { type: 'object', editor: 'json' }, + ]; + + types.forEach((type) => { + const schema = { + title: 'Test input schema', + type: 'object', + schemaVersion: 1, + properties: { + myField: { + title: 'Field title', + description: 'My test field', + ...type, + nullable: true, + default: null, + }, + }, + }; + expect(() => validateInputSchema(validator, schema)).not.toThrow(); + }); + }); + + it('should not allow default null if not nullable', () => { + const types = [ + { type: 'string', editor: 'textfield' }, + { type: 'integer', editor: 'number' }, + { type: 'boolean', editor: 'checkbox' }, + { type: 'array', editor: 'json' }, + { type: 'object', editor: 'json' }, + ]; + + types.forEach((type) => { + const schema = { + title: 'Test input schema', + type: 'object', + schemaVersion: 1, + properties: { + myField: { + title: 'Field title', + description: 'My test field', + ...type, + default: null, + }, + }, + }; + expect(() => validateInputSchema(validator, schema)).toThrow( + `Input schema is not valid (Field schema.properties.myField.default must be ${type.type})`, + ); + }); + + types.forEach((type) => { + const schema = { + title: 'Test input schema', + type: 'object', + schemaVersion: 1, + properties: { + myField: { + title: 'Field title', + description: 'My test field', + ...type, + nullable: false, + default: null, + }, + }, + }; + expect(() => validateInputSchema(validator, schema)).toThrow( + `Input schema is not valid (Field schema.properties.myField.default must be ${type.type})`, + ); + }); + }); + }); }); });