Skip to content

Commit

Permalink
Merge pull request #489 from json-schema-tools/feat/immutable
Browse files Browse the repository at this point in the history
feat: immutable by default with option to mutate
  • Loading branch information
BelfordZ authored Feb 27, 2023
2 parents 41de3a9 + 59cf27e commit f5a58e2
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 28 deletions.
2 changes: 1 addition & 1 deletion .node-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
16.17.0
18.14.2
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ The input schema, as well as all of its subschemas must have titles. Their title
Features:
- Cyclic schemas become cyclic references
- Completely synchronous
- immutable by default, option to mutate in place.
- No external dependencies
- Fully typed against the generated [meta-schema typings](https://github.com/json-schema-tools/meta-schema/)
- magically makes your json schema smaller.
Expand Down
12 changes: 6 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

48 changes: 33 additions & 15 deletions src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,21 +103,6 @@ describe("referencer", () => {
expect(props.anotherFoo.$ref).toBe("#/definitions/foo");
});

it("does mutate the input schema", () => {
const testSchema = {
title: "foo",
type: "object",
properties: { bar: { title: "bar", type: "number" } },
};

const reffed = referencer(testSchema as JSONSchema) as JSONSchemaObject;

const props = reffed.properties as Properties;

expect(props.bar.$ref).toBe("#/definitions/bar");
expect(reffed).toBe(testSchema);
});

it("already has some refs with dupes", () => {
const testSchema = {
title: "anyOfTheThings",
Expand Down Expand Up @@ -163,4 +148,37 @@ describe("referencer", () => {
expect(defs.allOfFoo.allOf[1].$ref).toBe("#/definitions/baz");
expect(defs.baz.properties.cba.$ref).toBe("#/definitions/cba");
});

describe("Mutable", () => {
it("does not mutate the input schema", () => {
const testSchema = Object.freeze({
title: "foo",
type: "object",
properties: { bar: { title: "bar", type: "number" } },
});

const reffed = referencer(testSchema as JSONSchema) as JSONSchemaObject;

const props = reffed.properties as Properties;

expect(props.bar.$ref).toBe("#/definitions/bar");
expect(reffed).not.toBe(testSchema);
});

it("does mutate the input schema when options.mutate === true", () => {
const testSchema = {
title: "foo",
type: "object",
properties: { bar: { title: "bar", type: "number" } },
};

const reffed = referencer(testSchema as JSONSchema, { mutate: true }) as JSONSchemaObject;

const props = reffed.properties as Properties;

expect(props.bar.$ref).toBe("#/definitions/bar");
expect(reffed).toBe(testSchema);
});

});
});
30 changes: 24 additions & 6 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,20 @@ export class NoTitleError implements Error {
}
}

/**
* Options that can be passed into the Referencer.
*/
export interface ReferencerOptions {
/**
* If true, the schema passed in will be referenced in-place, mutating the original. Default is false.
*/
mutate?: boolean;
}

const defaultReferencerOptions = {
mutate: false,
};

/**
* Returns the schema where all subschemas have been replaced with $refs and added to definitions.
*
Expand All @@ -67,10 +81,10 @@ export class NoTitleError implements Error {
* @category SchemaImprover
*
*/
export default function referencer(s: JSONSchema): JSONSchema {
export default function referencer(s: JSONSchema, options: ReferencerOptions = defaultReferencerOptions): JSONSchema {
const definitions: any = {};

traverse(
let newS = traverse(
s,
(subSchema: JSONSchema, isRootCycle: boolean) => {
let t = "";
Expand Down Expand Up @@ -117,12 +131,16 @@ export default function referencer(s: JSONSchema): JSONSchema {

return subSchema;
},
{ mutable: true, skipFirstMutation: true },
{ mutable: options.mutate, skipFirstMutation: true },
);

if (typeof s === "object" && Object.keys(definitions).length > 0) {
s.definitions = { ...s.definitions, ...definitions };
if (options.mutate === true) {
newS = s;
}

if (typeof newS === "object" && Object.keys(definitions).length > 0) {
newS.definitions = { ...newS.definitions, ...definitions };
}

return s;
return newS;
}

0 comments on commit f5a58e2

Please sign in to comment.