From 25ae852c666f702c8878a653efa76d90cb5350c1 Mon Sep 17 00:00:00 2001 From: Mani Satwick Chanupalli Date: Fri, 27 Jun 2025 04:59:22 +0000 Subject: [PATCH 1/2] Add initialValues option to turn on/off value generation --- src/draft2019-09/methods/getData.test.ts | 90 ++++++++++++++++++++++++ src/draft2019-09/methods/getData.ts | 25 ++++--- src/methods/getData.test.ts | 87 +++++++++++++++++++++++ src/methods/getData.ts | 25 ++++--- 4 files changed, 209 insertions(+), 18 deletions(-) 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 Date: Thu, 7 Aug 2025 09:51:41 +0000 Subject: [PATCH 2/2] Fix tests and rename initialValues --- src/draft2019-09/methods/getData.test.ts | 22 +++++++++++----------- src/draft2019-09/methods/getData.ts | 18 +++++++++--------- src/methods/getData.test.ts | 22 +++++++++++----------- src/methods/getData.ts | 18 +++++++++--------- 4 files changed, 40 insertions(+), 40 deletions(-) diff --git a/src/draft2019-09/methods/getData.test.ts b/src/draft2019-09/methods/getData.test.ts index 959d399..b14624c 100644 --- a/src/draft2019-09/methods/getData.test.ts +++ b/src/draft2019-09/methods/getData.test.ts @@ -1700,8 +1700,8 @@ 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", () => { + describe("defaultTemplateOptions.useTypeDefaults", () => { + it("should omit properties without default values when 'useTypeDefaults:false' even if required", () => { const node = compileSchema({ $schema: "draft-2019-09", type: "object", @@ -1713,13 +1713,13 @@ describe("getData (2019)", () => { } }); const res = node.getData(undefined, { - extendDefaults: false, initialValues: false + extendDefaults: false, useTypeDefaults: false }); assert.deepEqual(res, { name: "John Doe", country: "USA" }); }); - it("should omit properties without default values when 'initialValues:false' even if required in nested", () => { + it("should omit properties without default values when 'useTypeDefaults:false' even if required in nested", () => { const node = compileSchema({ $schema: "draft-2019-09", type: "object", @@ -1742,7 +1742,7 @@ describe("getData (2019)", () => { active: { type: "boolean", default: true } } }); - const res = node.getData({}, { addOptionalProps: true, initialValues: false}); + const res = node.getData({}, { addOptionalProps: true, useTypeDefaults: false}); assert.deepEqual(JSON.stringify(res), JSON.stringify({ user: { @@ -1755,26 +1755,26 @@ describe("getData (2019)", () => { })); }); - it("should handle type string with default value and 'initialValues:false'", () => { + it("should handle type string with default value and 'useTypeDefaults:false'", () => { const node = compileSchema({ type: "string", default: "default value" }); const res = node.getData(undefined, { - initialValues: false + useTypeDefaults: false }); assert.deepEqual(res, "default value"); }); - it("should handle type string without default value and 'initialValues:false'", () => { + it("should handle type string without default value and 'useTypeDefaults:false'", () => { const node = compileSchema({ type: "string", }); - const res = node.getData(undefined, {initialValues: false}); + const res = node.getData(undefined, {useTypeDefaults: false}); assert.deepEqual(res, undefined); }); - it("should handle array without default value and 'initialValues:false'", () => { + it("should handle array without default value and 'useTypeDefaults:false'", () => { const node = compileSchema({ $schema: "draft-2019-09", type: "object", @@ -1786,7 +1786,7 @@ describe("getData (2019)", () => { } } }); - const res = node.getData(undefined, {initialValues: false}); + const res = node.getData(undefined, {useTypeDefaults: false}); assert.deepEqual(res, { title: [] }); }); }); diff --git a/src/draft2019-09/methods/getData.ts b/src/draft2019-09/methods/getData.ts index c97dc5c..a192f47 100644 --- a/src/draft2019-09/methods/getData.ts +++ b/src/draft2019-09/methods/getData.ts @@ -24,7 +24,7 @@ export type TemplateOptions = { /** * Set to false to not use type specific initial values.Defaults to true */ - initialValues?: boolean; + useTypeDefaults?: boolean; /** * Limits how often a $ref should be followed before aborting. Prevents infinite data-structure. * Defaults to 1 @@ -177,11 +177,11 @@ export function getData(node: SchemaNode, data?: unknown, opts?: TemplateOptions } const TYPE: Record unknown> = { - 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), + null: (node, data, opts) => getDefault(node, data, null, opts.useTypeDefaults), + string: (node, data,opts) => getDefault(node, data, "", opts.useTypeDefaults), + number: (node, data,opts) => getDefault(node, data, 0, opts.useTypeDefaults), + integer: (node, data,opts) => getDefault(node, data, 0, opts.useTypeDefaults), + boolean: (node, data,opts) => getDefault(node, data, false, opts.useTypeDefaults), // object: (draft, schema, data: Record | undefined, pointer: JsonPointer, opts: TemplateOptions) => { object: (node, data, opts) => { const schema = node.schema; @@ -198,7 +198,7 @@ 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", () => { + describe("defaultTemplateOptions.useTypeDefaults", () => { + it("should omit properties without default values when 'useTypeDefaults:false' even if required", () => { const node = compileSchema({ type: "object", required: ["name", "age", "country"], @@ -1668,13 +1668,13 @@ describe("getData", () => { } }); const res = node.getData(undefined, { - extendDefaults: false, initialValues: false + extendDefaults: false, useTypeDefaults: false }); assert.deepEqual(res, { name: "John Doe", country: "USA" }); }); - it("should omit properties without default values when 'initialValues:false' even if required in nested", () => { + it("should omit properties without default values when 'useTypeDefaults:false' even if required in nested", () => { const node = compileSchema({ type: "object", properties: { @@ -1696,7 +1696,7 @@ describe("getData", () => { active: { type: "boolean", default: true } } }); - const res = node.getData({}, { addOptionalProps: true, initialValues: false}); + const res = node.getData({}, { addOptionalProps: true, useTypeDefaults: false}); assert.deepEqual(JSON.stringify(res), JSON.stringify({ user: { @@ -1709,26 +1709,26 @@ describe("getData", () => { })); }); - it("should handle type string with default value and 'initialValues:false'", () => { + it("should handle type string with default value and 'useTypeDefaults:false'", () => { const node = compileSchema({ type: "string", default: "default value" }); const res = node.getData(undefined, { - initialValues: false + useTypeDefaults: false }); assert.deepEqual(res, "default value"); }); - it("should handle type string without default value and 'initialValues:false'", () => { + it("should handle type string without default value and 'useTypeDefaults:false'", () => { const node = compileSchema({ type: "string", }); - const res = node.getData(undefined, {initialValues: false}); + const res = node.getData(undefined, {useTypeDefaults: false}); assert.deepEqual(res, undefined); }); - it("should handle array without default value and 'initialValues:false'", () => { + it("should handle array without default value and 'useTypeDefaults:false'", () => { const node = compileSchema({ type: "object", required: ["title"], @@ -1739,7 +1739,7 @@ describe("getData", () => { } } }); - const res = node.getData(undefined, {initialValues: false}); + const res = node.getData(undefined, {useTypeDefaults: false}); assert.deepEqual(res, { title: [] }); }); }); diff --git a/src/methods/getData.ts b/src/methods/getData.ts index 075317c..87472c1 100644 --- a/src/methods/getData.ts +++ b/src/methods/getData.ts @@ -24,7 +24,7 @@ export type TemplateOptions = { /** * Set to false to not use type specific initial values.Defaults to true */ - initialValues?: boolean; + useTypeDefaults?: boolean; /** * Limits how often a $ref should be followed before aborting. Prevents infinite data-structure. * Defaults to 1 @@ -168,11 +168,11 @@ export function getData(node: SchemaNode, data?: unknown, opts?: TemplateOptions } const TYPE: Record unknown> = { - 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), + null: (node, data, opts) => getDefault(node, data, null, opts.useTypeDefaults), + string: (node, data,opts) => getDefault(node, data, "", opts.useTypeDefaults), + number: (node, data,opts) => getDefault(node, data, 0, opts.useTypeDefaults), + integer: (node, data,opts) => getDefault(node, data, 0, opts.useTypeDefaults), + boolean: (node, data,opts) => getDefault(node, data, false, opts.useTypeDefaults), // object: (draft, schema, data: Record | undefined, pointer: JsonPointer, opts: TemplateOptions) => { object: (node, data, opts) => { const schema = node.schema; @@ -189,7 +189,7 @@ const TYPE: Record