Skip to content

Commit 0c3bbc7

Browse files
committed
add: getTemplate option extendDefaults
1 parent 5780d03 commit 0c3bbc7

File tree

3 files changed

+104
-3
lines changed

3 files changed

+104
-3
lines changed

README.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,32 @@ expect(myData).to.deep.equal({
268268

269269
</details>
270270

271+
<details><summary>Option: extendDefaults</summary>
272+
273+
Per default, `getTemplate` does try to create data that is valid to the json-schema. Example: array-schemas with `minItems: 1` will add one item to fullfil the validation criteria. You can use the option and pass `{ extendDefaults: false }` to override this behaviour with a default value:
274+
275+
```ts
276+
import { Draft07 } from "json-schema-library";
277+
278+
const myJsonSchema = {
279+
type: "array",
280+
default: [], // if omitted will add an array item
281+
items: {
282+
type: "string",
283+
enum: ["one", "two"]
284+
},
285+
minItems: 1 // usually adds an enty, but default states: []
286+
};
287+
288+
const jsonSchema = new Draft07(myJsonSchema);
289+
const myData = jsonSchema.getTemplate(undefined, undefined, { extendDefaults: false });
290+
291+
expect(myData).to.deep.equal([]);
292+
```
293+
294+
</details>
295+
296+
271297
### each
272298

273299
`each` iterates over each data-item (_object_, _array_ and _value_) and emits the data-item, schema and location to a callback.

lib/getTemplate.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,14 @@ import { mergeSchema } from "./mergeSchema";
1515
export type TemplateOptions = {
1616
/** Add all properties (required and optional) to the generated data */
1717
addOptionalProps?: boolean;
18-
/** remove data that does not match input schema. Defaults to false */
18+
/** Remove data that does not match input schema. Defaults to false */
1919
removeInvalidData?: boolean;
20+
/** Set to false to take default values as they are and not extend them.
21+
* Defaults to true.
22+
* This allows to control template data e.g. enforcing arrays to be empty,
23+
* regardless of minItems settings.
24+
*/
25+
extendDefaults?: boolean;
2026
};
2127

2228
const defaultOptions: TemplateOptions = {
@@ -257,7 +263,7 @@ const TYPE: Record<
257263
) => {
258264
const template = schema.default === undefined ? {} : schema.default;
259265
const d: Record<string, unknown> = {}; // do not assign data here, to keep ordering from json-schema
260-
const required = schema.required ?? [];
266+
const required = (opts.extendDefaults === false && schema.default !== undefined) ? [] : (schema.required ?? []);
261267

262268
if (schema.properties) {
263269
Object.keys(schema.properties).forEach((key) => {
@@ -345,7 +351,7 @@ const TYPE: Record<
345351

346352
const template = schema.default === undefined ? [] : schema.default;
347353
const d: unknown[] = data || template;
348-
const minItems = schema.minItems || 0;
354+
const minItems = (opts.extendDefaults === false && schema.default !== undefined) ? 0 : (schema.minItems || 0);
349355

350356
// build defined set of items
351357
if (Array.isArray(schema.items)) {

test/unit/getTemplate.test.ts

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1279,5 +1279,74 @@ describe("getTemplate", () => {
12791279

12801280
expect({ list: [], author: "jane" }).to.deep.equal(template);
12811281
});
1282+
1283+
1284+
describe("extendDefaults", () => {
1285+
1286+
it("should keep array default-value with 'extendDefaults:false'", () => {
1287+
draft.setSchema({
1288+
type: "array",
1289+
default: [],
1290+
items: {
1291+
type: "string",
1292+
enum: ["one", "two"]
1293+
},
1294+
minItems: 1 // usually adds an enty, but default states: []
1295+
});
1296+
const res = getTemplate(draft, undefined, draft.getSchema(), {
1297+
extendDefaults: false
1298+
});
1299+
1300+
expect(res).to.deep.equal([]);
1301+
});
1302+
1303+
it("should add items to array with no default-value given and 'extendDefaults:false'", () => {
1304+
draft.setSchema({
1305+
type: "array",
1306+
items: {
1307+
type: "string",
1308+
enum: ["one", "two"]
1309+
},
1310+
minItems: 1 // usually adds an enty, but default states: []
1311+
});
1312+
const res = getTemplate(draft, undefined, draft.getSchema(), {
1313+
extendDefaults: false
1314+
});
1315+
1316+
expect(res).to.deep.equal(["one"]);
1317+
});
1318+
1319+
it("should not add required items to object with default-value given and 'extendDefaults:false'", () => {
1320+
draft.setSchema({
1321+
type: "object",
1322+
required: ["title"],
1323+
default: {},
1324+
properties: {
1325+
title: { type: "string" }
1326+
}
1327+
});
1328+
const res = getTemplate(draft, undefined, draft.getSchema(), {
1329+
extendDefaults: false
1330+
});
1331+
1332+
expect(res).to.deep.equal({});
1333+
});
1334+
1335+
it("should extend object by required property with no default-value given and 'extendDefaults:false'", () => {
1336+
draft.setSchema({
1337+
type: "object",
1338+
required: ["title"],
1339+
properties: {
1340+
title: { type: "string" }
1341+
}
1342+
});
1343+
const res = getTemplate(draft, undefined, draft.getSchema(), {
1344+
extendDefaults: false
1345+
});
1346+
1347+
expect(res).to.deep.equal({ title: "" });
1348+
});
1349+
});
1350+
12821351
});
12831352
});

0 commit comments

Comments
 (0)