Merge branch 'transforms-transformer' into transforms-printer

This commit is contained in:
Ron Buckton 2016-02-22 15:58:33 -08:00
commit 90a317f62e
10 changed files with 1266 additions and 307 deletions

View file

@ -1798,7 +1798,7 @@ namespace ts {
* @param node The node to analyze
* @param subtreeFlags Transform flags computed for this node's subtree
*/
export function computeTransformFlagsForNode(node: Node, subtreeFlags: TransformFlags) {
export function computeTransformFlagsForNode(node: Node, subtreeFlags: TransformFlags): TransformFlags {
// Ambient nodes are TypeScript syntax and the flags of their subtree are ignored.
if (node.flags & NodeFlags.Ambient) {
return (node.transformFlags = TransformFlags.AssertTypeScript)
@ -1838,6 +1838,12 @@ namespace ts {
transformFlags |= TransformFlags.AssertJsx;
break;
case SyntaxKind.ExportKeyword:
// This node is both ES6 and TypeScript syntax.
transformFlags |= TransformFlags.AssertES6 | TransformFlags.TypeScript;
break;
case SyntaxKind.DefaultKeyword:
case SyntaxKind.NoSubstitutionTemplateLiteral:
case SyntaxKind.TemplateHead:
case SyntaxKind.TemplateMiddle:
@ -1965,20 +1971,6 @@ namespace ts {
break;
case SyntaxKind.ExpressionStatement:
if (nodeIsSynthesized(node)) {
const expression = (<ExpressionStatement>node).expression;
if (nodeIsSynthesized(expression)
&& isCallExpression(expression)
&& expression.expression.kind === SyntaxKind.SuperKeyword) {
// A synthesized call to `super` should be transformed to a cleaner emit
// when transpiling to ES5/3.
transformFlags |= TransformFlags.AssertES6;
}
}
break;
case SyntaxKind.BinaryExpression:
if (isDestructuringAssignment(node)) {
// Destructuring assignments are ES6 syntax.
@ -2087,7 +2079,7 @@ namespace ts {
case SyntaxKind.VariableDeclarationList:
// If a VariableDeclarationList is `let` or `const`, then it is ES6 syntax.
if (node.flags & NodeFlags.BlockScoped) {
transformFlags |= TransformFlags.AssertES6;
transformFlags |= TransformFlags.AssertES6 | TransformFlags.ContainsBlockScopedBinding;
}
break;
@ -2100,6 +2092,26 @@ namespace ts {
break;
case SyntaxKind.LabeledStatement:
// A labeled statement containing a block scoped binding *may* need to be transformed from ES6.
if (subtreeFlags & TransformFlags.ContainsBlockScopedBinding
&& isIterationStatement(this, /*lookInLabeledStatements*/ true)) {
transformFlags |= TransformFlags.AssertES6;
}
break;
case SyntaxKind.DoStatement:
case SyntaxKind.WhileStatement:
case SyntaxKind.ForStatement:
case SyntaxKind.ForInStatement:
// A loop containing a block scoped binding *may* need to be transformed from ES6.
if (subtreeFlags & TransformFlags.ContainsBlockScopedBinding) {
transformFlags |= TransformFlags.AssertES6;
}
break;
case SyntaxKind.ClassDeclaration:
case SyntaxKind.ClassExpression:
// A ClassDeclarations or ClassExpression is ES6 syntax.

View file

@ -130,11 +130,12 @@ namespace ts {
return -1;
}
export function countWhere<T>(array: T[], predicate: (x: T) => boolean): number {
export function countWhere<T>(array: T[], predicate: (x: T, i: number) => boolean): number {
let count = 0;
if (array) {
for (const v of array) {
if (predicate(v)) {
for (let i = 0; i < array.length; i++) {
const v = array[i];
if (predicate(v, i)) {
count++;
}
}
@ -142,25 +143,49 @@ namespace ts {
return count;
}
export function filter<T>(array: T[], f: (x: T) => boolean): T[] {
export function filter<T, U extends T>(array: T[], f: (x: T, i: number) => x is U): U[];
export function filter<T>(array: T[], f: (x: T, i: number) => boolean): T[];
export function filter<T>(array: T[], f: (x: T, i: number) => boolean): T[] {
let result: T[];
if (array) {
result = [];
for (const item of array) {
if (f(item)) {
result.push(item);
for (let i = 0; i < array.length; i++) {
const v = array[i];
if (f(v, i)) {
result.push(v);
}
}
}
return result;
}
export function map<T, U>(array: T[], f: (x: T) => U): U[] {
export function map<T, U>(array: T[], f: (x: T, i: number) => U): U[] {
let result: U[];
if (array) {
result = [];
for (const v of array) {
result.push(f(v));
for (let i = 0; i < array.length; i++) {
const v = array[i];
result.push(f(v, i));
}
}
return result;
}
/**
* Maps an array. If the mapped value is an array, it is spread into the result.
*/
export function flatMap<T, U>(array: T[], f: (x: T, i: number) => U | U[]): U[] {
let result: U[];
if (array) {
result = [];
for (let i = 0; i < array.length; i++) {
const v = array[i];
const ar = f(v, i);
if (ar) {
// We cast to <U> here to leverage the behavior of Array#concat
// which will append a single value here.
result = result.concat(<U[]>ar);
}
}
}
return result;
@ -172,18 +197,6 @@ namespace ts {
return [...array1, ...array2];
}
export function append<T>(array: T[], value: T): T[] {
if (value === undefined) return array;
if (!array || !array.length) return [value];
return [...array, value];
}
export function prepend<T>(array: T[], value: T): T[] {
if (value === undefined) return array;
if (!array || !array.length) return [value];
return [value, ...array];
}
export function deduplicate<T>(array: T[]): T[] {
let result: T[];
if (array) {
@ -197,6 +210,27 @@ namespace ts {
return result;
}
/**
* Compacts an array, removing any falsey elements.
*/
export function compact<T>(array: T[]): T[] {
let result: T[];
if (array) {
for (let i = 0; i < array.length; i++) {
const v = array[i];
if (result || !v) {
if (!result) {
result = array.slice(0, i);
}
if (v) {
result.push(v);
}
}
}
}
return result || array;
}
export function sum(array: any[], prop: string): number {
let result = 0;
for (const v of array) {
@ -223,15 +257,25 @@ namespace ts {
return true;
}
export function firstOrUndefined<T>(array: T[]): T {
return array && array.length > 0
? array[0]
: undefined;
}
export function singleOrUndefined<T>(array: T[]): T {
return array && array.length === 1
? array[0]
: undefined;
}
/**
* Returns the last element of an array if non-empty, undefined otherwise.
*/
export function lastOrUndefined<T>(array: T[]): T {
if (array.length === 0) {
return undefined;
}
return array[array.length - 1];
return array && array.length > 0
? array[array.length - 1]
: undefined;
}
/**
@ -263,9 +307,9 @@ namespace ts {
return ~low;
}
export function reduceLeft<T, U>(array: T[], f: (memo: U, value: T) => U, initial: U): U;
export function reduceLeft<T>(array: T[], f: (memo: T, value: T) => T): T;
export function reduceLeft<T>(array: T[], f: (memo: T, value: T) => T, initial?: T): T {
export function reduceLeft<T, U>(array: T[], f: (memo: U, value: T, i: number) => U, initial: U): U;
export function reduceLeft<T>(array: T[], f: (memo: T, value: T, i: number) => T): T;
export function reduceLeft<T>(array: T[], f: (memo: T, value: T, i: number) => T, initial?: T): T {
if (array) {
const count = array.length;
if (count > 0) {
@ -279,7 +323,7 @@ namespace ts {
result = initial;
}
while (pos < count) {
result = f(result, array[pos]);
result = f(result, array[pos], pos);
pos++;
}
return result;
@ -288,9 +332,9 @@ namespace ts {
return initial;
}
export function reduceRight<T, U>(array: T[], f: (memo: U, value: T) => U, initial: U): U;
export function reduceRight<T>(array: T[], f: (memo: T, value: T) => T): T;
export function reduceRight<T>(array: T[], f: (memo: T, value: T) => T, initial?: T): T {
export function reduceRight<T, U>(array: T[], f: (memo: U, value: T, i: number) => U, initial: U): U;
export function reduceRight<T>(array: T[], f: (memo: T, value: T, i: number) => T): T;
export function reduceRight<T>(array: T[], f: (memo: T, value: T, i: number) => T, initial?: T): T {
if (array) {
let pos = array.length - 1;
if (pos >= 0) {
@ -303,7 +347,7 @@ namespace ts {
result = initial;
}
while (pos >= 0) {
result = f(result, array[pos]);
result = f(result, array[pos], pos);
pos--;
}
return result;

View file

@ -2691,7 +2691,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
}
function synthesizedNodeStartsOnNewLine(node: Node) {
return nodeIsSynthesized(node) && (<SynthesizedNode>node).startsOnNewLine;
return nodeIsSynthesized(node) && node.startsOnNewLine;
}
function emitConditionalExpression(node: ConditionalExpression) {

File diff suppressed because it is too large Load diff

View file

@ -4069,6 +4069,10 @@ namespace ts {
function parseBlock(ignoreMissingOpenBrace: boolean, diagnosticMessage?: DiagnosticMessage): Block {
const node = <Block>createNode(SyntaxKind.Block);
if (parseExpected(SyntaxKind.OpenBraceToken, diagnosticMessage) || ignoreMissingOpenBrace) {
if (scanner.hasPrecedingLineBreak()) {
node.multiLine = true;
}
node.statements = parseList(ParsingContext.BlockStatements, parseStatement);
parseExpected(SyntaxKind.CloseBraceToken);
}

View file

@ -48,8 +48,12 @@ namespace ts {
hoistFunctionDeclaration,
startLexicalEnvironment,
endLexicalEnvironment,
identifierSubstitution: node => node,
expressionSubstitution: node => node,
enableExpressionSubstitution,
isExpressionSubstitutionEnabled,
onBeforeEmitNode: node => { },
onAfterEmitNode: node => { },
enableEmitNotification,
isEmitNotificationEnabled,
};
@ -112,8 +116,9 @@ namespace ts {
/**
* Sets flags that control emit behavior of a node.
*/
function setNodeEmitFlags(node: Node, flags: NodeEmitFlags) {
function setNodeEmitFlags<T extends Node>(node: T, flags: NodeEmitFlags) {
nodeEmitFlags[getNodeId(node)] = flags;
return node;
}
/**
@ -202,7 +207,7 @@ namespace ts {
case SyntaxKind.ClassExpression:
return generateNameForClassExpression();
default:
return createTempVariable(TempVariableKind.Auto);
return createTempVariable();
}
}
@ -281,11 +286,17 @@ namespace ts {
}
if (hoistedVariableDeclarations) {
statements = append(statements,
createVariableStatement(
createVariableDeclarationList(hoistedVariableDeclarations)
)
const statement = createVariableStatement(
/*modifiers*/ undefined,
createVariableDeclarationList(hoistedVariableDeclarations)
);
if (!statements) {
statements = [statement];
}
else {
statements.push(statement);
}
}
}

View file

@ -449,6 +449,7 @@ namespace ts {
/* @internal */ id?: number; // Unique id (used to look up NodeLinks)
parent?: Node; // Parent node (initialized by binding)
/* @internal */ original?: Node; // The original node if this is an updated node.
/* @internal */ startsOnNewLine?: boolean; // Whether a synthesized node should start on a new line (used by transforms).
/* @internal */ jsDocComment?: JSDocComment; // JSDoc for the node, if it has any. Only for .js files.
/* @internal */ symbol?: Symbol; // Symbol declared by node (initialized by binding)
/* @internal */ locals?: SymbolTable; // Locals associated with node (initialized by binding)
@ -1124,6 +1125,7 @@ namespace ts {
// @kind(SyntaxKind.Block)
export interface Block extends Statement {
statements: NodeArray<Statement>;
/*@internal*/ multiLine?: boolean;
}
// @kind(SyntaxKind.VariableStatement)
@ -1301,7 +1303,7 @@ namespace ts {
export interface EnumMember extends Declaration {
// This does include ComputedPropertyName, but the parser will give an error
// if it parses a ComputedPropertyName in an EnumMember
name: DeclarationName;
name: PropertyName;
initializer?: Expression;
}
@ -2765,6 +2767,7 @@ namespace ts {
ContainsParameterPropertyAssignments = 1 << 13,
ContainsSpreadElementExpression = 1 << 14,
ContainsComputedPropertyName = 1 << 15,
ContainsBlockScopedBinding = 1 << 16,
// Assertions
// - Bitmasks that are used to assert facts about the syntax of a node and its subtree.
@ -2777,12 +2780,12 @@ namespace ts {
// - Bitmasks that exclude flags from propagating out of a specific context
// into the subtree flags of their container.
NodeExcludes = TypeScript | Jsx | ES7 | ES6,
ArrowFunctionExcludes = ContainsDecorators | ContainsDefaultValueAssignments | ContainsLexicalThis | ContainsParameterPropertyAssignments,
FunctionExcludes = ContainsDecorators | ContainsDefaultValueAssignments | ContainsCapturedLexicalThis | ContainsLexicalThis | ContainsParameterPropertyAssignments,
ConstructorExcludes = ContainsDefaultValueAssignments | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsParameterPropertyAssignments,
MethodOrAccessorExcludes = ContainsDefaultValueAssignments | ContainsLexicalThis | ContainsCapturedLexicalThis,
ArrowFunctionExcludes = ContainsDecorators | ContainsDefaultValueAssignments | ContainsLexicalThis | ContainsParameterPropertyAssignments | ContainsBlockScopedBinding,
FunctionExcludes = ContainsDecorators | ContainsDefaultValueAssignments | ContainsCapturedLexicalThis | ContainsLexicalThis | ContainsParameterPropertyAssignments | ContainsBlockScopedBinding,
ConstructorExcludes = ContainsDefaultValueAssignments | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsBlockScopedBinding,
MethodOrAccessorExcludes = ContainsDefaultValueAssignments | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsBlockScopedBinding,
ClassExcludes = ContainsDecorators | ContainsPropertyInitializer | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsComputedPropertyName | ContainsParameterPropertyAssignments,
ModuleExcludes = ContainsDecorators | ContainsLexicalThis | ContainsCapturedLexicalThis,
ModuleExcludes = ContainsDecorators | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsBlockScopedBinding,
TypeExcludes = ~ContainsTypeScript,
ObjectLiteralExcludes = ContainsDecorators | ContainsComputedPropertyName,
ArrayLiteralOrCallOrNewExcludes = ContainsSpreadElementExpression,
@ -2797,8 +2800,7 @@ namespace ts {
UMDDefine = 1 << 4, // This node should be replaced with the UMD define helper.
NoLexicalEnvironment = 1 << 5, // A new LexicalEnvironment should *not* be introduced when emitting this node, this is primarily used when printing a SystemJS module.
SingleLine = 1 << 6, // The contents of this node should be emit on a single line.
MultiLine = 1 << 7, // The contents of this node should be emit on multiple lines.
AdviseOnEmitNode = 1 << 8, // The node printer should invoke the onBeforeEmitNode and onAfterEmitNode callbacks when printing this node.
AdviseOnEmitNode = 1 << 7, // The node printer should invoke the onBeforeEmitNode and onAfterEmitNode callbacks when printing this node.
}
/** Additional context provided to `visitEachChild` */
@ -2815,7 +2817,7 @@ namespace ts {
getCompilerOptions(): CompilerOptions;
getEmitResolver(): EmitResolver;
getNodeEmitFlags(node: Node): NodeEmitFlags;
setNodeEmitFlags(node: Node, flags: NodeEmitFlags): void;
setNodeEmitFlags<T extends Node>(node: T, flags: NodeEmitFlags): T;
hoistFunctionDeclaration(node: FunctionDeclaration): void;
hoistVariableDeclaration(node: Identifier): void;
isUniqueName(name: string): boolean;

View file

@ -8,12 +8,6 @@ namespace ts {
isNoDefaultLib?: boolean;
}
export interface SynthesizedNode extends Node {
leadingCommentRanges?: CommentRange[];
trailingCommentRanges?: CommentRange[];
startsOnNewLine: boolean;
}
export function getDeclarationOfKind(symbol: Symbol, kind: SyntaxKind): Declaration {
const declarations = symbol.declarations;
if (declarations) {
@ -179,6 +173,10 @@ namespace ts {
return node.pos;
}
export function isDefined(value: any): boolean {
return value !== undefined;
}
// Returns true if this node is missing from the actual source code. A 'missing' node is different
// from 'undefined/defined'. When a node is undefined (which can happen for optional nodes
// in the tree), it is definitely missing. However, a node may be defined, but still be
@ -1714,7 +1712,7 @@ namespace ts {
return getOperatorPrecedence(expression.kind, operator, hasArguments);
}
function getOperator(expression: Expression) {
export function getOperator(expression: Expression) {
if (expression.kind === SyntaxKind.BinaryExpression) {
return (<BinaryExpression>expression).operatorToken.kind;
}
@ -2724,6 +2722,10 @@ namespace ts {
// Literals
export function isNoSubstitutionTemplateLiteral(node: Node): node is LiteralExpression {
return node.kind === SyntaxKind.NoSubstitutionTemplateLiteral;
}
export function isLiteralKind(kind: SyntaxKind): boolean {
return SyntaxKind.FirstLiteralToken <= kind && kind <= SyntaxKind.LastLiteralToken;
}
@ -2817,6 +2819,10 @@ namespace ts {
// Type members
export function isMethodDeclaration(node: Node): node is MethodDeclaration {
return node.kind === SyntaxKind.MethodDeclaration;
}
export function isClassElement(node: Node): node is ClassElement {
const kind = node.kind;
return kind === SyntaxKind.Constructor
@ -2824,7 +2830,6 @@ namespace ts {
|| kind === SyntaxKind.MethodDeclaration
|| kind === SyntaxKind.GetAccessor
|| kind === SyntaxKind.SetAccessor
|| kind === SyntaxKind.MethodSignature
|| kind === SyntaxKind.IndexSignature;
}
@ -2890,6 +2895,10 @@ namespace ts {
return node.kind === SyntaxKind.BinaryExpression;
}
export function isConditionalExpression(node: Node): node is ConditionalExpression {
return node.kind === SyntaxKind.ConditionalExpression;
}
export function isCallExpression(node: Node): node is CallExpression {
return node.kind === SyntaxKind.CallExpression;
}
@ -2900,11 +2909,16 @@ namespace ts {
|| kind === SyntaxKind.NoSubstitutionTemplateLiteral;
}
export function isSpreadElementExpression(node: Node): node is SpreadElementExpression {
return node.kind === SyntaxKind.SpreadElementExpression;
}
export function isExpressionWithTypeArguments(node: Node): node is ExpressionWithTypeArguments {
return node.kind === SyntaxKind.ExpressionWithTypeArguments;
}
function isLeftHandSideExpressionKind(kind: SyntaxKind) {
export function isLeftHandSideExpression(node: Node): node is LeftHandSideExpression {
const kind = node.kind;
return kind === SyntaxKind.PropertyAccessExpression
|| kind === SyntaxKind.ElementAccessExpression
|| kind === SyntaxKind.NewExpression
@ -2930,11 +2944,8 @@ namespace ts {
|| kind === SyntaxKind.SuperKeyword;
}
export function isLeftHandSideExpression(node: Node): node is LeftHandSideExpression {
return isLeftHandSideExpressionKind(node.kind);
}
function isUnaryExpressionKind(kind: SyntaxKind): boolean {
export function isUnaryExpression(node: Node): node is UnaryExpression {
const kind = node.kind;
return kind === SyntaxKind.PrefixUnaryExpression
|| kind === SyntaxKind.PostfixUnaryExpression
|| kind === SyntaxKind.DeleteExpression
@ -2942,14 +2953,11 @@ namespace ts {
|| kind === SyntaxKind.VoidExpression
|| kind === SyntaxKind.AwaitExpression
|| kind === SyntaxKind.TypeAssertionExpression
|| isLeftHandSideExpressionKind(kind);
|| isLeftHandSideExpression(node);
}
export function isUnaryExpression(node: Node): node is UnaryExpression {
return isUnaryExpressionKind(node.kind);
}
export function isExpressionKind(kind: SyntaxKind): boolean {
export function isExpression(node: Node): node is Expression {
const kind = node.kind;
return kind === SyntaxKind.ConditionalExpression
|| kind === SyntaxKind.YieldExpression
|| kind === SyntaxKind.ArrowFunction
@ -2957,11 +2965,7 @@ namespace ts {
|| kind === SyntaxKind.SpreadElementExpression
|| kind === SyntaxKind.AsExpression
|| kind === SyntaxKind.OmittedExpression
|| isUnaryExpressionKind(kind);
}
export function isExpression(node: Node): node is Expression {
return isExpressionKind(node.kind);
|| isUnaryExpression(node);
}
// Misc
@ -3113,7 +3117,8 @@ namespace ts {
export function isStatement(node: Node): node is Statement {
const kind = node.kind;
return isStatementKindButNotDeclarationKind(kind)
|| isDeclarationStatementKind(kind);
|| isDeclarationStatementKind(kind)
|| kind === SyntaxKind.Block;
}
// Module references
@ -3149,6 +3154,10 @@ namespace ts {
|| kind === SyntaxKind.JsxSpreadAttribute;
}
export function isJsxSpreadAttribute(node: Node): node is JsxSpreadAttribute {
return node.kind === SyntaxKind.JsxSpreadAttribute;
}
// Clauses
export function isCaseOrDefaultClause(node: Node): node is CaseOrDefaultClause {
@ -3168,9 +3177,12 @@ namespace ts {
// Property assignments
export function isShortHandPropertyAssignment(node: Node): node is ShorthandPropertyAssignment {
const kind = node.kind;
return kind === SyntaxKind.ShorthandPropertyAssignment;
export function isPropertyAssignment(node: Node): node is PropertyAssignment {
return node.kind === SyntaxKind.PropertyAssignment;
}
export function isShorthandPropertyAssignment(node: Node): node is ShorthandPropertyAssignment {
return node.kind === SyntaxKind.ShorthandPropertyAssignment;
}
// Enum

View file

@ -2,7 +2,7 @@
/* @internal */
namespace ts {
export type OneOrMore<T extends Node> = T | NodeArrayNode<T>;
export type OneOrMany<T extends Node> = T | NodeArrayNode<T>;
/**
* Describes an edge of a Node, used when traversing a syntax tree.
*/
@ -18,6 +18,9 @@ namespace ts {
/** A callback used to lift a NodeArrayNode into a valid node. */
lift?: (nodes: NodeArray<Node>) => Node;
/** A callback used to parenthesize a node to preserve the intended order of operations. */
parenthesize?: (value: Node, parentNode: Node) => Node;
};
/**
@ -51,7 +54,7 @@ namespace ts {
{ name: "modifiers", test: isModifier },
{ name: "name", test: isBindingName },
{ name: "type", test: isTypeNode, optional: true },
{ name: "initializer", test: isExpression, optional: true },
{ name: "initializer", test: isExpression, optional: true, parenthesize: parenthesizeExpressionForList },
],
[SyntaxKind.Decorator]: [
{ name: "expression", test: isLeftHandSideExpression },
@ -107,34 +110,34 @@ namespace ts {
[SyntaxKind.BindingElement]: [
{ name: "propertyName", test: isPropertyName, optional: true },
{ name: "name", test: isBindingName },
{ name: "initializer", test: isExpression, optional: true },
{ name: "initializer", test: isExpression, optional: true, parenthesize: parenthesizeExpressionForList },
],
[SyntaxKind.ArrayLiteralExpression]: [
{ name: "elements", test: isExpression },
{ name: "elements", test: isExpression, parenthesize: parenthesizeExpressionForList },
],
[SyntaxKind.ObjectLiteralExpression]: [
{ name: "properties", test: isObjectLiteralElement },
],
[SyntaxKind.PropertyAccessExpression]: [
{ name: "expression", test: isLeftHandSideExpression },
{ name: "expression", test: isLeftHandSideExpression, parenthesize: parenthesizeForAccess },
{ name: "name", test: isIdentifier },
],
[SyntaxKind.ElementAccessExpression]: [
{ name: "expression", test: isLeftHandSideExpression },
{ name: "expression", test: isLeftHandSideExpression, parenthesize: parenthesizeForAccess },
{ name: "argumentExpression", test: isExpression },
],
[SyntaxKind.CallExpression]: [
{ name: "expression", test: isLeftHandSideExpression },
{ name: "expression", test: isLeftHandSideExpression, parenthesize: parenthesizeForAccess },
{ name: "typeArguments", test: isTypeNode },
{ name: "arguments", test: isExpression },
],
[SyntaxKind.NewExpression]: [
{ name: "expression", test: isLeftHandSideExpression },
{ name: "expression", test: isLeftHandSideExpression, parenthesize: parenthesizeForAccess },
{ name: "typeArguments", test: isTypeNode },
{ name: "arguments", test: isExpression },
],
[SyntaxKind.TaggedTemplateExpression]: [
{ name: "tag", test: isLeftHandSideExpression },
{ name: "tag", test: isLeftHandSideExpression, parenthesize: parenthesizeForAccess },
{ name: "template", test: isTemplate },
],
[SyntaxKind.TypeAssertionExpression]: [
@ -162,26 +165,26 @@ namespace ts {
{ name: "body", test: isConciseBody, lift: liftToBlock },
],
[SyntaxKind.DeleteExpression]: [
{ name: "expression", test: isUnaryExpression },
{ name: "expression", test: isUnaryExpression, parenthesize: parenthesizePrefixOperand },
],
[SyntaxKind.TypeOfExpression]: [
{ name: "expression", test: isUnaryExpression },
{ name: "expression", test: isUnaryExpression, parenthesize: parenthesizePrefixOperand },
],
[SyntaxKind.VoidExpression]: [
{ name: "expression", test: isUnaryExpression },
{ name: "expression", test: isUnaryExpression, parenthesize: parenthesizePrefixOperand },
],
[SyntaxKind.AwaitExpression]: [
{ name: "expression", test: isUnaryExpression },
{ name: "expression", test: isUnaryExpression, parenthesize: parenthesizePrefixOperand },
],
[SyntaxKind.PrefixUnaryExpression]: [
{ name: "operand", test: isUnaryExpression },
{ name: "operand", test: isUnaryExpression, parenthesize: parenthesizePrefixOperand },
],
[SyntaxKind.PostfixUnaryExpression]: [
{ name: "operand", test: isLeftHandSideExpression },
{ name: "operand", test: isLeftHandSideExpression, parenthesize: parenthesizePostfixOperand },
],
[SyntaxKind.BinaryExpression]: [
{ name: "left", test: isExpression },
{ name: "right", test: isExpression },
{ name: "left", test: isExpression, parenthesize: (node: Expression, parent: BinaryExpression) => parenthesizeBinaryOperand(getOperator(parent), node, true) },
{ name: "right", test: isExpression, parenthesize: (node: Expression, parent: BinaryExpression) => parenthesizeBinaryOperand(getOperator(parent), node, false) },
],
[SyntaxKind.ConditionalExpression]: [
{ name: "condition", test: isExpression },
@ -196,7 +199,7 @@ namespace ts {
{ name: "expression", test: isExpression, optional: true },
],
[SyntaxKind.SpreadElementExpression]: [
{ name: "expression", test: isExpression },
{ name: "expression", test: isExpression, parenthesize: parenthesizeExpressionForList },
],
[SyntaxKind.ClassExpression]: [
{ name: "decorators", test: isDecorator },
@ -207,7 +210,7 @@ namespace ts {
{ name: "members", test: isClassElement },
],
[SyntaxKind.ExpressionWithTypeArguments]: [
{ name: "expression", test: isLeftHandSideExpression },
{ name: "expression", test: isLeftHandSideExpression, parenthesize: parenthesizeForAccess },
{ name: "typeArguments", test: isTypeNode },
],
[SyntaxKind.AsExpression]: [
@ -227,7 +230,7 @@ namespace ts {
{ name: "declarationList", test: isVariableDeclarationList },
],
[SyntaxKind.ExpressionStatement]: [
{ name: "expression", test: isExpression },
{ name: "expression", test: isExpression, parenthesize: parenthesizeExpressionForExpressionStatement },
],
[SyntaxKind.IfStatement]: [
{ name: "expression", test: isExpression },
@ -290,7 +293,7 @@ namespace ts {
[SyntaxKind.VariableDeclaration]: [
{ name: "name", test: isBindingName },
{ name: "type", test: isTypeNode, optional: true },
{ name: "initializer", test: isExpression, optional: true },
{ name: "initializer", test: isExpression, optional: true, parenthesize: parenthesizeExpressionForList },
],
[SyntaxKind.VariableDeclarationList]: [
{ name: "declarations", test: isVariableDeclaration },
@ -419,7 +422,7 @@ namespace ts {
],
[SyntaxKind.PropertyAssignment]: [
{ name: "name", test: isPropertyName },
{ name: "initializer", test: isExpression },
{ name: "initializer", test: isExpression, parenthesize: parenthesizeExpressionForList },
],
[SyntaxKind.ShorthandPropertyAssignment]: [
{ name: "name", test: isIdentifier },
@ -427,7 +430,7 @@ namespace ts {
],
[SyntaxKind.EnumMember]: [
{ name: "name", test: isPropertyName },
{ name: "initializer", test: isExpression, optional: true },
{ name: "initializer", test: isExpression, optional: true, parenthesize: parenthesizeExpressionForList },
],
[SyntaxKind.SourceFile]: [
{ name: "statements", test: isStatement },
@ -528,7 +531,7 @@ namespace ts {
// Visit each original node.
for (let i = 0; i < count; i++) {
const node = nodes[i + start];
const visited = node && <OneOrMore<T>>visitor(node);
const visited = node && <OneOrMany<T>>visitor(node);
if (updated !== undefined || visited === undefined || visited !== node) {
if (updated === undefined) {
// Ensure we have a copy of `nodes`, up to the current index.
@ -539,14 +542,14 @@ namespace ts {
aggregateTransformFlags(visited);
}
addNode(updated, visited, test);
addNodeWorker(updated, visited, /*addOnNewLine*/ undefined, test);
}
}
if (updated !== undefined) {
return <TArray>(isModifiersArray(nodes)
? createModifiersArray(updated, nodes)
: createNodeArray(updated, nodes));
: createNodeArray(updated, nodes, nodes.hasTrailingComma));
}
return nodes;
@ -575,21 +578,28 @@ namespace ts {
const edgeTraversalPath = nodeEdgeTraversalMap[node.kind];
if (edgeTraversalPath) {
let modifiers: NodeFlags;
for (const edge of edgeTraversalPath) {
const value = <Node | NodeArray<Node>>node[edge.name];
if (value !== undefined) {
const visited = visitEdge(edge, value, visitor);
if (visited && isArray(visited) && isModifiersArray(visited)) {
modifiers = visited.flags;
}
if (updated !== undefined || visited !== value) {
if (updated === undefined) {
updated = cloneNode(node, /*location*/ node, node.flags & ~NodeFlags.Modifier, /*parent*/ undefined, /*original*/ node);
updated = getMutableNode(node);
updated.flags &= ~NodeFlags.Modifier;
}
if (visited && isArray(visited) && isModifiersArray(visited)) {
updated[edge.name] = visited;
updated.flags |= visited.flags;
if (modifiers) {
updated.flags |= modifiers;
modifiers = undefined;
}
else {
updated[edge.name] = visited;
if (visited !== value) {
setEdgeValue(updated, edge, visited);
}
}
}
@ -609,6 +619,7 @@ namespace ts {
if (updated !== node) {
aggregateTransformFlags(updated);
updated.original = node;
}
return updated;
@ -627,6 +638,26 @@ namespace ts {
: visitNode(<Node>value, visitor, edge.test, edge.optional, edge.lift);
}
/**
* Sets the value of an edge, adjusting the value as necessary for cases such as expression precedence.
*/
function setEdgeValue(parentNode: Node & Map<any>, edge: NodeEdge, value: Node | NodeArray<Node>) {
if (value && edge.parenthesize && !isArray(value)) {
value = parenthesizeEdge(<Node>value, parentNode, edge.parenthesize, edge.test);
}
parentNode[edge.name] = value;
}
/**
* Applies parentheses to a node to ensure the correct precedence.
*/
function parenthesizeEdge(node: Node, parentNode: Node, parenthesize: (node: Node, parentNode: Node) => Node, test: (node: Node) => boolean) {
node = parenthesize(node, parentNode);
Debug.assert(test === undefined || test(node), "Unexpected node kind after visit.");
return node;
}
/**
* Appends a node to an array.
*
@ -634,16 +665,8 @@ namespace ts {
* @param from The source Node or NodeArrayNode.
* @param test The node test used to validate each node.
*/
export function addNode<T extends Node>(to: T[], from: OneOrMore<T>, test?: (node: Node) => boolean) {
if (to !== undefined && from !== undefined) {
if (isNodeArrayNode(from)) {
addNodes(to, from.nodes, test);
}
else {
Debug.assert(test === undefined || test(from), "Wrong node type after visit.");
to.push(from);
}
}
export function addNode<T extends Node>(to: T[], from: OneOrMany<T>, startOnNewLine?: boolean) {
addNodeWorker(to, from, startOnNewLine, /*test*/ undefined);
}
/**
@ -653,10 +676,30 @@ namespace ts {
* @param from The source array of Node or NodeArrayNode.
* @param test The node test used to validate each node.
*/
export function addNodes<T extends Node>(to: T[], from: OneOrMore<T>[], test?: (node: Node) => boolean) {
if (to !== undefined && from !== undefined) {
export function addNodes<T extends Node>(to: T[], from: OneOrMany<T>[], startOnNewLine?: boolean) {
addNodesWorker(to, from, startOnNewLine, /*test*/ undefined);
}
function addNodeWorker<T extends Node>(to: T[], from: OneOrMany<T>, startOnNewLine: boolean, test: (node: Node) => boolean) {
if (to && from) {
if (isNodeArrayNode(from)) {
addNodesWorker(to, from.nodes, startOnNewLine, test);
}
else {
Debug.assert(test === undefined || test(from), "Wrong node type after visit.");
if (startOnNewLine) {
from.startsOnNewLine = true;
}
to.push(from);
}
}
}
function addNodesWorker<T extends Node>(to: T[], from: OneOrMany<T>[], startOnNewLine: boolean, test: (node: Node) => boolean) {
if (to && from) {
for (const node of from) {
addNode(to, node, test);
addNodeWorker(to, node, startOnNewLine, test);
}
}
}
@ -821,7 +864,7 @@ namespace ts {
*
* @param nodes The NodeArray.
*/
function liftToBlock(nodes: NodeArray<Node>) {
export function liftToBlock(nodes: NodeArray<Node>) {
Debug.assert(every(nodes, isStatement), "Cannot lift nodes to a Block.");
return createBlock(<NodeArray<Statement>>nodes);
}

View file

@ -1,54 +1,54 @@
/**
* Declaration module describing the TypeScript Server protocol
/**
* Declaration module describing the TypeScript Server protocol
*/
declare namespace ts.server.protocol {
/**
* A TypeScript Server message
/**
* A TypeScript Server message
*/
export interface Message {
/**
* Sequence number of the message
/**
* Sequence number of the message
*/
seq: number;
/**
* One of "request", "response", or "event"
* One of "request", "response", or "event"
*/
type: string;
}
/**
* Client-initiated request message
/**
* Client-initiated request message
*/
export interface Request extends Message {
/**
* The command to execute
* The command to execute
*/
command: string;
/**
* Object containing arguments for the command
/**
* Object containing arguments for the command
*/
arguments?: any;
}
/**
* Request to reload the project structure for all the opened files
* Request to reload the project structure for all the opened files
*/
export interface ReloadProjectsRequest extends Message {
}
/**
* Server-initiated event message
/**
* Server-initiated event message
*/
export interface Event extends Message {
/**
* Name of event
/**
* Name of event
*/
event: string;
/**
* Event-specific information
/**
* Event-specific information
*/
body?: any;
}
@ -62,18 +62,18 @@ declare namespace ts.server.protocol {
*/
request_seq: number;
/**
* Outcome of the request.
/**
* Outcome of the request.
*/
success: boolean;
/**
/**
* The command requested.
*/
command: string;
/**
* Contains error message if success === false.
/**
* Contains error message if success === false.
*/
message?: string;
@ -83,7 +83,7 @@ declare namespace ts.server.protocol {
body?: any;
}
/**
/**
* Arguments for FileRequest messages.
*/
export interface FileRequestArgs {
@ -93,7 +93,7 @@ declare namespace ts.server.protocol {
file: string;
}
/**
/**
* Arguments for ProjectInfoRequest request.
*/
export interface ProjectInfoRequestArgs extends FileRequestArgs {
@ -110,7 +110,7 @@ declare namespace ts.server.protocol {
arguments: ProjectInfoRequestArgs;
}
/**
/**
* Response message body for "projectInfo" request
*/
export interface ProjectInfo {
@ -125,7 +125,7 @@ declare namespace ts.server.protocol {
fileNames?: string[];
}
/**
/**
* Response message for "projectInfo" request
*/
export interface ProjectInfoResponse extends Response {
@ -144,12 +144,12 @@ declare namespace ts.server.protocol {
* (file, line, character offset), where line and character offset are 1-based.
*/
export interface FileLocationRequestArgs extends FileRequestArgs {
/**
/**
* The line number for the request (1-based).
*/
line: number;
/**
/**
* The character offset (on the line) for the request (1-based).
*/
offset: number;
@ -216,7 +216,7 @@ declare namespace ts.server.protocol {
* Object found in response messages defining a span of text in a specific source file.
*/
export interface FileSpan extends TextSpan {
/**
/**
* File containing text span.
*/
file: string;
@ -300,14 +300,14 @@ declare namespace ts.server.protocol {
*/
lineText: string;
/**
/**
* True if reference is a write location, false otherwise.
*/
isWriteAccess: boolean;
}
/**
* The body of a "references" response message.
* The body of a "references" response message.
*/
export interface ReferencesResponseBody {
/**
@ -325,7 +325,7 @@ declare namespace ts.server.protocol {
*/
symbolStartOffset: number;
/**
/**
* The full display name of the symbol.
*/
symbolDisplayString: string;
@ -355,7 +355,7 @@ declare namespace ts.server.protocol {
}
/**
* Information about the item to be renamed.
* Information about the item to be renamed.
*/
export interface RenameInfo {
/**
@ -373,7 +373,7 @@ declare namespace ts.server.protocol {
*/
displayName: string;
/**
/**
* Full display name of item to be renamed.
*/
fullDisplayName: string;
@ -383,7 +383,7 @@ declare namespace ts.server.protocol {
*/
kind: string;
/**
/**
* Optional modifiers for the kind (such as 'public').
*/
kindModifiers: string;
@ -469,7 +469,7 @@ declare namespace ts.server.protocol {
placeOpenBraceOnNewLineForControlBlocks?: boolean;
/** Index operator */
[key: string] : string | number | boolean;
[key: string]: string | number | boolean;
}
/**
@ -477,7 +477,7 @@ declare namespace ts.server.protocol {
*/
export interface ConfigureRequestArguments {
/**
/**
* Information about the host, for example 'Emacs 24.4' or
* 'Sublime Text version 3075'
*/
@ -495,7 +495,7 @@ declare namespace ts.server.protocol {
}
/**
* Configure request; value of command field is "configure". Specifies
* Configure request; value of command field is "configure". Specifies
* host information, such as host type, tab size, and indent size.
*/
export interface ConfigureRequest extends Request {
@ -514,8 +514,8 @@ declare namespace ts.server.protocol {
*/
export interface OpenRequestArgs extends FileRequestArgs {
/**
* Used when a version of the file content is known to be more up to date than the one on disk.
* Then the known content will be used upon opening instead of the disk copy
* Used when a version of the file content is known to be more up to date than the one on disk.
* Then the known content will be used upon opening instead of the disk copy
*/
fileContent?: string;
}
@ -751,7 +751,7 @@ declare namespace ts.server.protocol {
* Optional modifiers for the kind (such as 'public').
*/
kindModifiers: string;
/**
/**
* A string that is used for comparing completion items so that they can be ordered. This
* is often the same as the name but may be different in certain circumstances.
*/
@ -794,7 +794,7 @@ declare namespace ts.server.protocol {
}
/**
* Signature help information for a single parameter
* Signature help information for a single parameter
*/
export interface SignatureHelpParameter {
@ -814,18 +814,18 @@ declare namespace ts.server.protocol {
displayParts: SymbolDisplayPart[];
/**
* Whether the parameter is optional or not.
* Whether the parameter is optional or not.
*/
isOptional: boolean;
}
/**
* Represents a single signature to show in signature help.
* Represents a single signature to show in signature help.
*/
export interface SignatureHelpItem {
/**
* Whether the signature accepts a variable number of arguments.
* Whether the signature accepts a variable number of arguments.
*/
isVariadic: boolean;
@ -845,7 +845,7 @@ declare namespace ts.server.protocol {
separatorDisplayParts: SymbolDisplayPart[];
/**
* The signature helps items for the parameters.
* The signature helps items for the parameters.
*/
parameters: SignatureHelpParameter[];
@ -861,17 +861,17 @@ declare namespace ts.server.protocol {
export interface SignatureHelpItems {
/**
* The signature help items.
* The signature help items.
*/
items: SignatureHelpItem[];
/**
* The span for which signature help should appear on a signature
* The span for which signature help should appear on a signature
*/
applicableSpan: TextSpan;
/**
* The item selected in the set of available help items.
* The item selected in the set of available help items.
*/
selectedItemIndex: number;
@ -895,7 +895,7 @@ declare namespace ts.server.protocol {
/**
* Signature help request; value of command field is "signatureHelp".
* Given a file location (file, line, col), return the signature
* Given a file location (file, line, col), return the signature
* help.
*/
export interface SignatureHelpRequest extends FileLocationRequest {
@ -926,8 +926,8 @@ declare namespace ts.server.protocol {
}
/**
* GeterrForProjectRequest request; value of command field is
* "geterrForProject". It works similarly with 'Geterr', only
* GeterrForProjectRequest request; value of command field is
* "geterrForProject". It works similarly with 'Geterr', only
* it request for every file in this project.
*/
export interface GeterrForProjectRequest extends Request {
@ -997,7 +997,7 @@ declare namespace ts.server.protocol {
diagnostics: Diagnostic[];
}
/**
/**
* Event message for "syntaxDiag" and "semanticDiag" event types.
* These events provide syntactic and semantic errors for a file.
*/
@ -1033,7 +1033,7 @@ declare namespace ts.server.protocol {
export interface ReloadResponse extends Response {
}
/**
/**
* Arguments for saveto request.
*/
export interface SavetoRequestArgs extends FileRequestArgs {
@ -1109,7 +1109,7 @@ declare namespace ts.server.protocol {
*/
kindModifiers?: string;
/**
/**
* The file in which the symbol is found.
*/
file: string;
@ -1156,7 +1156,7 @@ declare namespace ts.server.protocol {
/**
* Change request message; value of command field is "change".
* Update the server's view of the file named by argument 'file'.
* Update the server's view of the file named by argument 'file'.
* Server does not currently send a response to a change request.
*/
export interface ChangeRequest extends FileLocationRequest {