Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JSDoc string literal types #9995

Merged
merged 7 commits into from
Aug 17, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5529,6 +5529,8 @@ namespace ts {
return getTypeFromThisTypeNode(node);
case SyntaxKind.LiteralType:
return getTypeFromLiteralTypeNode(<LiteralTypeNode>node);
case SyntaxKind.JSDocLiteralType:
return getTypeFromLiteralTypeNode((<JSDocLiteralType>node).literal);
case SyntaxKind.TypeReference:
case SyntaxKind.JSDocTypeReference:
return getTypeFromTypeReference(<TypeReferenceNode>node);
Expand Down
14 changes: 13 additions & 1 deletion src/compiler/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,8 @@ namespace ts {
case SyntaxKind.JSDocPropertyTag:
return visitNode(cbNode, (<JSDocPropertyTag>node).typeExpression) ||
visitNode(cbNode, (<JSDocPropertyTag>node).name);
case SyntaxKind.JSDocLiteralType:
return visitNode(cbNode, (<JSDocLiteralType>node).literal);
}
}

Expand Down Expand Up @@ -5889,9 +5891,13 @@ namespace ts {
case SyntaxKind.SymbolKeyword:
case SyntaxKind.VoidKeyword:
return parseTokenNode<JSDocType>();
case SyntaxKind.StringLiteral:
case SyntaxKind.NumericLiteral:
case SyntaxKind.TrueKeyword:
case SyntaxKind.FalseKeyword:
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

need NeverKeyword and UndefinedKeyword here too

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and NullKeyword as well.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, those are not literal types, it turns out. In the interests of getting this PR in, I'll do those separately.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They probably need their own special handling (see the lines preceding the diff in checker)

return parseJSDocLiteralType();
}

// TODO (drosen): Parse string literal types in JSDoc as well.
return parseJSDocTypeReference();
}

Expand Down Expand Up @@ -6070,6 +6076,12 @@ namespace ts {
return finishNode(result);
}

function parseJSDocLiteralType(): JSDocLiteralType {
const result = <JSDocLiteralType>createNode(SyntaxKind.JSDocLiteralType);
result.literal = parseLiteralTypeNode();
return finishNode(result);
}

