Skip to content

Commit

Permalink
Merge pull request #1937 from vega/next
Browse files Browse the repository at this point in the history
Release
  • Loading branch information
domoritz committed Apr 23, 2024
2 parents 6b6c47e + 9043546 commit 3c112c5
Show file tree
Hide file tree
Showing 11 changed files with 168 additions and 124 deletions.
7 changes: 1 addition & 6 deletions .github/workflows/test.yml
Expand Up @@ -12,12 +12,7 @@ jobs:
test:
name: Test

strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest]

runs-on: ${{ matrix.os }}
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
Expand Down
File renamed without changes.
10 changes: 5 additions & 5 deletions package.json
Expand Up @@ -6,7 +6,7 @@
"types": "dist/index.d.ts",
"type": "module",
"bin": {
"ts-json-schema-generator": "./bin/ts-json-schema-generator"
"ts-json-schema-generator": "./bin/ts-json-schema-generator.js"
},
"files": [
"dist",
Expand Down Expand Up @@ -59,8 +59,8 @@
"@babel/core": "^7.24.4",
"@babel/preset-env": "^7.24.4",
"@babel/preset-typescript": "^7.24.1",
"@eslint/js": "^9.0.0",
"@types/eslint": "^8.56.9",
"@eslint/js": "^9.1.1",
"@types/eslint": "^8.56.10",
"@types/glob": "^8.1.0",
"@types/jest": "^29.5.12",
"@types/node": "^20.12.7",
Expand All @@ -70,14 +70,14 @@
"auto": "^11.1.6",
"chai": "^5.1.0",
"cross-env": "^7.0.3",
"eslint": "^9.0.0",
"eslint": "^9.1.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.1.3",
"jest": "^29.7.0",
"jest-junit": "^16.0.0",
"prettier": "^3.2.5",
"tsx": "^4.7.2",
"typescript-eslint": "^7.7.0",
"typescript-eslint": "^7.7.1",
"vega": "^5.28.0",
"vega-lite": "^5.18.0"
},
Expand Down
10 changes: 3 additions & 7 deletions src/NodeParser/MappedTypeNodeParser.ts
Expand Up @@ -18,6 +18,7 @@ import { derefAnnotatedType, derefType } from "../Utils/derefType.js";
import { getKey } from "../Utils/nodeKey.js";
import { preserveAnnotation } from "../Utils/preserveAnnotation.js";
import { removeUndefined } from "../Utils/removeUndefined.js";
import { uniqueTypeArray } from "../Utils/uniqueTypeArray.js";

