Skip to content

Commit

Permalink
fix: avoid unrelated schemaOverrides when building definition for sin…
Browse files Browse the repository at this point in the history
…gle type (#589)
  • Loading branch information
lundibundi authored Feb 14, 2024
1 parent ec3f098 commit 0a963ca
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 11 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"SomeOtherDefinition": {
"type": "string"
}
},
"properties": {
"sub": {
"$ref": "#/definitions/SomeOtherDefinition"
}
},
"type": "object"
}
40 changes: 40 additions & 0 deletions test/programs/no-unrelated-definitions/schema.program.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"MyObject": {
"properties": {
"sub": {
"$ref": "#/definitions/SomeDefinition"
}
},
"type": "object"
},
"MyOtherObject": {
"properties": {
"sub": {
"$ref": "#/definitions/SomeOtherDefinition"
}
},
"type": "object"
},
"SomeDefinition": {
"properties": {
"is": {
"type": "string"
}
},
"type": "object"
},
"SomeOtherDefinition": {
"properties": {
"is": {
"type": "string"
}
},
"type": "object"
},
"UnrelatedDefinition": {
"type": "string"
}
}
}
37 changes: 37 additions & 0 deletions test/schema.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,43 @@ describe("when reusing a generator", () => {
assert.deepEqual(actualSchemaObject, expectedSchemaObject, `The schema for ${symbolName} is not as expected`);
});
});

it("should not add unrelated schemaOverrides to schemas", () => {
const testProgramPath = BASE + "no-unrelated-definitions/";
const program = TJS.programFromConfig(resolve(testProgramPath + "tsconfig.json"));
const generator = TJS.buildGenerator(program);

const schemaOverride: TJS.Definition = { type: "string" };
generator?.setSchemaOverride("SomeOtherDefinition", schemaOverride);

[
{ symbolName: "MyObject", schemaName: "MyObject" },
{ symbolName: "MyOtherObject", schemaName: "MyOtherObjectWithOverride" },
].forEach(({ symbolName, schemaName }) => {
const expectedSchemaString = readFileSync(`${testProgramPath}schema.${schemaName}.json`, "utf8");
const expectedSchemaObject = JSON.parse(expectedSchemaString);

const actualSchemaObject = generator?.getSchemaForSymbol(symbolName);

assert.deepEqual(actualSchemaObject, expectedSchemaObject, `The schema for ${symbolName} is not as expected`);
});
});

it("should include all schemaOverrides when generating program schemas", () => {
const testProgramPath = BASE + "no-unrelated-definitions/";
const program = TJS.programFromConfig(resolve(`${testProgramPath}tsconfig.json`));
const generator = TJS.buildGenerator(program)!;

const schemaOverride: TJS.Definition = { type: "string" };
generator.setSchemaOverride("UnrelatedDefinition", schemaOverride);

const expectedSchemaString = readFileSync(`${testProgramPath}schema.program.json`, "utf8");
const expectedSchemaObject = JSON.parse(expectedSchemaString);

const actualSchemaObject = TJS.generateSchema(program, "*", {}, undefined, generator);

assert.deepEqual(actualSchemaObject, expectedSchemaObject, `The schema for whole program is not as expected`);
});
});

describe("satisfies keyword - ignore from a \"satisfies\" and build by rally type", () => {
Expand Down
28 changes: 17 additions & 11 deletions typescript-json-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -534,15 +534,17 @@ export class JsonSchemaGenerator {
return false;
}

private resetSchemaSpecificProperties() {
private resetSchemaSpecificProperties(includeAllOverrides: boolean = false) {
this.reffedDefinitions = {};
this.typeIdsByName = {};
this.typeNamesById = {};

// restore schema overrides
this.schemaOverrides.forEach((value, key) => {
this.reffedDefinitions[key] = value;
});
if (includeAllOverrides) {
this.schemaOverrides.forEach((value, key) => {
this.reffedDefinitions[key] = value;
});
}
}

/**
Expand Down Expand Up @@ -1410,8 +1412,12 @@ export class JsonSchemaGenerator {
}

// Create the actual definition only if is an inline definition, or
// if it will be a $ref and it is not yet created
if (!asRef || !this.reffedDefinitions[fullTypeName]) {
// if it will be a $ref and it is not yet created.
// Prioritise overrides.
const overrideDefinition = this.schemaOverrides.get(fullTypeName);
if (overrideDefinition) {
this.reffedDefinitions[fullTypeName] = overrideDefinition;
} else if (!asRef || !this.reffedDefinitions[fullTypeName]) {
if (asRef) {
// must be here to prevent recursivity problems
let reffedDefinition: Definition;
Expand Down Expand Up @@ -1511,12 +1517,12 @@ export class JsonSchemaGenerator {
this.schemaOverrides.set(symbolName, schema);
}

public getSchemaForSymbol(symbolName: string, includeReffedDefinitions: boolean = true): Definition {
public getSchemaForSymbol(symbolName: string, includeReffedDefinitions: boolean = true, includeAllOverrides: boolean = false): Definition {
if (!this.allSymbols[symbolName]) {
throw new Error(`type ${symbolName} not found`);
}

this.resetSchemaSpecificProperties();
this.resetSchemaSpecificProperties(includeAllOverrides);

const def = this.getTypeDefinition(
this.allSymbols[symbolName],
Expand All @@ -1538,13 +1544,13 @@ export class JsonSchemaGenerator {
return def;
}

public getSchemaForSymbols(symbolNames: string[], includeReffedDefinitions: boolean = true): Definition {
public getSchemaForSymbols(symbolNames: string[], includeReffedDefinitions: boolean = true, includeAllOverrides: boolean = false): Definition {
const root = {
$schema: "http://json-schema.org/draft-07/schema#",
definitions: {},
};

this.resetSchemaSpecificProperties();
this.resetSchemaSpecificProperties(includeAllOverrides);

const id = this.args.id;

Expand Down Expand Up @@ -1742,7 +1748,7 @@ export function generateSchema(

if (fullTypeName === "*") {
// All types in file(s)
return generator.getSchemaForSymbols(generator.getMainFileSymbols(program, onlyIncludeFiles));
return generator.getSchemaForSymbols(generator.getMainFileSymbols(program, onlyIncludeFiles), true, true);
} else if (args.uniqueNames) {
// Find the hashed type name to use as the root object
const matchingSymbols = generator.getSymbols(fullTypeName);
Expand Down

0 comments on commit 0a963ca

Please sign in to comment.