function parseJSDocUnknownOrNullableType(): JSDocUnknownType | JSDocNullableType {
const pos = scanner.getStartPos();
// skip the ?
Expand Down
9 changes: 7 additions & 2 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,7 @@ namespace ts {
JSDocTypedefTag,
JSDocPropertyTag,
JSDocTypeLiteral,
JSDocLiteralType,

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You may need to update the LastJSDocNode and LastJSDocTagNode pointers

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated

// Synthesized list
SyntaxList,
Expand Down Expand Up @@ -376,9 +377,9 @@ namespace ts {
LastBinaryOperator = CaretEqualsToken,
FirstNode = QualifiedName,
FirstJSDocNode = JSDocTypeExpression,
LastJSDocNode = JSDocTypeLiteral,
LastJSDocNode = JSDocLiteralType,
FirstJSDocTagNode = JSDocComment,
LastJSDocTagNode = JSDocTypeLiteral
LastJSDocTagNode = JSDocLiteralType
}

export const enum NodeFlags {
Expand Down Expand Up @@ -1492,6 +1493,10 @@ namespace ts {
type: JSDocType;
}

export interface JSDocLiteralType extends JSDocType {
literal: LiteralTypeNode;
}

export type JSDocTypeReferencingNode = JSDocThisType | JSDocConstructorType | JSDocVariadicType | JSDocOptionalType | JSDocNullableType | JSDocNonNullableType;

// @kind(SyntaxKind.JSDocRecordMember)
Expand Down
24 changes: 24 additions & 0 deletions tests/baselines/reference/jsdocLiteral.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//// [in.js]
/**
* @param {'literal'} p1
* @param {"literal"} p2
* @param {'literal' | 'other'} p3
* @param {'literal' | number} p4
* @param {12 | true | 'str'} p5
*/
function f(p1, p2, p3, p4, p5) {
return p1 + p2 + p3 + p4 + p5 + '.';
}


//// [out.js]
/**
* @param {'literal'} p1
* @param {"literal"} p2
* @param {'literal' | 'other'} p3
* @param {'literal' | number} p4
* @param {12 | true | 'str'} p5
*/
function f(p1, p2, p3, p4, p5) {
return p1 + p2 + p3 + p4 + p5 + '.';
}
24 changes: 24 additions & 0 deletions tests/baselines/reference/jsdocLiteral.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
=== tests/cases/conformance/jsdoc/in.js ===
/**
* @param {'literal'} p1
* @param {"literal"} p2
* @param {'literal' | 'other'} p3
* @param {'literal' | number} p4
* @param {12 | true | 'str'} p5
*/
function f(p1, p2, p3, p4, p5) {
>f : Symbol(f, Decl(in.js, 0, 0))
>p1 : Symbol(p1, Decl(in.js, 7, 11))
>p2 : Symbol(p2, Decl(in.js, 7, 14))
>p3 : Symbol(p3, Decl(in.js, 7, 18))
>p4 : Symbol(p4, Decl(in.js, 7, 22))
>p5 : Symbol(p5, Decl(in.js, 7, 26))

return p1 + p2 + p3 + p4 + p5 + '.';
>p1 : Symbol(p1, Decl(in.js, 7, 11))
>p2 : Symbol(p2, Decl(in.js, 7, 14))
>p3 : Symbol(p3, Decl(in.js, 7, 18))
>p4 : Symbol(p4, Decl(in.js, 7, 22))
>p5 : Symbol(p5, Decl(in.js, 7, 26))
}

30 changes: 30 additions & 0 deletions tests/baselines/reference/jsdocLiteral.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
=== tests/cases/conformance/jsdoc/in.js ===
/**
* @param {'literal'} p1
* @param {"literal"} p2
* @param {'literal' | 'other'} p3
* @param {'literal' | number} p4
* @param {12 | true | 'str'} p5
*/
function f(p1, p2, p3, p4, p5) {
>f : (p1: "literal", p2: "literal", p3: "literal" | "other", p4: number | "literal", p5: true | 12 | "str") => string
>p1 : "literal"
>p2 : "literal"
>p3 : "literal" | "other"
>p4 : number | "literal"
>p5 : true | 12 | "str"

return p1 + p2 + p3 + p4 + p5 + '.';
>p1 + p2 + p3 + p4 + p5 + '.' : string
>p1 + p2 + p3 + p4 + p5 : string
>p1 + p2 + p3 + p4 : string
>p1 + p2 + p3 : string
>p1 + p2 : string
>p1 : "literal"
>p2 : "literal"
>p3 : "literal" | "other"
>p4 : number | "literal"
>p5 : true | 12 | "str"
>'.' : string
}

13 changes: 13 additions & 0 deletions tests/cases/conformance/jsdoc/jsdocLiteral.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// @allowJs: true
// @filename: in.js
// @out: out.js
/**
* @param {'literal'} p1
* @param {"literal"} p2
* @param {'literal' | 'other'} p3
* @param {'literal' | number} p4
* @param {12 | true | 'str'} p5
*/
function f(p1, p2, p3, p4, p5) {
return p1 + p2 + p3 + p4 + p5 + '.';
}
23 changes: 23 additions & 0 deletions tests/cases/fourslash/completionForStringLiteral4.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/// <reference path='fourslash.ts'/>
// @allowJs: true
// @Filename: in.js
/////** I am documentation
//// * @param {'literal'} p1
//// * @param {"literal"} p2
//// * @param {'other1' | 'other2'} p3
//// * @param {'literal' | number} p4
//// * @param {12 | true} p5
//// */
////function f(p1, p2, p3, p4, p5) {
//// return p1 + p2 + p3 + p4 + p5 + '.';
////}
////f/*1*/('literal', 'literal', "o/*2*/ther1", 12);

goTo.marker('1');
verify.quickInfoExists();
verify.quickInfoIs('function f(p1: "literal", p2: "literal", p3: "other1" | "other2", p4: number | "literal", p5: true | 12): string', 'I am documentation');

goTo.marker('2');
verify.completionListContains("other1");
verify.completionListContains("other2");
verify.memberListCount(2);