ts-json-schema-generator 2.5.0-next.8 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/factory/parser.js +3 -0
- package/dist/factory/parser.js.map +1 -1
- package/dist/factory/program.js +6 -3
- package/dist/factory/program.js.map +1 -1
- package/dist/package.json +28 -33
- package/dist/src/AnnotationsReader/BasicAnnotationsReader.js +6 -0
- package/dist/src/AnnotationsReader/BasicAnnotationsReader.js.map +1 -1
- package/dist/src/AnnotationsReader/ExtendedAnnotationsReader.d.ts +4 -0
- package/dist/src/AnnotationsReader/ExtendedAnnotationsReader.js +7 -0
- package/dist/src/AnnotationsReader/ExtendedAnnotationsReader.js.map +1 -1
- package/dist/src/Config.d.ts +99 -0
- package/dist/src/Error/BaseError.d.ts +6 -1
- package/dist/src/Error/BaseError.js +8 -2
- package/dist/src/Error/BaseError.js.map +1 -1
- package/dist/src/Error/Errors.d.ts +3 -0
- package/dist/src/Error/Errors.js +5 -0
- package/dist/src/Error/Errors.js.map +1 -1
- package/dist/src/NodeParser/AnnotatedNodeParser.js +5 -0
- package/dist/src/NodeParser/AnnotatedNodeParser.js.map +1 -1
- package/dist/src/NodeParser/ArrayNodeParser.js +1 -0
- package/dist/src/NodeParser/ArrayNodeParser.js.map +1 -1
- package/dist/src/NodeParser/AsExpressionNodeParser.js +1 -0
- package/dist/src/NodeParser/AsExpressionNodeParser.js.map +1 -1
- package/dist/src/NodeParser/BinaryExpressionNodeParser.d.ts +13 -0
- package/dist/src/NodeParser/BinaryExpressionNodeParser.js +84 -0
- package/dist/src/NodeParser/BinaryExpressionNodeParser.js.map +1 -0
- package/dist/src/NodeParser/CallExpressionParser.js +6 -0
- package/dist/src/NodeParser/CallExpressionParser.js.map +1 -1
- package/dist/src/NodeParser/ConditionalTypeNodeParser.d.ts +16 -0
- package/dist/src/NodeParser/ConditionalTypeNodeParser.js +22 -0
- package/dist/src/NodeParser/ConditionalTypeNodeParser.js.map +1 -1
- package/dist/src/NodeParser/FunctionNodeParser.js +1 -0
- package/dist/src/NodeParser/FunctionNodeParser.js.map +1 -1
- package/dist/src/NodeParser/IdentifierNodeParser.d.ts +3 -0
- package/dist/src/NodeParser/IdentifierNodeParser.js +3 -0
- package/dist/src/NodeParser/IdentifierNodeParser.js.map +1 -1
- package/dist/src/NodeParser/IndexedAccessTypeNodeParser.js +4 -1
- package/dist/src/NodeParser/IndexedAccessTypeNodeParser.js.map +1 -1
- package/dist/src/NodeParser/InterfaceAndClassNodeParser.d.ts +7 -0
- package/dist/src/NodeParser/InterfaceAndClassNodeParser.js +10 -0
- package/dist/src/NodeParser/InterfaceAndClassNodeParser.js.map +1 -1
- package/dist/src/NodeParser/IntersectionNodeParser.d.ts +4 -0
- package/dist/src/NodeParser/IntersectionNodeParser.js +8 -0
- package/dist/src/NodeParser/IntersectionNodeParser.js.map +1 -1
- package/dist/src/NodeParser/MappedTypeNodeParser.js +12 -5
- package/dist/src/NodeParser/MappedTypeNodeParser.js.map +1 -1
- package/dist/src/NodeParser/ObjectLiteralExpressionNodeParser.js +1 -0
- package/dist/src/NodeParser/ObjectLiteralExpressionNodeParser.js.map +1 -1
- package/dist/src/NodeParser/PrefixUnaryExpressionNodeParser.js +1 -0
- package/dist/src/NodeParser/PrefixUnaryExpressionNodeParser.js.map +1 -1
- package/dist/src/NodeParser/PromiseNodeParser.d.ts +3 -0
- package/dist/src/NodeParser/PromiseNodeParser.js +19 -1
- package/dist/src/NodeParser/PromiseNodeParser.js.map +1 -1
- package/dist/src/NodeParser/SpreadElementNodeParser.d.ts +4 -0
- package/dist/src/NodeParser/SpreadElementNodeParser.js +4 -0
- package/dist/src/NodeParser/SpreadElementNodeParser.js.map +1 -1
- package/dist/src/NodeParser/TypeLiteralNodeParser.js +5 -0
- package/dist/src/NodeParser/TypeLiteralNodeParser.js.map +1 -1
- package/dist/src/NodeParser/TypeOperatorNodeParser.js +1 -0
- package/dist/src/NodeParser/TypeOperatorNodeParser.js.map +1 -1
- package/dist/src/NodeParser/TypeReferenceNodeParser.js +6 -0
- package/dist/src/NodeParser/TypeReferenceNodeParser.js.map +1 -1
- package/dist/src/NodeParser/TypeofNodeParser.js +1 -0
- package/dist/src/NodeParser/TypeofNodeParser.js.map +1 -1
- package/dist/src/SchemaGenerator.js +28 -1
- package/dist/src/SchemaGenerator.js.map +1 -1
- package/dist/src/Type/AnnotatedType.d.ts +1 -3
- package/dist/src/Type/AnnotatedType.js.map +1 -1
- package/dist/src/Type/BaseType.d.ts +3 -0
- package/dist/src/Type/BaseType.js +3 -0
- package/dist/src/Type/BaseType.js.map +1 -1
- package/dist/src/Type/ObjectType.js +3 -1
- package/dist/src/Type/ObjectType.js.map +1 -1
- package/dist/src/Type/UnionType.d.ts +3 -0
- package/dist/src/Type/UnionType.js +3 -0
- package/dist/src/Type/UnionType.js.map +1 -1
- package/dist/src/Type/UnknownType.d.ts +11 -1
- package/dist/src/Type/UnknownType.js +8 -1
- package/dist/src/Type/UnknownType.js.map +1 -1
- package/dist/src/TypeFormatter/AnnotatedTypeFormatter.js +2 -1
- package/dist/src/TypeFormatter/AnnotatedTypeFormatter.js.map +1 -1
- package/dist/src/TypeFormatter/EnumTypeFormatter.d.ts +3 -0
- package/dist/src/TypeFormatter/EnumTypeFormatter.js +7 -0
- package/dist/src/TypeFormatter/EnumTypeFormatter.js.map +1 -1
- package/dist/src/TypeFormatter/IntersectionTypeFormatter.js +3 -0
- package/dist/src/TypeFormatter/IntersectionTypeFormatter.js.map +1 -1
- package/dist/src/TypeFormatter/LiteralUnionTypeFormatter.js +7 -0
- package/dist/src/TypeFormatter/LiteralUnionTypeFormatter.js.map +1 -1
- package/dist/src/TypeFormatter/ReferenceTypeFormatter.js +6 -0
- package/dist/src/TypeFormatter/ReferenceTypeFormatter.js.map +1 -1
- package/dist/src/TypeFormatter/TupleTypeFormatter.js +12 -5
- package/dist/src/TypeFormatter/TupleTypeFormatter.js.map +1 -1
- package/dist/src/TypeFormatter/UnionTypeFormatter.js +1 -0
- package/dist/src/TypeFormatter/UnionTypeFormatter.js.map +1 -1
- package/dist/src/Utils/allOfDefinition.js +5 -0
- package/dist/src/Utils/allOfDefinition.js.map +1 -1
- package/dist/src/Utils/deepMerge.d.ts +8 -0
- package/dist/src/Utils/deepMerge.js +9 -0
- package/dist/src/Utils/deepMerge.js.map +1 -1
- package/dist/src/Utils/derefType.d.ts +6 -0
- package/dist/src/Utils/derefType.js +6 -0
- package/dist/src/Utils/derefType.js.map +1 -1
- package/dist/src/Utils/intersectionOfArrays.js +1 -0
- package/dist/src/Utils/intersectionOfArrays.js.map +1 -1
- package/dist/src/Utils/isAssignableTo.d.ts +12 -0
- package/dist/src/Utils/isAssignableTo.js +54 -0
- package/dist/src/Utils/isAssignableTo.js.map +1 -1
- package/dist/src/Utils/modifiers.d.ts +19 -0
- package/dist/src/Utils/modifiers.js +19 -0
- package/dist/src/Utils/modifiers.js.map +1 -1
- package/dist/src/Utils/narrowType.d.ts +12 -0
- package/dist/src/Utils/narrowType.js +15 -0
- package/dist/src/Utils/narrowType.js.map +1 -1
- package/dist/src/Utils/nodeKey.d.ts +1 -1
- package/dist/src/Utils/nodeKey.js +7 -1
- package/dist/src/Utils/nodeKey.js.map +1 -1
- package/dist/src/Utils/preserveAnnotation.d.ts +6 -0
- package/dist/src/Utils/preserveAnnotation.js +6 -0
- package/dist/src/Utils/preserveAnnotation.js.map +1 -1
- package/dist/src/Utils/removeUndefined.d.ts +3 -0
- package/dist/src/Utils/removeUndefined.js +3 -0
- package/dist/src/Utils/removeUndefined.js.map +1 -1
- package/dist/src/Utils/removeUnreachable.js +1 -0
- package/dist/src/Utils/removeUnreachable.js.map +1 -1
- package/dist/src/Utils/symbolAtNode.js +1 -0
- package/dist/src/Utils/symbolAtNode.js.map +1 -1
- package/dist/src/Utils/typeKeys.js +1 -0
- package/dist/src/Utils/typeKeys.js.map +1 -1
- package/dist/ts-json-schema-generator.js +6 -7
- package/dist/ts-json-schema-generator.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/factory/parser.ts +2 -0
- package/factory/program.ts +8 -4
- package/package.json +28 -33
- package/src/Error/BaseError.ts +1 -3
- package/src/NodeParser/BinaryExpressionNodeParser.ts +99 -0
- package/src/NodeParser/IndexedAccessTypeNodeParser.ts +4 -1
- package/src/NodeParser/MappedTypeNodeParser.ts +12 -8
- package/src/SchemaGenerator.ts +18 -3
- package/src/Type/AnnotatedType.ts +1 -3
- package/src/Type/UnknownType.ts +1 -1
- package/src/TypeFormatter/AnnotatedTypeFormatter.ts +2 -2
- package/src/Utils/narrowType.ts +1 -6
- package/src/Utils/nodeKey.ts +3 -1
- package/ts-json-schema-generator.ts +2 -11
package/factory/parser.ts
CHANGED
|
@@ -12,6 +12,7 @@ import { AnyTypeNodeParser } from "../src/NodeParser/AnyTypeNodeParser.js";
|
|
|
12
12
|
import { ArrayLiteralExpressionNodeParser } from "../src/NodeParser/ArrayLiteralExpressionNodeParser.js";
|
|
13
13
|
import { ArrayNodeParser } from "../src/NodeParser/ArrayNodeParser.js";
|
|
14
14
|
import { AsExpressionNodeParser } from "../src/NodeParser/AsExpressionNodeParser.js";
|
|
15
|
+
import { BinaryExpressionNodeParser } from "../src/NodeParser/BinaryExpressionNodeParser.js";
|
|
15
16
|
import { BooleanLiteralNodeParser } from "../src/NodeParser/BooleanLiteralNodeParser.js";
|
|
16
17
|
import { BooleanTypeNodeParser } from "../src/NodeParser/BooleanTypeNodeParser.js";
|
|
17
18
|
import { CallExpressionParser } from "../src/NodeParser/CallExpressionParser.js";
|
|
@@ -118,6 +119,7 @@ export function createParser(program: ts.Program, config: CompletedConfig, augme
|
|
|
118
119
|
.addNodeParser(new NeverTypeNodeParser())
|
|
119
120
|
.addNodeParser(new ObjectTypeNodeParser())
|
|
120
121
|
.addNodeParser(new AsExpressionNodeParser(chainNodeParser))
|
|
122
|
+
.addNodeParser(new BinaryExpressionNodeParser(chainNodeParser))
|
|
121
123
|
.addNodeParser(new SatisfiesNodeParser(chainNodeParser))
|
|
122
124
|
.addNodeParser(withJsDoc(new ParameterParser(chainNodeParser)))
|
|
123
125
|
.addNodeParser(new StringLiteralNodeParser())
|
package/factory/program.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import * as path from "node:path";
|
|
2
2
|
import normalize from "normalize-path";
|
|
3
|
+
import type { CompilerOptions } from "typescript";
|
|
3
4
|
import ts from "typescript";
|
|
4
5
|
import type { CompletedConfig, Config } from "../src/Config.js";
|
|
5
6
|
import { BuildError } from "../src/Error/Errors.js";
|
|
6
|
-
import
|
|
7
|
+
import fs from "node:fs";
|
|
7
8
|
|
|
8
9
|
function loadTsConfigFile(configFile: string) {
|
|
9
10
|
const raw = ts.sys.readFile(configFile);
|
|
@@ -55,16 +56,19 @@ function getTsConfig(config: Config) {
|
|
|
55
56
|
noEmit: true,
|
|
56
57
|
emitDecoratorMetadata: true,
|
|
57
58
|
experimentalDecorators: true,
|
|
58
|
-
target: ts.ScriptTarget.
|
|
59
|
+
target: ts.ScriptTarget.ES2022,
|
|
59
60
|
module: ts.ModuleKind.CommonJS,
|
|
60
61
|
strictNullChecks: false,
|
|
61
|
-
|
|
62
|
+
skipLibCheck: true,
|
|
63
|
+
skipDefaultLibCheck: true,
|
|
64
|
+
esModuleInterop: true,
|
|
65
|
+
} satisfies CompilerOptions,
|
|
62
66
|
};
|
|
63
67
|
}
|
|
64
68
|
|
|
65
69
|
export function createProgram(config: CompletedConfig): ts.Program {
|
|
66
70
|
const rootNamesFromPath = config.path
|
|
67
|
-
? globSync(normalize(path.resolve(config.path))).map((rootName) => normalize(rootName))
|
|
71
|
+
? fs.globSync(normalize(path.resolve(config.path))).map((rootName) => normalize(rootName))
|
|
68
72
|
: [];
|
|
69
73
|
const tsconfig = getTsConfig(config);
|
|
70
74
|
const rootNames = rootNamesFromPath.length ? rootNamesFromPath : tsconfig.fileNames;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ts-json-schema-generator",
|
|
3
|
-
"version": "2.5.0
|
|
3
|
+
"version": "2.5.0",
|
|
4
4
|
"description": "Generate JSON schema from your Typescript sources",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ts",
|
|
@@ -49,53 +49,48 @@
|
|
|
49
49
|
"prepublishOnly": "npm run build",
|
|
50
50
|
"release": "npm run build && auto shipit",
|
|
51
51
|
"run": "tsx ts-json-schema-generator.ts",
|
|
52
|
-
"test": "
|
|
53
|
-
"test:
|
|
54
|
-
"test:fast": "cross-env FAST_TEST=1
|
|
55
|
-
"test:update": "cross-env UPDATE_SCHEMA=true
|
|
52
|
+
"test": "tsx --test \"test/**/*.test.ts\"",
|
|
53
|
+
"test:debug": "tsx --inspect-brk --test-concurrency=1 --test",
|
|
54
|
+
"test:fast": "cross-env FAST_TEST=1 tsx --test \"test/**/*.test.ts\"",
|
|
55
|
+
"test:update": "cross-env FAST_TEST=1 UPDATE_SCHEMA=true tsx --test \"test/**/*.test.ts\"",
|
|
56
|
+
"test:coverage": "c8 --reporter lcov --reporter text tsx --test \"test/**/*.test.ts\"",
|
|
56
57
|
"watch": "tsc -w"
|
|
57
58
|
},
|
|
58
59
|
"dependencies": {
|
|
59
60
|
"@types/json-schema": "^7.0.15",
|
|
60
|
-
"commander": "^14.0.
|
|
61
|
-
"glob": "^13.0.0",
|
|
61
|
+
"commander": "^14.0.2",
|
|
62
62
|
"json5": "^2.2.3",
|
|
63
63
|
"normalize-path": "^3.0.0",
|
|
64
64
|
"safe-stable-stringify": "^2.5.0",
|
|
65
65
|
"tslib": "^2.8.1",
|
|
66
|
-
"typescript": "^5.
|
|
67
|
-
"@typescript/vfs": "1.6.2"
|
|
66
|
+
"typescript": "^5.9.3"
|
|
68
67
|
},
|
|
69
68
|
"devDependencies": {
|
|
70
|
-
"@auto-it/conventional-commits": "^11.3.
|
|
71
|
-
"@auto-it/first-time-contributor": "^11.3.
|
|
72
|
-
"@
|
|
73
|
-
"@babel/preset-env": "^7.28.0",
|
|
74
|
-
"@babel/preset-typescript": "^7.27.1",
|
|
75
|
-
"@eslint/js": "^9.30.1",
|
|
69
|
+
"@auto-it/conventional-commits": "^11.3.6",
|
|
70
|
+
"@auto-it/first-time-contributor": "^11.3.6",
|
|
71
|
+
"@eslint/js": "^9.39.1",
|
|
76
72
|
"@types/eslint": "^9.6.1",
|
|
77
|
-
"@types/
|
|
78
|
-
"@types/node": "^24.0.10",
|
|
73
|
+
"@types/node": "^24.10.1",
|
|
79
74
|
"@types/normalize-path": "^3.0.2",
|
|
75
|
+
"@typescript/vfs": "1.6.2",
|
|
80
76
|
"ajv": "^8.17.1",
|
|
81
77
|
"ajv-formats": "^3.0.1",
|
|
82
|
-
"auto": "^11.3.
|
|
83
|
-
"
|
|
84
|
-
"cross-env": "^10.
|
|
85
|
-
"eslint": "9.39.
|
|
86
|
-
"eslint-config-prettier": "^10.1.
|
|
87
|
-
"eslint-plugin-prettier": "^5.5.
|
|
88
|
-
"globals": "^
|
|
89
|
-
"
|
|
90
|
-
"
|
|
91
|
-
"
|
|
92
|
-
"
|
|
93
|
-
"
|
|
94
|
-
"vega": "^6.1
|
|
95
|
-
"vega-lite": "^6.2.0"
|
|
78
|
+
"auto": "^11.3.6",
|
|
79
|
+
"c8": "^10.1.3",
|
|
80
|
+
"cross-env": "^10.1.0",
|
|
81
|
+
"eslint": "9.39.2",
|
|
82
|
+
"eslint-config-prettier": "^10.1.8",
|
|
83
|
+
"eslint-plugin-prettier": "^5.5.4",
|
|
84
|
+
"globals": "^17.0.0",
|
|
85
|
+
"prettier": "^3.7.3",
|
|
86
|
+
"try": "^1.0.1",
|
|
87
|
+
"tsx": "^4.21.0",
|
|
88
|
+
"typescript-eslint": "^8.48.0",
|
|
89
|
+
"vega": "^6.2.0",
|
|
90
|
+
"vega-lite": "^6.4.1"
|
|
96
91
|
},
|
|
97
|
-
"packageManager": "npm@11.4
|
|
92
|
+
"packageManager": "npm@11.6.4",
|
|
98
93
|
"engines": {
|
|
99
|
-
"node": ">=
|
|
94
|
+
"node": ">=22.0.0"
|
|
100
95
|
}
|
|
101
96
|
}
|
package/src/Error/BaseError.ts
CHANGED
|
@@ -12,8 +12,6 @@ export type PartialDiagnostic = Omit<ts.Diagnostic, "category" | "file" | "start
|
|
|
12
12
|
category?: ts.DiagnosticCategory;
|
|
13
13
|
};
|
|
14
14
|
|
|
15
|
-
const isTTY = process.env.TTY || process.stdout.isTTY;
|
|
16
|
-
|
|
17
15
|
/**
|
|
18
16
|
* Base error for ts-json-schema-generator
|
|
19
17
|
*/
|
|
@@ -51,7 +49,7 @@ export abstract class BaseError extends Error {
|
|
|
51
49
|
);
|
|
52
50
|
}
|
|
53
51
|
|
|
54
|
-
format() {
|
|
52
|
+
format(isTTY = process.env.TTY || process.stdout.isTTY): string {
|
|
55
53
|
const formatter = isTTY ? ts.formatDiagnosticsWithColorAndContext : ts.formatDiagnostics;
|
|
56
54
|
|
|
57
55
|
return formatter([this.diagnostic], {
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import ts from "typescript";
|
|
2
|
+
import type { Context, NodeParser } from "../NodeParser.js";
|
|
3
|
+
import type { SubNodeParser } from "../SubNodeParser.js";
|
|
4
|
+
import { AnyType } from "../Type/AnyType.js";
|
|
5
|
+
import type { BaseType } from "../Type/BaseType.js";
|
|
6
|
+
import { BooleanType } from "../Type/BooleanType.js";
|
|
7
|
+
import { LiteralType } from "../Type/LiteralType.js";
|
|
8
|
+
import { NumberType } from "../Type/NumberType.js";
|
|
9
|
+
import { StringType } from "../Type/StringType.js";
|
|
10
|
+
import { UnionType } from "../Type/UnionType.js";
|
|
11
|
+
import { AliasType } from "../Type/AliasType.js";
|
|
12
|
+
|
|
13
|
+
export class BinaryExpressionNodeParser implements SubNodeParser {
|
|
14
|
+
public constructor(protected childNodeParser: NodeParser) {}
|
|
15
|
+
|
|
16
|
+
public supportsNode(node: ts.Node): boolean {
|
|
17
|
+
return node.kind === ts.SyntaxKind.BinaryExpression;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
public createType(node: ts.BinaryExpression, context: Context): BaseType {
|
|
21
|
+
const leftType = this.childNodeParser.createType(node.left, context);
|
|
22
|
+
const rightType = this.childNodeParser.createType(node.right, context);
|
|
23
|
+
|
|
24
|
+
if (leftType instanceof AnyType || rightType instanceof AnyType) {
|
|
25
|
+
return new AnyType();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (this.isStringLike(leftType) || this.isStringLike(rightType)) {
|
|
29
|
+
return new StringType();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (this.isDefinitelyNumberLike(leftType) && this.isDefinitelyNumberLike(rightType)) {
|
|
33
|
+
return new NumberType();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (this.isBooleanLike(leftType) && this.isBooleanLike(rightType)) {
|
|
37
|
+
return new BooleanType();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Anything else (objects, any, unknown, weird unions, etc.) return
|
|
41
|
+
// 'string' because at runtime + will usually go through ToPrimitive and
|
|
42
|
+
// end up in the "string concatenation" branch when non-numeric stuff is
|
|
43
|
+
// involved.
|
|
44
|
+
return new StringType();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
private isStringLike(type: BaseType): boolean {
|
|
48
|
+
if (type instanceof AliasType) {
|
|
49
|
+
return this.isStringLike(type.getType());
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (type instanceof StringType) {
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (type instanceof LiteralType && type.isString()) {
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Any union member being string-like is enough.
|
|
61
|
+
if (type instanceof UnionType) {
|
|
62
|
+
return type.getTypes().some((t) => this.isStringLike(t));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
private isBooleanLike(type: BaseType): boolean {
|
|
69
|
+
if (type instanceof BooleanType) {
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (type instanceof LiteralType && typeof type.getValue() === "boolean") {
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
private isDefinitelyNumberLike(type: BaseType): boolean {
|
|
81
|
+
if (type instanceof AliasType) {
|
|
82
|
+
return this.isDefinitelyNumberLike(type.getType());
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (type instanceof NumberType) {
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (type instanceof LiteralType && typeof type.getValue() === "number") {
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (type instanceof UnionType) {
|
|
94
|
+
return type.getTypes().every((t) => this.isDefinitelyNumberLike(t));
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
@@ -79,7 +79,10 @@ export class IndexedAccessTypeNodeParser implements SubNodeParser {
|
|
|
79
79
|
return objectType;
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
|
|
82
|
+
// When the indexed property does not exist (e.g. constrained generics with
|
|
83
|
+
// narrower instantiations), treat it as never so optional properties are dropped
|
|
84
|
+
// instead of throwing.
|
|
85
|
+
return new NeverType();
|
|
83
86
|
}
|
|
84
87
|
|
|
85
88
|
throw new LogicError(node, `No additional properties in type "${objectType.getId()}"`);
|
|
@@ -4,6 +4,7 @@ import type { NodeParser } from "../NodeParser.js";
|
|
|
4
4
|
import { Context } from "../NodeParser.js";
|
|
5
5
|
import type { SubNodeParser } from "../SubNodeParser.js";
|
|
6
6
|
import { AnnotatedType } from "../Type/AnnotatedType.js";
|
|
7
|
+
import { AnyType } from "../Type/AnyType.js";
|
|
7
8
|
import { ArrayType } from "../Type/ArrayType.js";
|
|
8
9
|
import type { BaseType } from "../Type/BaseType.js";
|
|
9
10
|
import { DefinitionType } from "../Type/DefinitionType.js";
|
|
@@ -52,18 +53,21 @@ export class MappedTypeNodeParser implements SubNodeParser {
|
|
|
52
53
|
return new ObjectType(id, [], this.getProperties(node, new UnionType([keyListType]), context), false);
|
|
53
54
|
}
|
|
54
55
|
|
|
56
|
+
const maybeUnionType = this.childNodeParser.createType(
|
|
57
|
+
node.type!,
|
|
58
|
+
this.createSubContext(node, keyListType, context),
|
|
59
|
+
);
|
|
60
|
+
if (maybeUnionType instanceof UnionType && constraintType?.getId() === "number") {
|
|
61
|
+
// Then we turn it into an array
|
|
62
|
+
return maybeUnionType instanceof NeverType ? new NeverType() : new ArrayType(maybeUnionType);
|
|
63
|
+
}
|
|
64
|
+
|
|
55
65
|
if (
|
|
56
66
|
keyListType instanceof StringType ||
|
|
57
67
|
keyListType instanceof NumberType ||
|
|
58
|
-
keyListType instanceof SymbolType
|
|
68
|
+
keyListType instanceof SymbolType ||
|
|
69
|
+
keyListType instanceof AnyType
|
|
59
70
|
) {
|
|
60
|
-
if (constraintType?.getId() === "number") {
|
|
61
|
-
const type = this.childNodeParser.createType(
|
|
62
|
-
node.type!,
|
|
63
|
-
this.createSubContext(node, keyListType, context),
|
|
64
|
-
);
|
|
65
|
-
return type instanceof NeverType ? new NeverType() : new ArrayType(type);
|
|
66
|
-
}
|
|
67
71
|
// Key type widens to `string`
|
|
68
72
|
const type = this.childNodeParser.createType(node.type!, this.createSubContext(node, keyListType, context));
|
|
69
73
|
// const resultType = type instanceof NeverType ? new NeverType() : new ObjectType(id, [], [], type);
|
package/src/SchemaGenerator.ts
CHANGED
|
@@ -8,6 +8,7 @@ import type { BaseType } from "./Type/BaseType.js";
|
|
|
8
8
|
import { DefinitionType } from "./Type/DefinitionType.js";
|
|
9
9
|
import type { TypeFormatter } from "./TypeFormatter.js";
|
|
10
10
|
import type { StringMap } from "./Utils/StringMap.js";
|
|
11
|
+
import { AnnotatedType } from "./Type/AnnotatedType.js";
|
|
11
12
|
import { hasJsDocTag } from "./Utils/hasJsDocTag.js";
|
|
12
13
|
import { removeUnreachable } from "./Utils/removeUnreachable.js";
|
|
13
14
|
import { castArray } from "./Utils/castArray.js";
|
|
@@ -124,21 +125,35 @@ export class SchemaGenerator {
|
|
|
124
125
|
});
|
|
125
126
|
|
|
126
127
|
const ids = new Map<string, string>();
|
|
128
|
+
const baseIds = new Map<string, string>();
|
|
127
129
|
for (const child of children) {
|
|
128
130
|
const name = child.getName();
|
|
129
131
|
const previousId = ids.get(name);
|
|
130
|
-
//
|
|
131
|
-
//
|
|
132
|
+
// Strip def- prefixes from IDs. DefinitionType.getId() returns "def-{innerType.getId()}"
|
|
133
|
+
// and for generic types, nested DefinitionTypes also add def- prefixes. Stripping all
|
|
134
|
+
// of them normalizes the comparison for types that may be wrapped differently.
|
|
132
135
|
const childId = child.getId().replace(/def-/g, "");
|
|
136
|
+
// Also track the base type ID (without AnnotatedType wrapper) to handle cases where
|
|
137
|
+
// the same type appears with different annotations (e.g., a discriminated union type
|
|
138
|
+
// referenced directly vs from a property - one has @discriminator annotation, one doesn't)
|
|
139
|
+
const innerType = child.getType();
|
|
140
|
+
const baseChildId = (innerType instanceof AnnotatedType ? innerType.getType() : innerType).getId();
|
|
141
|
+
const previousBaseId = baseIds.get(name);
|
|
133
142
|
|
|
134
143
|
if (previousId && childId !== previousId) {
|
|
144
|
+
// Check if the base type (without annotations) matches - if so, it's just
|
|
145
|
+
// annotation differences, not truly different types
|
|
146
|
+
if (previousBaseId === baseChildId) {
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
135
149
|
throw new MultipleDefinitionsError(
|
|
136
150
|
name,
|
|
137
151
|
child,
|
|
138
|
-
children.find((c) => c.getId() === previousId),
|
|
152
|
+
children.find((c) => c.getId().replace(/def-/g, "") === previousId),
|
|
139
153
|
);
|
|
140
154
|
}
|
|
141
155
|
ids.set(name, childId);
|
|
156
|
+
baseIds.set(name, baseChildId);
|
|
142
157
|
}
|
|
143
158
|
|
|
144
159
|
children.reduce((definitions, child) => {
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { BaseType } from "./BaseType.js";
|
|
2
2
|
import { hash } from "../Utils/nodeKey.js";
|
|
3
3
|
|
|
4
|
-
export
|
|
5
|
-
[name: string]: any;
|
|
6
|
-
}
|
|
4
|
+
export type Annotations = Record<string, unknown>;
|
|
7
5
|
|
|
8
6
|
export class AnnotatedType extends BaseType {
|
|
9
7
|
public constructor(
|
package/src/Type/UnknownType.ts
CHANGED
|
@@ -5,7 +5,7 @@ export class UnknownType extends BaseType {
|
|
|
5
5
|
/**
|
|
6
6
|
* If the source for this UnknownType was from a failed operation than to an actual `unknown` type present in the source code.
|
|
7
7
|
*/
|
|
8
|
-
readonly erroredSource
|
|
8
|
+
readonly erroredSource = false,
|
|
9
9
|
) {
|
|
10
10
|
super();
|
|
11
11
|
}
|
|
@@ -8,7 +8,7 @@ import type { TypeFormatter } from "../TypeFormatter.js";
|
|
|
8
8
|
import { derefType } from "../Utils/derefType.js";
|
|
9
9
|
|
|
10
10
|
export function makeNullable(def: Definition): Definition {
|
|
11
|
-
const union
|
|
11
|
+
const union = (def.oneOf || def.anyOf) as Definition[] | undefined;
|
|
12
12
|
if (union && union.filter((d: Definition) => d.type === "null").length === 0) {
|
|
13
13
|
union.push({ type: "null" });
|
|
14
14
|
} else if (def.type && def.type !== "object") {
|
|
@@ -58,7 +58,7 @@ export class AnnotatedTypeFormatter implements SubTypeFormatter {
|
|
|
58
58
|
if ("discriminator" in annotations) {
|
|
59
59
|
const deref = derefType(type.getType());
|
|
60
60
|
if (deref instanceof UnionType) {
|
|
61
|
-
deref.setDiscriminator(annotations.discriminator);
|
|
61
|
+
deref.setDiscriminator(annotations.discriminator as string);
|
|
62
62
|
delete annotations.discriminator;
|
|
63
63
|
} else {
|
|
64
64
|
throw new JsonTypeError(
|
package/src/Utils/narrowType.ts
CHANGED
|
@@ -16,12 +16,7 @@ import { derefType } from "./derefType.js";
|
|
|
16
16
|
* kept, when returning false it is removed.
|
|
17
17
|
* @return The narrowed down type.
|
|
18
18
|
*/
|
|
19
|
-
export function narrowType(
|
|
20
|
-
type: BaseType,
|
|
21
|
-
// TODO: remove the next line
|
|
22
|
-
// eslint-disable-next-line no-shadow
|
|
23
|
-
predicate: (type: BaseType) => boolean,
|
|
24
|
-
): BaseType {
|
|
19
|
+
export function narrowType(type: BaseType, predicate: (type: BaseType) => boolean): BaseType {
|
|
25
20
|
const derefed = derefType(type);
|
|
26
21
|
if (derefed instanceof UnionType || derefed instanceof EnumType) {
|
|
27
22
|
let changed = false;
|
package/src/Utils/nodeKey.ts
CHANGED
|
@@ -2,7 +2,9 @@ import stringify from "safe-stable-stringify";
|
|
|
2
2
|
import type { Node } from "typescript";
|
|
3
3
|
import type { Context } from "../NodeParser.js";
|
|
4
4
|
|
|
5
|
-
export function hash(
|
|
5
|
+
export function hash(
|
|
6
|
+
a: string | boolean | number | (string | boolean | number | Record<string, unknown>)[] | Record<string, unknown>,
|
|
7
|
+
): string | number {
|
|
6
8
|
if (typeof a === "number") {
|
|
7
9
|
return a;
|
|
8
10
|
}
|
|
@@ -11,23 +11,14 @@ import pkg from "./package.json";
|
|
|
11
11
|
|
|
12
12
|
const args = new Command()
|
|
13
13
|
.option("-p, --path <path>", "Source file path")
|
|
14
|
-
.option(
|
|
15
|
-
"-t, --type <name>",
|
|
16
|
-
"Type name (can be passed multiple times)",
|
|
17
|
-
(value: string, previous: string[] | undefined) => {
|
|
18
|
-
if (previous) {
|
|
19
|
-
return previous.concat(value);
|
|
20
|
-
}
|
|
21
|
-
return [value];
|
|
22
|
-
},
|
|
23
|
-
)
|
|
14
|
+
.option("-t, --type <name...>", "Type name(s)")
|
|
24
15
|
.option("-i, --id <name>", "$id for generated schema")
|
|
25
16
|
.option("-f, --tsconfig <path>", "Custom tsconfig.json path")
|
|
26
17
|
.addOption(
|
|
27
18
|
new Option("-e, --expose <expose>", "Type exposing").choices(["all", "none", "export"]).default("export"),
|
|
28
19
|
)
|
|
29
20
|
.addOption(
|
|
30
|
-
new Option("-j, --jsDoc <extended>", "Read
|
|
21
|
+
new Option("-j, --jsDoc <extended>", "Read JSDoc annotations")
|
|
31
22
|
.choices(["none", "basic", "extended"])
|
|
32
23
|
.default("extended"),
|
|
33
24
|
)
|