Skip to content

Commit fa9b8b5

Browse files
committed
fix: all tests pass - including vega-lite!
1 parent ab6eafb commit fa9b8b5

File tree

29 files changed

+374
-384
lines changed

29 files changed

+374
-384
lines changed

package.json

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
"ajv": "^7.1.1",
6767
"ajv-formats": "^1.5.1",
6868
"chai": "^4.3.0",
69+
"cross-env": "^7.0.3",
6970
"eslint": "^7.20.0",
7071
"eslint-config-prettier": "^7.2.0",
7172
"eslint-plugin-prettier": "^3.3.1",
@@ -82,11 +83,12 @@
8283
"lint": "eslint {src,test,factory}/**/*.ts",
8384
"format": "yarn lint --fix",
8485
"test": "jest test/ --verbose",
85-
"test:fast": "FAST_TEST=1 jest test/ --verbose",
86+
"test:fast": "cross-env FAST_TEST=1 jest test/ --verbose",
8687
"test:coverage": "yarn jest test/ --collectCoverage=true",
87-
"test:update": "UPDATE_SCHEMA=true yarn test:fast",
88+
"test:update": "cross-env UPDATE_SCHEMA=true yarn test:fast",
8889
"debug": "node -r ts-node/register --inspect-brk ts-json-schema-generator.ts",
89-
"dbg": "node -r ts-node/register --inspect-brk ts-json-schema-generator.ts -p test/valid-data/duplicates-composition/main.ts -t MyObject",
90+
"dbg": "node -r ts-node/register --inspect-brk ts-json-schema-generator.ts -p test/valid-data/type-aliases-recursive-anonymous/main.ts -t MyAlias",
91+
"dbg-vega": "node -r ts-node/register --inspect-brk ts-json-schema-generator.ts -p ../../../tmp/vega-lite/src/index.ts -t TopLevelSpec --no-type-check --no-ref-encode > ../../../tmp/vega-lite/build/vega-lite-schema2.json",
9092
"run": "ts-node ts-json-schema-generator.ts"
9193
},
9294
"release": {

src/SchemaGenerator.ts

Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ import { removeUnreachable } from "./Utils/removeUnreachable";
1313
import { Config } from "./Config";
1414
import { hasJsDocTag } from "./Utils/hasJsDocTag";
1515
import { JSONSchema7, JSONSchema7Definition } from "json-schema";
16+
import { derefType } from "./Utils/derefType";
17+
import { AliasType } from "./Type/AliasType";
18+
import { ObjectType } from "./Type/ObjectType";
1619

1720
export class SchemaGenerator {
1821
public constructor(
@@ -40,22 +43,6 @@ export class SchemaGenerator {
4043
rootTypes.forEach((rootType) => this.appendRootChildDefinitions(rootType, definitions, idNameMap));
4144
const reachableDefinitions = removeUnreachable(rootTypeDefinition, definitions);
4245

43-
if (true) {
44-
// TODO: remove this.
45-
console.log(
46-
JSON.stringify(
47-
{
48-
rootTypeDefinition,
49-
definitions,
50-
reachableDefinitions,
51-
},
52-
null,
53-
2
54-
)
55-
);
56-
console.log(idNameMap);
57-
}
58-
5946
// create schema - all $ref's use getId().
6047
const schema: JSONSchema7Definition = {
6148
...(this.config?.schemaId ? { $id: this.config.schemaId } : {}),
@@ -121,19 +108,19 @@ export class SchemaGenerator {
121108

122109
const duplicates: StringMap<Set<DefinitionType>> = {};
123110
for (const child of children) {
124-
const name = child.getName(); // .replace(/^def-interface/, "interface");
111+
const name = child.getName();
125112
duplicates[name] = duplicates[name] ?? new Set<DefinitionType>();
126113
duplicates[name].add(child);
127114
}
128115

129116
children.reduce((definitions, child) => {
130-
const id = child.getId(); // .replace(/^def-interface/, "interface");
117+
const id = child.getId().replace(/^def-/, "");
131118
if (!(id in definitions)) {
119+
const name = unambiguousName(child, child === rootType, [...duplicates[child.getName()]]);
132120
// Record the schema against the ID, allowing steps like removeUnreachable to work
133121
definitions[id] = this.typeFormatter.getDefinition(child.getType());
134122
// Create a record of id->name mapping. This is used in the final step
135123
// to resolve id -> name before delivering the schema to caller.
136-
const name = unambiguousName(child, child === rootType, [...duplicates[child.getName()]]);
137124
idNameMap.set(id, name);
138125
}
139126
return definitions;
@@ -222,17 +209,33 @@ function getCommonPrefixes(paths: string[]) {
222209
);
223210
}
224211

225-
function unambiguousName(child: DefinitionType, isRoot: boolean, peers: DefinitionType[]) {
212+
function unambiguousName(child: DefinitionType, isRoot: boolean, peers: DefinitionType[]): string {
226213
if (peers.length === 1 || isRoot) {
227214
return child.getName();
228-
} else {
215+
} else if (child.getType().getSrcFileName()) {
229216
let index = -1;
230-
const srcPaths = peers.map((peer: DefinitionType, count) => {
217+
218+
// filter unique peers to be those that have srcFileNames.
219+
// Intermediate Types - AnnotationTypes, UnionTypes, do not have sourceFileNames
220+
const uniques = peers.filter((peer) => peer.getType().getSrcFileName());
221+
if (uniques.length === 1) {
222+
return uniques[0].getName();
223+
}
224+
const srcPaths = uniques.map((peer: DefinitionType, count) => {
231225
index = child === peer ? count : index;
232-
return peer.getType().getSrcFileName();
226+
return peer.getType().getSrcFileName()!;
233227
});
234228
const prefixes = getCommonPrefixes(srcPaths);
235229
return `${prefixes[index]}-${child.getName()}`;
230+
} else {
231+
// intermediate type.
232+
const name = child.getName();
233+
// TODO: Perhaps we should maintain a name-id map, and throw a duplicate error on collision.
234+
if (name === undefined) {
235+
// this might be unreachable code.
236+
throw new Error(`Unable to disambiguate types`);
237+
}
238+
return name;
236239
}
237240
}
238241

src/Type/BaseType.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export abstract class BaseType {
1212
* Provide a base class implementation. Will only be exported for entities
1313
* exposed in a schema - Alias|Enum|Class|Interface.
1414
*/
15-
public getSrcFileName(): string {
16-
throw new Error(`Missing sourceFileName '${this.getId()}'`);
15+
public getSrcFileName(): string | null {
16+
return null;
1717
}
1818
}

src/Type/DefinitionType.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export class DefinitionType extends BaseType {
1717
return this.type;
1818
}
1919

20-
public getSrcFileName(): string {
20+
public getSrcFileName(): string | null {
2121
return this.type.getSrcFileName();
2222
}
2323
}

src/TypeFormatter/DefinitionTypeFormatter.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export class DefinitionTypeFormatter implements SubTypeFormatter {
1212
return type instanceof DefinitionType;
1313
}
1414
public getDefinition(type: DefinitionType): Definition {
15-
const ref = type.getId();
15+
const ref = type.getId().replace(/^def-/, "");
1616
return { $ref: `#/definitions/${this.encodeRefs ? encodeURIComponent(ref) : ref}` };
1717
}
1818
public getChildren(type: DefinitionType): BaseType[] {

src/TypeFormatter/ReferenceTypeFormatter.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export class ReferenceTypeFormatter implements SubTypeFormatter {
1212
return type instanceof ReferenceType;
1313
}
1414
public getDefinition(type: ReferenceType): Definition {
15-
const ref = type.getId();
15+
const ref = type.getId().replace(/^def-/, "");
1616
return { $ref: `#/definitions/${this.encodeRefs ? encodeURIComponent(ref) : ref}` };
1717
}
1818
public getChildren(type: ReferenceType): BaseType[] {

test/valid-data/annotation-custom/schema.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,5 @@
1818
"customUnquotedProperty": "not-a-valid-json",
1919
"type": "object"
2020
}
21+
}
2122
}
Lines changed: 48 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,54 @@
11
{
2-
"$schema": "http://json-schema.org/draft-07/schema#",
3-
"$ref": "#/definitions/MyObject",
4-
"definitions": {
5-
"MyObject": {
6-
"type": "object",
7-
"required": [
8-
"a",
9-
"b",
10-
"c",
11-
"d"
12-
],
13-
"properties": {
14-
"a": {
15-
"type": "number"
16-
},
17-
"b": {
18-
"type": "string"
19-
},
20-
"c": {
21-
"$ref": "#/definitions/Base%3Cstring%3E"
22-
},
23-
"d": {
24-
"$ref": "#/definitions/Base%3Cboolean%3E"
25-
}
26-
},
27-
"additionalProperties": false
2+
"$ref": "#/definitions/MyObject",
3+
"$schema": "http://json-schema.org/draft-07/schema#",
4+
"definitions": {
5+
"Base<boolean>": {
6+
"additionalProperties": false,
7+
"properties": {
8+
"a": {
9+
"type": "boolean"
10+
}
11+
},
12+
"required": [
13+
"a"
14+
],
15+
"type": "object"
16+
},
17+
"Base<string>": {
18+
"additionalProperties": false,
19+
"properties": {
20+
"a": {
21+
"type": "string"
22+
}
23+
},
24+
"required": [
25+
"a"
26+
],
27+
"type": "object"
28+
},
29+
"MyObject": {
30+
"additionalProperties": false,
31+
"properties": {
32+
"a": {
33+
"type": "number"
34+
},
35+
"b": {
36+
"type": "string"
2837
},
29-
"Base<string>": {
30-
"type": "object",
31-
"required": [
32-
"a"
33-
],
34-
"properties": {
35-
"a": {
36-
"type": "string"
37-
}
38-
},
39-
"additionalProperties": false
38+
"c": {
39+
"$ref": "#/definitions/Base%3Cstring%3E"
4040
},
41-
"Base<boolean>": {
42-
"type": "object",
43-
"required": [
44-
"a"
45-
],
46-
"properties": {
47-
"a": {
48-
"type": "boolean"
49-
}
50-
},
51-
"additionalProperties": false
41+
"d": {
42+
"$ref": "#/definitions/Base%3Cboolean%3E"
5243
}
44+
},
45+
"required": [
46+
"a",
47+
"b",
48+
"c",
49+
"d"
50+
],
51+
"type": "object"
5352
}
53+
}
5454
}
Lines changed: 41 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,46 @@
11
{
2-
"$schema": "http://json-schema.org/draft-07/schema#",
3-
"$ref": "#/definitions/MyObject",
4-
"definitions": {
5-
"MyObject": {
6-
"type": "object",
7-
"required": [
8-
"a",
9-
"b"
10-
],
11-
"properties": {
12-
"a": {
13-
"$ref": "#/definitions/componentA-MyObject"
14-
},
15-
"b": {
16-
"$ref": "#/definitions/componentB-MyObject"
17-
}
18-
},
19-
"additionalProperties": false
2+
"$ref": "#/definitions/MyObject",
3+
"$schema": "http://json-schema.org/draft-07/schema#",
4+
"definitions": {
5+
"MyObject": {
6+
"additionalProperties": false,
7+
"properties": {
8+
"a": {
9+
"$ref": "#/definitions/componentA-MyObject"
2010
},
21-
"componentA-MyObject": {
22-
"type": "object",
23-
"required": [
24-
"a"
25-
],
26-
"properties": {
27-
"a": {
28-
"type": "string"
29-
}
30-
},
31-
"additionalProperties": false
32-
},
33-
"componentB-MyObject": {
34-
"type": "object",
35-
"required": [
36-
"b"
37-
],
38-
"properties": {
39-
"b": {
40-
"type": "string"
41-
}
42-
},
43-
"additionalProperties": false
11+
"b": {
12+
"$ref": "#/definitions/componentB-MyObject"
13+
}
14+
},
15+
"required": [
16+
"a",
17+
"b"
18+
],
19+
"type": "object"
20+
},
21+
"componentA-MyObject": {
22+
"additionalProperties": false,
23+
"properties": {
24+
"a": {
25+
"type": "string"
26+
}
27+
},
28+
"required": [
29+
"a"
30+
],
31+
"type": "object"
32+
},
33+
"componentB-MyObject": {
34+
"additionalProperties": false,
35+
"properties": {
36+
"b": {
37+
"type": "string"
4438
}
39+
},
40+
"required": [
41+
"b"
42+
],
43+
"type": "object"
4544
}
45+
}
4646
}

0 commit comments

Comments
 (0)