diff --git a/src/draft2019-09/methods/getData.test.ts b/src/draft2019-09/methods/getData.test.ts index ca7c547..959d399 100644 --- a/src/draft2019-09/methods/getData.test.ts +++ b/src/draft2019-09/methods/getData.test.ts @@ -1700,4 +1700,94 @@ describe("getData (2019)", () => { assert.deepEqual(res, { valid: "stays", invalid: "not removed" }); }); }); + describe("defaultTemplateOptions.initialValues", () => { + it("should omit properties without default values when 'initialValues:false' even if required", () => { + const node = compileSchema({ + $schema: "draft-2019-09", + type: "object", + required: ["name", "age", "country"], + properties: { + name: { type: "string", default: "John Doe" }, + age: { type: "number" }, + country: { type: "string", default: "USA" } + } + }); + const res = node.getData(undefined, { + extendDefaults: false, initialValues: false + }); + + assert.deepEqual(res, { name: "John Doe", country: "USA" }); + }); + + it("should omit properties without default values when 'initialValues:false' even if required in nested", () => { + const node = compileSchema({ + $schema: "draft-2019-09", + type: "object", + properties: { + user: { + type: "object", + required: ["id", "username"], + properties: { + id: { type: "string" }, + username: { type: "string", default: "guest" }, + profile: { + type: "object", + properties: { + bio: { type: "string" }, + theme: { type: "string", default: "light" } + } + } + } + }, + active: { type: "boolean", default: true } + } + }); + const res = node.getData({}, { addOptionalProps: true, initialValues: false}); + + assert.deepEqual(JSON.stringify(res), JSON.stringify({ + user: { + username: "guest", + profile: { + theme: "light" + } + }, + active: true + })); + }); + + it("should handle type string with default value and 'initialValues:false'", () => { + const node = compileSchema({ + type: "string", + default: "default value" + }); + const res = node.getData(undefined, { + initialValues: false + }); + assert.deepEqual(res, "default value"); + }); + + it("should handle type string without default value and 'initialValues:false'", () => { + const node = compileSchema({ + type: "string", + }); + const res = node.getData(undefined, {initialValues: false}); + assert.deepEqual(res, undefined); + }); + + it("should handle array without default value and 'initialValues:false'", () => { + const node = compileSchema({ + $schema: "draft-2019-09", + type: "object", + required: ["title"], + properties: { + title: { + type: "array", + items: { type: "string" } + } + } + }); + const res = node.getData(undefined, {initialValues: false}); + assert.deepEqual(res, { title: [] }); + }); + }); }); diff --git a/src/draft2019-09/methods/getData.ts b/src/draft2019-09/methods/getData.ts index ab343db..c97dc5c 100644 --- a/src/draft2019-09/methods/getData.ts +++ b/src/draft2019-09/methods/getData.ts @@ -21,6 +21,10 @@ export type TemplateOptions = { * regardless of minItems settings. */ extendDefaults?: boolean; + /** + * Set to false to not use type specific initial values.Defaults to true + */ + initialValues?: boolean; /** * Limits how often a $ref should be followed before aborting. Prevents infinite data-structure. * Defaults to 1 @@ -173,11 +177,11 @@ export function getData(node: SchemaNode, data?: unknown, opts?: TemplateOptions } const TYPE: Record unknown> = { - null: (node, data) => getDefault(node, data, null), - string: (node, data) => getDefault(node, data, ""), - number: (node, data) => getDefault(node, data, 0), - integer: (node, data) => getDefault(node, data, 0), - boolean: (node, data) => getDefault(node, data, false), + null: (node, data, opts) => getDefault(node, data, null, opts.initialValues), + string: (node, data,opts) => getDefault(node, data, "", opts.initialValues), + number: (node, data,opts) => getDefault(node, data, 0, opts.initialValues), + integer: (node, data,opts) => getDefault(node, data, 0, opts.initialValues), + boolean: (node, data,opts) => getDefault(node, data, false, opts.initialValues), // object: (draft, schema, data: Record | undefined, pointer: JsonPointer, opts: TemplateOptions) => { object: (node, data, opts) => { const schema = node.schema; @@ -193,7 +197,10 @@ const TYPE: Record { assert.deepEqual(res, { valid: "stays", invalid: "not removed" }); }); }); + describe("defaultTemplateOptions.initialValues", () => { + it("should omit properties without default values when 'initialValues:false' even if required", () => { + const node = compileSchema({ + type: "object", + required: ["name", "age", "country"], + properties: { + name: { type: "string", default: "John Doe" }, + age: { type: "number" }, + country: { type: "string", default: "USA" } + } + }); + const res = node.getData(undefined, { + extendDefaults: false, initialValues: false + }); + + assert.deepEqual(res, { name: "John Doe", country: "USA" }); + }); + + it("should omit properties without default values when 'initialValues:false' even if required in nested", () => { + const node = compileSchema({ + type: "object", + properties: { + user: { + type: "object", + required: ["id", "username"], + properties: { + id: { type: "string" }, + username: { type: "string", default: "guest" }, + profile: { + type: "object", + properties: { + bio: { type: "string" }, + theme: { type: "string", default: "light" } + } + } + } + }, + active: { type: "boolean", default: true } + } + }); + const res = node.getData({}, { addOptionalProps: true, initialValues: false}); + + assert.deepEqual(JSON.stringify(res), JSON.stringify({ + user: { + username: "guest", + profile: { + theme: "light" + } + }, + active: true + })); + }); + + it("should handle type string with default value and 'initialValues:false'", () => { + const node = compileSchema({ + type: "string", + default: "default value" + }); + const res = node.getData(undefined, { + initialValues: false + }); + assert.deepEqual(res, "default value"); + }); + + it("should handle type string without default value and 'initialValues:false'", () => { + const node = compileSchema({ + type: "string", + }); + const res = node.getData(undefined, {initialValues: false}); + assert.deepEqual(res, undefined); + }); + + it("should handle array without default value and 'initialValues:false'", () => { + const node = compileSchema({ + type: "object", + required: ["title"], + properties: { + title: { + type: "array", + items: { type: "string" } + } + } + }); + const res = node.getData(undefined, {initialValues: false}); + assert.deepEqual(res, { title: [] }); + }); + }); }); diff --git a/src/methods/getData.ts b/src/methods/getData.ts index 34860a0..075317c 100644 --- a/src/methods/getData.ts +++ b/src/methods/getData.ts @@ -21,6 +21,10 @@ export type TemplateOptions = { * regardless of minItems settings. */ extendDefaults?: boolean; + /** + * Set to false to not use type specific initial values.Defaults to true + */ + initialValues?: boolean; /** * Limits how often a $ref should be followed before aborting. Prevents infinite data-structure. * Defaults to 1 @@ -164,11 +168,11 @@ export function getData(node: SchemaNode, data?: unknown, opts?: TemplateOptions } const TYPE: Record unknown> = { - null: (node, data) => getDefault(node, data, null), - string: (node, data) => getDefault(node, data, ""), - number: (node, data) => getDefault(node, data, 0), - integer: (node, data) => getDefault(node, data, 0), - boolean: (node, data) => getDefault(node, data, false), + null: (node, data, opts) => getDefault(node, data, null, opts.initialValues), + string: (node, data,opts) => getDefault(node, data, "", opts.initialValues), + number: (node, data,opts) => getDefault(node, data, 0, opts.initialValues), + integer: (node, data,opts) => getDefault(node, data, 0, opts.initialValues), + boolean: (node, data,opts) => getDefault(node, data, false, opts.initialValues), // object: (draft, schema, data: Record | undefined, pointer: JsonPointer, opts: TemplateOptions) => { object: (node, data, opts) => { const schema = node.schema; @@ -184,7 +188,10 @@ const TYPE: Record