Skip to content

Commit 34d39f7

Browse files
authored
Improve code coverage (#24)
1 parent 69f8a1f commit 34d39f7

File tree

40 files changed

+932
-90
lines changed

40 files changed

+932
-90
lines changed

src/Error/BaseError.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,8 @@
11
export abstract class BaseError implements Error {
2-
private callStack: any;
2+
public readonly stack: string;
33

4-
public constructor() {
5-
this.callStack = new Error().stack;
6-
}
7-
8-
public get stack(): string {
9-
return this.callStack;
4+
protected constructor() {
5+
Error.captureStackTrace(this, this.constructor);
106
}
117

128
public abstract get name(): string;

src/Error/UnknownNodeError.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export class UnknownNodeError extends BaseError {
1010
return "UnknownNodeError";
1111
}
1212
public get message(): string {
13-
return `Unknown node "${this.node.getFullText()}`;
13+
return `Unknown node "${this.node.getFullText()}"`;
1414
}
1515

1616
public getNode(): ts.Node {

src/NodeParser/EnumNodeParser.ts

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import { Context } from "../NodeParser";
33
import { SubNodeParser } from "../SubNodeParser";
44
import { BaseType } from "../Type/BaseType";
55
import { EnumType, EnumValue } from "../Type/EnumType";
6+
import { UnknownNodeError } from "../Error/UnknownNodeError";
7+
import { assertDefined } from "../Utils/assert";
68

79
export class EnumNodeParser implements SubNodeParser {
810
public constructor(
@@ -20,24 +22,18 @@ export class EnumNodeParser implements SubNodeParser {
2022

2123
return new EnumType(
2224
`enum-${node.getFullStart()}`,
23-
members.map((member, index) => this.getMemberValue(member, index)),
25+
members.map((member) => this.getMemberValue(member)),
2426
);
2527
}
2628

27-
private getMemberValue(member: ts.EnumMember, index: number): EnumValue {
29+
private getMemberValue(member: ts.EnumMember): EnumValue {
2830
const constantValue = this.typeChecker.getConstantValue(member);
2931
if (constantValue !== undefined) {
3032
return constantValue;
3133
}
3234

33-
const initializer = member.initializer;
34-
if (!initializer) {
35-
return index;
36-
} else if (initializer.kind === ts.SyntaxKind.NoSubstitutionTemplateLiteral) {
37-
return member.name.getText();
38-
} else {
39-
return this.parseInitializer(initializer);
40-
}
35+
const initializer = assertDefined(member.initializer);
36+
return this.parseInitializer(initializer);
4137
}
4238
private parseInitializer(initializer: ts.Node): EnumValue {
4339
if (initializer.kind === ts.SyntaxKind.TrueKeyword) {
@@ -46,16 +42,20 @@ export class EnumNodeParser implements SubNodeParser {
4642
return false;
4743
} else if (initializer.kind === ts.SyntaxKind.NullKeyword) {
4844
return null;
45+
} else if (initializer.kind === ts.SyntaxKind.NumericLiteral) {
46+
return parseFloat((initializer as ts.NumericLiteral).text);
4947
} else if (initializer.kind === ts.SyntaxKind.StringLiteral) {
50-
return (initializer as ts.LiteralLikeNode).text;
48+
return (initializer as ts.StringLiteral).text;
49+
} else if (initializer.kind === ts.SyntaxKind.NoSubstitutionTemplateLiteral) {
50+
return (initializer as ts.NoSubstitutionTemplateLiteral).text;
5151
} else if (initializer.kind === ts.SyntaxKind.ParenthesizedExpression) {
5252
return this.parseInitializer((initializer as ts.ParenthesizedExpression).expression);
5353
} else if (initializer.kind === ts.SyntaxKind.AsExpression) {
5454
return this.parseInitializer((initializer as ts.AsExpression).expression);
5555
} else if (initializer.kind === ts.SyntaxKind.TypeAssertionExpression) {
5656
return this.parseInitializer((initializer as ts.TypeAssertion).expression);
57-
} else {
58-
return initializer.getText();
5957
}
58+
59+
throw new UnknownNodeError(initializer);
6060
}
6161
}

src/Schema/Definition.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,7 @@ export interface Definition {
1414
format?: string;
1515
items?: Definition | Definition[];
1616
minItems?: number;
17-
additionalItems?: {
18-
anyOf: Definition[],
19-
};
17+
additionalItems?: false | Definition;
2018
enum?: (RawType | Definition)[];
2119
default?: RawType | Object;
2220
additionalProperties?: false | Definition;

src/TypeFormatter/LiteralUnionTypeFormatter.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,11 @@ import { uniqueArray } from "../Utils/uniqueArray";
88

99
export class LiteralUnionTypeFormatter implements SubTypeFormatter {
1010
public supportsType(type: UnionType): boolean {
11-
return type instanceof UnionType && this.isLiteralUnion(type);
11+
return (
12+
type instanceof UnionType &&
13+
type.getTypes().length > 0 &&
14+
this.isLiteralUnion(type)
15+
);
1216
}
1317
public getDefinition(type: UnionType): Definition {
1418
const values = uniqueArray(type.getTypes().map((item: LiteralType | NullType) => this.getLiteralValue(item)));

src/TypeFormatter/PrimitiveUnionTypeFormatter.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,11 @@ import { NullType } from "../Type/NullType";
1313

1414
export class PrimitiveUnionTypeFormatter implements SubTypeFormatter {
1515
public supportsType(type: UnionType): boolean {
16-
return type instanceof UnionType && this.isPrimitiveUnion(type);
16+
return (
17+
type instanceof UnionType &&
18+
type.getTypes().length > 0 &&
19+
this.isPrimitiveUnion(type)
20+
);
1721
}
1822
public getDefinition(type: UnionType): Definition {
1923
return {

src/TypeFormatter/TupleTypeFormatter.ts

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { SubTypeFormatter } from "../SubTypeFormatter";
33
import { TupleType } from "../Type/TupleType";
44
import { BaseType } from "../Type/BaseType";
55
import { Definition } from "../Schema/Definition";
6+
import { UnionType } from "../Type/UnionType";
67

78
export class TupleTypeFormatter implements SubTypeFormatter {
89
public constructor(
@@ -14,14 +15,21 @@ export class TupleTypeFormatter implements SubTypeFormatter {
1415
return type instanceof TupleType;
1516
}
1617
public getDefinition(type: TupleType): Definition {
17-
const tupleDefinitions = type.getTypes().map((item) => this.childTypeFormatter.getDefinition(item));
18-
19-
return {
20-
type: "array",
21-
items: tupleDefinitions,
22-
minItems: tupleDefinitions.length,
23-
...(tupleDefinitions.length > 1 ? {additionalItems: {anyOf: tupleDefinitions}} : {}),
24-
};
18+
const itemTypes = type.getTypes();
19+
if (itemTypes.length > 1) {
20+
return {
21+
type: "array",
22+
items: itemTypes.map((item) => this.childTypeFormatter.getDefinition(item)),
23+
minItems: itemTypes.length,
24+
additionalItems: this.childTypeFormatter.getDefinition(new UnionType(itemTypes)),
25+
};
26+
} else {
27+
return {
28+
type: "array",
29+
items: this.childTypeFormatter.getDefinition(itemTypes[0]),
30+
minItems: 1,
31+
};
32+
}
2533
}
2634
public getChildren(type: TupleType): BaseType[] {
2735
return type.getTypes().reduce((result: BaseType[], item) => [

src/TypeFormatter/UnionTypeFormatter.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,13 @@ export class UnionTypeFormatter implements SubTypeFormatter {
3434
};
3535
}
3636

37-
return definitions.length > 1 ? {
38-
anyOf: definitions,
39-
} : definitions[0];
37+
if (definitions.length === 0) {
38+
return {not: {}};
39+
} else if (definitions.length === 1) {
40+
return definitions[0];
41+
} else {
42+
return {anyOf: definitions};
43+
}
4044
}
4145
public getChildren(type: UnionType): BaseType[] {
4246
return type.getTypes().reduce((result: BaseType[], item) => [

test/config.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ describe("config", () => {
5555
assertSchema("jsdoc-complex-basic", {type: "MyObject", expose: "export", topRef: true, jsDoc: "basic"});
5656
assertSchema("jsdoc-complex-extended", {type: "MyObject", expose: "export", topRef: true, jsDoc: "extended"});
5757
assertSchema("jsdoc-description-only", {type: "MyObject", expose: "export", topRef: true, jsDoc: "extended"});
58+
assertSchema("jsdoc-empty-or-invalid", {type: "MyObject", expose: "export", topRef: true, jsDoc: "basic"});
5859

5960
assertSchema("jsdoc-inheritance", {type: "MyObject", expose: "export", topRef: true, jsDoc: "extended"});
6061
});
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/**
2+
* @title Some title here
3+
* @description Some description here
4+
*/
5+
export interface MyObject {
6+
/**
7+
* @minLength 123
8+
* @default {"abc": 123}
9+
*/
10+
validJsDoc: any;
11+
/**
12+
* @minLength ABC
13+
* @default {"abc": ABC}
14+
*/
15+
invalidJsDoc: any;
16+
/**
17+
* @minLength
18+
* @default
19+
*/
20+
emptyJsDoc: any;
21+
}

0 commit comments

Comments
 (0)