Skip to content

Commit

Permalink
Initial draft of named tuple members
Browse files Browse the repository at this point in the history
  • Loading branch information
weswigham committed Apr 28, 2020
1 parent 167f954 commit c80c84a
Show file tree
Hide file tree
Showing 49 changed files with 901 additions and 436 deletions.
108 changes: 82 additions & 26 deletions src/compiler/checker.ts

Large diffs are not rendered by default.

12 changes: 12 additions & 0 deletions src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -3513,6 +3513,18 @@
"category": "Error",
"code": 5083
},
"Tuple members must all have names or not have names.": {
"category": "Error",
"code": 5084
},
"Tuple members express optionality with a trailing question mark on the type, a question mark on the member name is invalid.": {
"category": "Error",
"code": 5085
},
"Rest tuple members are declared with a `...` on the type. A `...` on the name is invalid.": {
"category": "Error",
"code": 5086
},

"Generates a sourcemap for each corresponding '.d.ts' file.": {
"category": "Message",
Expand Down
16 changes: 13 additions & 3 deletions src/compiler/emitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1370,6 +1370,8 @@ namespace ts {
case SyntaxKind.RestType:
case SyntaxKind.JSDocVariadicType:
return emitRestOrJSDocVariadicType(node as RestTypeNode | JSDocVariadicType);
case SyntaxKind.NamedTupleMember:
return emitNamedTupleMember(node as NamedTupleMember);

// Binding patterns
case SyntaxKind.ObjectBindingPattern:
Expand Down Expand Up @@ -2099,9 +2101,17 @@ namespace ts {
}

function emitTupleType(node: TupleTypeNode) {
writePunctuation("[");
emitList(node, node.elementTypes, ListFormat.TupleTypeElements);
writePunctuation("]");
emitTokenWithComment(SyntaxKind.OpenBracketToken, node.pos, writePunctuation, node);
const flags = getEmitFlags(node) & EmitFlags.SingleLine ? ListFormat.SingleLineTupleTypeElements : ListFormat.MultiLineTupleTypeElements;
emitList(node, node.elements, flags | ListFormat.NoSpaceIfEmpty);
emitTokenWithComment(SyntaxKind.CloseBracketToken, node.elements.end, writePunctuation, node);
}

function emitNamedTupleMember(node: NamedTupleMember) {
emit(node.name);
emitTokenWithComment(SyntaxKind.ColonToken, node.name.end, writePunctuation, node);
writeSpace();
emit(node.type);
}

function emitOptionalType(node: OptionalTypeNode) {
Expand Down
39 changes: 34 additions & 5 deletions src/compiler/factoryPublic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -810,15 +810,15 @@ namespace ts {
: node;
}

export function createTupleTypeNode(elementTypes: readonly TypeNode[]) {
export function createTupleTypeNode(elements: readonly (TypeNode | NamedTupleMember)[]) {
const node = createSynthesizedNode(SyntaxKind.TupleType) as TupleTypeNode;
node.elementTypes = createNodeArray(elementTypes);
node.elements = createNodeArray(elements);
return node;
}

export function updateTupleTypeNode(node: TupleTypeNode, elementTypes: readonly TypeNode[]) {
return node.elementTypes !== elementTypes
? updateNode(createTupleTypeNode(elementTypes), node)
export function updateTupleTypeNode(node: TupleTypeNode, elements: readonly (TypeNode | NamedTupleMember)[]) {
return node.elements !== elements
? updateNode(createTupleTypeNode(elements), node)
: node;
}

Expand Down Expand Up @@ -934,6 +934,20 @@ namespace ts {
: node;
}

export function createNamedTupleMember(name: Identifier, type: TypeNode) {
const node = <NamedTupleMember>createSynthesizedNode(SyntaxKind.NamedTupleMember);
node.name = name;
node.type = type;
return node;
}

export function updateNamedTupleMember(node: NamedTupleMember, name: Identifier, type: TypeNode) {
return node.name !== name
|| node.type !== type
? updateNode(createNamedTupleMember(name, type), node)
: node;
}

export function createThisTypeNode() {
return <ThisTypeNode>createSynthesizedNode(SyntaxKind.ThisType);
}
Expand Down Expand Up @@ -2524,6 +2538,21 @@ namespace ts {
return node;
}


/* @internal */
export function createJSDocVariadicType(type: TypeNode): JSDocVariadicType {
const node = createSynthesizedNode(SyntaxKind.JSDocVariadicType) as JSDocVariadicType;
node.type = type;
return node;
}

/* @internal */
export function updateJSDocVariadicType(node: JSDocVariadicType, type: TypeNode): JSDocVariadicType {
return node.type !== type
? updateNode(createJSDocVariadicType(type), node)
: node;
}

// JSX

export function createJsxElement(openingElement: JsxOpeningElement, children: readonly JsxChild[], closingElement: JsxClosingElement) {
Expand Down
33 changes: 31 additions & 2 deletions src/compiler/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ namespace ts {
case SyntaxKind.ArrayType:
return visitNode(cbNode, (<ArrayTypeNode>node).elementType);
case SyntaxKind.TupleType:
return visitNodes(cbNode, cbNodes, (<TupleTypeNode>node).elementTypes);
return visitNodes(cbNode, cbNodes, (<TupleTypeNode>node).elements);
case SyntaxKind.UnionType:
case SyntaxKind.IntersectionType:
return visitNodes(cbNode, cbNodes, (<UnionOrIntersectionTypeNode>node).types);
Expand Down Expand Up @@ -207,6 +207,11 @@ namespace ts {
visitNode(cbNode, (<MappedTypeNode>node).type);
case SyntaxKind.LiteralType:
return visitNode(cbNode, (<LiteralTypeNode>node).literal);
case SyntaxKind.NamedTupleMember:
return visitNode(cbNode, (<NamedTupleMember>node).dotDotDotToken) ||
visitNode(cbNode, (<NamedTupleMember>node).name) ||
visitNode(cbNode, (<NamedTupleMember>node).questionToken) ||
visitNode(cbNode, (<NamedTupleMember>node).type);
case SyntaxKind.ObjectBindingPattern:
case SyntaxKind.ArrayBindingPattern:
return visitNodes(cbNode, cbNodes, (<BindingPattern>node).elements);
Expand Down Expand Up @@ -3056,9 +3061,33 @@ namespace ts {
return type;
}

function isNextTokenColonOrQuestionColon() {
return nextToken() === SyntaxKind.ColonToken || (token() === SyntaxKind.QuestionToken && nextToken() === SyntaxKind.ColonToken);
}

function isTupleElementName() {
if (token() === SyntaxKind.DotDotDotToken) {
return tokenIsIdentifierOrKeyword(nextToken()) && isNextTokenColonOrQuestionColon();
}
return tokenIsIdentifierOrKeyword(token()) && isNextTokenColonOrQuestionColon();
}

function parseTupleElementNameOrTupleElementType() {
if (lookAhead(isTupleElementName)) {
const node = <NamedTupleMember>createNode(SyntaxKind.NamedTupleMember);
node.dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken);
node.name = parseIdentifierName();
node.questionToken = parseOptionalToken(SyntaxKind.QuestionToken);
parseExpected(SyntaxKind.ColonToken);
node.type = parseTupleElementType();
return addJSDocComment(finishNode(node));
}
return parseTupleElementType();
}

function parseTupleType(): TupleTypeNode {
const node = <TupleTypeNode>createNode(SyntaxKind.TupleType);
node.elementTypes = parseBracketedList(ParsingContext.TupleElementTypes, parseTupleElementType, SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken);
node.elements = parseBracketedList(ParsingContext.TupleElementTypes, parseTupleElementNameOrTupleElementType, SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken);
return finishNode(node);
}

Expand Down
4 changes: 4 additions & 0 deletions src/compiler/transformers/declarations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1018,6 +1018,10 @@ namespace ts {
}
}

if (isTupleTypeNode(input) && (getLineAndCharacterOfPosition(currentSourceFile, input.pos).line === getLineAndCharacterOfPosition(currentSourceFile, input.end).line)) {
setEmitFlags(input, EmitFlags.SingleLine);
}

return cleanup(visitEachChild(input, visitDeclarationSubtree, context));

function cleanup<T extends Node>(returnValue: T | undefined): T | undefined {
Expand Down
15 changes: 13 additions & 2 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,7 @@ namespace ts {
IndexedAccessType,
MappedType,
LiteralType,
NamedTupleMember,
ImportType,
// Binding patterns
ObjectBindingPattern,
Expand Down Expand Up @@ -699,6 +700,7 @@ namespace ts {
| ConstructorTypeNode
| JSDocFunctionType
| ExportDeclaration
| NamedTupleMember
| EndOfFileToken;

export type HasType =
Expand Down Expand Up @@ -1273,7 +1275,15 @@ namespace ts {

export interface TupleTypeNode extends TypeNode {
kind: SyntaxKind.TupleType;
elementTypes: NodeArray<TypeNode>;
elements: NodeArray<TypeNode | NamedTupleMember>;
}

export interface NamedTupleMember extends TypeNode, JSDocContainer {
kind: SyntaxKind.NamedTupleMember;
dotDotDotToken?: Token<SyntaxKind.DotDotDotToken>;
name: Identifier;
questionToken?: Token<SyntaxKind.QuestionToken>;
type: TypeNode;
}

export interface OptionalTypeNode extends TypeNode {
Expand Down Expand Up @@ -6570,7 +6580,8 @@ namespace ts {
SingleLineTypeLiteralMembers = SingleLine | SpaceBetweenBraces | SpaceBetweenSiblings,
MultiLineTypeLiteralMembers = MultiLine | Indented | OptionalIfEmpty,

TupleTypeElements = CommaDelimited | SpaceBetweenSiblings | SingleLine,
SingleLineTupleTypeElements = CommaDelimited | SpaceBetweenSiblings | SingleLine,
MultiLineTupleTypeElements = CommaDelimited | Indented | SpaceBetweenSiblings | MultiLine,
UnionTypeConstituents = BarDelimited | SpaceBetweenSiblings | SingleLine,
IntersectionTypeConstituents = AmpersandDelimited | SpaceBetweenSiblings | SingleLine,
ObjectBindingPatternElements = SingleLine | AllowTrailingComma | SpaceBetweenBraces | CommaDelimited | SpaceBetweenSiblings | NoSpaceIfEmpty,
Expand Down
5 changes: 4 additions & 1 deletion src/compiler/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2702,7 +2702,10 @@ namespace ts {
}

export function walkUpParenthesizedTypes(node: Node) {
return walkUp(node, SyntaxKind.ParenthesizedType);
while (node && (node.kind === SyntaxKind.ParenthesizedType || node.kind === SyntaxKind.NamedTupleMember)) {
node = node.parent;
}
return node;
}

export function walkUpParenthesizedExpressions(node: Node) {
Expand Down
8 changes: 7 additions & 1 deletion src/compiler/visitorPublic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -480,7 +480,7 @@ namespace ts {

case SyntaxKind.TupleType:
return updateTupleTypeNode((<TupleTypeNode>node),
nodesVisitor((<TupleTypeNode>node).elementTypes, visitor, isTypeNode));
nodesVisitor((<TupleTypeNode>node).elements, visitor, isTypeNode));

case SyntaxKind.OptionalType:
return updateOptionalTypeNode((<OptionalTypeNode>node),
Expand Down Expand Up @@ -517,6 +517,12 @@ namespace ts {
(<ImportTypeNode>node).isTypeOf
);

case SyntaxKind.NamedTupleMember:
return updateNamedTupleMember(<NamedTupleMember>node,
visitNode((<NamedTupleMember>node).name, visitor, isIdentifierName),
visitNode((<NamedTupleMember>node).type, visitor, isTypeNode),
);

case SyntaxKind.ParenthesizedType:
return updateParenthesizedType(<ParenthesizedTypeNode>node,
visitNode((<ParenthesizedTypeNode>node).type, visitor, isTypeNode));
Expand Down
5 changes: 5 additions & 0 deletions src/services/refactors/extractType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,11 @@ namespace ts.refactor {
}
}
}

if (file && isTupleTypeNode(node) && (getLineAndCharacterOfPosition(file, node.pos).line === getLineAndCharacterOfPosition(file, node.end).line)) {
setEmitFlags(node, EmitFlags.SingleLine);
}

return forEachChild(node, visitor);
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/testRunner/unittests/printer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ namespace ts {
// https://github.com/Microsoft/TypeScript/issues/15651
printsCorrectly("functionTypes", {}, printer => printer.printNode(
EmitHint.Unspecified,
createTupleTypeNode([
setEmitFlags(createTupleTypeNode([
createFunctionTypeNode(
/*typeArguments*/ undefined,
[createParameter(
Expand Down Expand Up @@ -293,7 +293,7 @@ namespace ts {
)],
createKeywordTypeNode(SyntaxKind.AnyKeyword)
),
]),
]), EmitFlags.SingleLine),
createSourceFile("source.ts", "", ScriptTarget.ES2015)
));
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"flags": "JSDoc",
"modifierFlagsCache": 0,
"transformFlags": 0,
"elementTypes": {
"elements": {
"length": 0,
"pos": 2,
"end": 2
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"flags": "JSDoc",
"modifierFlagsCache": 0,
"transformFlags": 0,
"elementTypes": {
"elements": {
"0": {
"kind": "NumberKeyword",
"pos": 2,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"flags": "JSDoc",
"modifierFlagsCache": 0,
"transformFlags": 0,
"elementTypes": {
"elements": {
"0": {
"kind": "NumberKeyword",
"pos": 2,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"flags": "JSDoc",
"modifierFlagsCache": 0,
"transformFlags": 0,
"elementTypes": {
"elements": {
"0": {
"kind": "NumberKeyword",
"pos": 2,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"flags": "JSDoc",
"modifierFlagsCache": 0,
"transformFlags": 0,
"elementTypes": {
"elements": {
"0": {
"kind": "NumberKeyword",
"pos": 2,
Expand Down
Loading

0 comments on commit c80c84a

Please sign in to comment.