export class MappedTypeNodeParser implements SubNodeParser {
public constructor(
Expand Down Expand Up @@ -94,16 +95,11 @@ export class MappedTypeNodeParser implements SubNodeParser {
if (!node.nameType) {
return rawKey;
}
const key = derefType(
this.childNodeParser.createType(node.nameType, this.createSubContext(node, rawKey, context)),
);

return key;
return derefType(this.childNodeParser.createType(node.nameType, this.createSubContext(node, rawKey, context)));
}

protected getProperties(node: ts.MappedTypeNode, keyListType: UnionType, context: Context): ObjectProperty[] {
return keyListType
.getTypes()
return uniqueTypeArray(keyListType.getFlattenedTypes(derefType))
.filter((type): type is LiteralType => type instanceof LiteralType)
.map((type) => [type, this.mapKey(node, type, context)])
.filter((value): value is [LiteralType, LiteralType] => value[1] instanceof LiteralType)
Expand Down
17 changes: 16 additions & 1 deletion src/Type/UnionType.ts
@@ -1,7 +1,7 @@
import { BaseType } from "./BaseType.js";
import { uniqueTypeArray } from "../Utils/uniqueTypeArray.js";
import { NeverType } from "./NeverType.js";
import { derefType } from "../Utils/derefType.js";
import { derefAliasedType, derefType, isHiddenType } from "../Utils/derefType.js";

export class UnionType extends BaseType {
private readonly types: BaseType[];
Expand Down Expand Up @@ -56,4 +56,19 @@ export class UnionType extends BaseType {
}
}
}

/**
* Get the types in this union as a flat list.
*/
public getFlattenedTypes(deref: (type: BaseType) => BaseType = derefAliasedType): BaseType[] {
return this.getTypes()
.filter((t) => !isHiddenType(t))
.map(deref)
.flatMap((t) => {
if (t instanceof UnionType) {
return t.getFlattenedTypes(deref);
}
return t;
});
}
}
24 changes: 5 additions & 19 deletions src/TypeFormatter/LiteralUnionTypeFormatter.ts
Expand Up @@ -6,7 +6,6 @@ import { LiteralType, LiteralValue } from "../Type/LiteralType.js";
import { NullType } from "../Type/NullType.js";
import { StringType } from "../Type/StringType.js";
import { UnionType } from "../Type/UnionType.js";
import { derefAliasedType, isHiddenType } from "../Utils/derefType.js";
import { typeName } from "../Utils/typeName.js";
import { uniqueArray } from "../Utils/uniqueArray.js";

Expand All @@ -20,10 +19,10 @@ export class LiteralUnionTypeFormatter implements SubTypeFormatter {
let allStrings = true;
let hasNull = false;

const flattenedTypes = flattenTypes(type);
const literals = type.getFlattenedTypes();

// filter out String types since we need to be more careful about them
const types = flattenedTypes.filter((t) => {
const types = literals.filter((t) => {
if (t instanceof StringType) {
hasString = true;
preserveLiterals = preserveLiterals || t.getPreserveLiterals();
Expand Down Expand Up @@ -70,23 +69,10 @@ export class LiteralUnionTypeFormatter implements SubTypeFormatter {
}
}

function flattenTypes(type: UnionType): (StringType | LiteralType | NullType)[] {
return type
.getTypes()
.filter((t) => !isHiddenType(t))
.map(derefAliasedType)
.flatMap((t) => {
if (t instanceof UnionType) {
return flattenTypes(t);
}
return t as StringType | LiteralType | NullType;
});
}

export function isLiteralUnion(type: UnionType): boolean {
return flattenTypes(type).every(
(item) => item instanceof LiteralType || item instanceof NullType || item instanceof StringType,
);
return type
.getFlattenedTypes()
.every((item) => item instanceof LiteralType || item instanceof NullType || item instanceof StringType);
}

function getLiteralValue(value: LiteralType | NullType): LiteralValue | null {
Expand Down
1 change: 1 addition & 0 deletions test/valid-data-type.test.ts
Expand Up @@ -102,6 +102,7 @@ describe("valid-data-type", () => {
it("type-mapped-additional-props", assertValidSchema("type-mapped-additional-props", "MyObject"));
it("type-mapped-array", assertValidSchema("type-mapped-array", "MyObject"));
it("type-mapped-union-intersection", assertValidSchema("type-mapped-union-intersection", "MyObject"));
it("type-mapped-union-union", assertValidSchema("type-mapped-union-union", "MyType"));
it("type-mapped-enum", assertValidSchema("type-mapped-enum", "MyObject"));
it("type-mapped-enum-optional", assertValidSchema("type-mapped-enum-optional", "MyObject"));
it("type-mapped-enum-null", assertValidSchema("type-mapped-enum-null", "MyObject"));
Expand Down
6 changes: 6 additions & 0 deletions test/valid-data/type-mapped-union-union/main.ts
@@ -0,0 +1,6 @@
type MyType1 = "s1";
type MyType2 = MyType1 | "s2" | "s3";
type MyType3 = MyType2 | "s4" | "s5";
type MyType10 = MyType3 | MyType2 | "s6";

export type MyType = Record<MyType10, string>;
40 changes: 40 additions & 0 deletions test/valid-data/type-mapped-union-union/schema.json
@@ -0,0 +1,40 @@
{
"$ref": "#/definitions/MyType",
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"MyType": {
"additionalProperties": {
"type": "string"
},
"properties": {
"s1": {
"type": "string"
},
"s2": {
"type": "string"
},
"s3": {
"type": "string"
},
"s4": {
"type": "string"
},
"s5": {
"type": "string"
},
"s6": {
"type": "string"
}
},
"required": [
"s1",
"s2",
"s3",
"s4",
"s5",
"s6"
],
"type": "object"
}
}
}
2 changes: 1 addition & 1 deletion tsconfig.eslint.json
@@ -1,4 +1,4 @@
{
"extends": "./tsconfig.json",
"include": ["src/**/*.ts", "factory/**/*.ts", "test/**/*.test.ts", "test/utils.ts"]
"include": ["src/**/*.ts", "factory/**/*.ts", "test/**/*.test.ts", "test/utils.ts", "bin/ts-json-schema-generator.js"]
}

0 comments on commit 3c112c5

Please sign in to comment.