Skip to content

Commit 0a963ca

Browse files
authored
fix: avoid unrelated schemaOverrides when building definition for single type (YousefED#589)
1 parent ec3f098 commit 0a963ca

File tree

4 files changed

+108
-11
lines changed

4 files changed

+108
-11
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-07/schema#",
3+
"definitions": {
4+
"SomeOtherDefinition": {
5+
"type": "string"
6+
}
7+
},
8+
"properties": {
9+
"sub": {
10+
"$ref": "#/definitions/SomeOtherDefinition"
11+
}
12+
},
13+
"type": "object"
14+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-07/schema#",
3+
"definitions": {
4+
"MyObject": {
5+
"properties": {
6+
"sub": {
7+
"$ref": "#/definitions/SomeDefinition"
8+
}
9+
},
10+
"type": "object"
11+
},
12+
"MyOtherObject": {
13+
"properties": {
14+
"sub": {
15+
"$ref": "#/definitions/SomeOtherDefinition"
16+
}
17+
},
18+
"type": "object"
19+
},
20+
"SomeDefinition": {
21+
"properties": {
22+
"is": {
23+
"type": "string"
24+
}
25+
},
26+
"type": "object"
27+
},
28+
"SomeOtherDefinition": {
29+
"properties": {
30+
"is": {
31+
"type": "string"
32+
}
33+
},
34+
"type": "object"
35+
},
36+
"UnrelatedDefinition": {
37+
"type": "string"
38+
}
39+
}
40+
}

test/schema.test.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,43 @@ describe("when reusing a generator", () => {
534534
assert.deepEqual(actualSchemaObject, expectedSchemaObject, `The schema for ${symbolName} is not as expected`);
535535
});
536536
});
537+
538+
it("should not add unrelated schemaOverrides to schemas", () => {
539+
const testProgramPath = BASE + "no-unrelated-definitions/";
540+
const program = TJS.programFromConfig(resolve(testProgramPath + "tsconfig.json"));
541+
const generator = TJS.buildGenerator(program);
542+
543+
const schemaOverride: TJS.Definition = { type: "string" };
544+
generator?.setSchemaOverride("SomeOtherDefinition", schemaOverride);
545+
546+
[
547+
{ symbolName: "MyObject", schemaName: "MyObject" },
548+
{ symbolName: "MyOtherObject", schemaName: "MyOtherObjectWithOverride" },
549+
].forEach(({ symbolName, schemaName }) => {
550+
const expectedSchemaString = readFileSync(`${testProgramPath}schema.${schemaName}.json`, "utf8");
551+
const expectedSchemaObject = JSON.parse(expectedSchemaString);
552+
553+
const actualSchemaObject = generator?.getSchemaForSymbol(symbolName);
554+
555+
assert.deepEqual(actualSchemaObject, expectedSchemaObject, `The schema for ${symbolName} is not as expected`);
556+
});
557+
});
558+
559+
it("should include all schemaOverrides when generating program schemas", () => {
560+
const testProgramPath = BASE + "no-unrelated-definitions/";
561+
const program = TJS.programFromConfig(resolve(`${testProgramPath}tsconfig.json`));
562+
const generator = TJS.buildGenerator(program)!;
563+
564+
const schemaOverride: TJS.Definition = { type: "string" };
565+
generator.setSchemaOverride("UnrelatedDefinition", schemaOverride);
566+
567+
const expectedSchemaString = readFileSync(`${testProgramPath}schema.program.json`, "utf8");
568+
const expectedSchemaObject = JSON.parse(expectedSchemaString);
569+
570+
const actualSchemaObject = TJS.generateSchema(program, "*", {}, undefined, generator);
571+
572+
assert.deepEqual(actualSchemaObject, expectedSchemaObject, `The schema for whole program is not as expected`);
573+
});
537574
});
538575

539576
describe("satisfies keyword - ignore from a \"satisfies\" and build by rally type", () => {

typescript-json-schema.ts

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -534,15 +534,17 @@ export class JsonSchemaGenerator {
534534
return false;
535535
}
536536

537-
private resetSchemaSpecificProperties() {
537+
private resetSchemaSpecificProperties(includeAllOverrides: boolean = false) {
538538
this.reffedDefinitions = {};
539539
this.typeIdsByName = {};
540540
this.typeNamesById = {};
541541

542542
// restore schema overrides
543-
this.schemaOverrides.forEach((value, key) => {
544-
this.reffedDefinitions[key] = value;
545-
});
543+
if (includeAllOverrides) {
544+
this.schemaOverrides.forEach((value, key) => {
545+
this.reffedDefinitions[key] = value;
546+
});
547+
}
546548
}
547549

548550
/**
@@ -1410,8 +1412,12 @@ export class JsonSchemaGenerator {
14101412
}
14111413

14121414
// Create the actual definition only if is an inline definition, or
1413-
// if it will be a $ref and it is not yet created
1414-
if (!asRef || !this.reffedDefinitions[fullTypeName]) {
1415+
// if it will be a $ref and it is not yet created.
1416+
// Prioritise overrides.
1417+
const overrideDefinition = this.schemaOverrides.get(fullTypeName);
1418+
if (overrideDefinition) {
1419+
this.reffedDefinitions[fullTypeName] = overrideDefinition;
1420+
} else if (!asRef || !this.reffedDefinitions[fullTypeName]) {
14151421
if (asRef) {
14161422
// must be here to prevent recursivity problems
14171423
let reffedDefinition: Definition;
@@ -1511,12 +1517,12 @@ export class JsonSchemaGenerator {
15111517
this.schemaOverrides.set(symbolName, schema);
15121518
}
15131519

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

1519-
this.resetSchemaSpecificProperties();
1525+
this.resetSchemaSpecificProperties(includeAllOverrides);
15201526

15211527
const def = this.getTypeDefinition(
15221528
this.allSymbols[symbolName],
@@ -1538,13 +1544,13 @@ export class JsonSchemaGenerator {
15381544
return def;
15391545
}
15401546

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

1547-
this.resetSchemaSpecificProperties();
1553+
this.resetSchemaSpecificProperties(includeAllOverrides);
15481554

15491555
const id = this.args.id;
15501556

@@ -1742,7 +1748,7 @@ export function generateSchema(
17421748

17431749
if (fullTypeName === "*") {
17441750
// All types in file(s)
1745-
return generator.getSchemaForSymbols(generator.getMainFileSymbols(program, onlyIncludeFiles));
1751+
return generator.getSchemaForSymbols(generator.getMainFileSymbols(program, onlyIncludeFiles), true, true);
17461752
} else if (args.uniqueNames) {
17471753
// Find the hashed type name to use as the root object
17481754
const matchingSymbols = generator.getSymbols(fullTypeName);

0 commit comments

Comments
 (0)