Merge branch 'transforms-flags' into transforms-transformer

This commit is contained in:
Ron Buckton 2016-02-12 15:10:57 -08:00
commit ceae78bea0
4 changed files with 525 additions and 368 deletions

View file

@ -1962,16 +1962,20 @@ namespace ts {
transformFlags = TransformFlags.AssertTypeScript; transformFlags = TransformFlags.AssertTypeScript;
} }
} }
break; break;
case SyntaxKind.ExpressionStatement: case SyntaxKind.ExpressionStatement:
// if (node.flags & NodeFlags.Generated) { if (nodeIsSynthesized(node)) {
// let expression = (<ExpressionStatement>node).expression; const expression = (<ExpressionStatement>node).expression;
// if (expression.kind === SyntaxKind.CallExpression if (nodeIsSynthesized(expression)
// && (<CallExpression>expression).expression.kind === SyntaxKind.SuperKeyword) { && isCallExpression(expression)
// transformFlags |= TransformFlags.AssertES6; && 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; break;
@ -2082,17 +2086,16 @@ namespace ts {
case SyntaxKind.VariableDeclarationList: case SyntaxKind.VariableDeclarationList:
// If a VariableDeclarationList is `let` or `const`, then it is ES6 syntax. // If a VariableDeclarationList is `let` or `const`, then it is ES6 syntax.
if (node.flags & NodeFlags.Let if (node.flags & NodeFlags.BlockScoped) {
|| node.flags & NodeFlags.Const) {
transformFlags |= TransformFlags.AssertES6; transformFlags |= TransformFlags.AssertES6;
} }
break; break;
case SyntaxKind.VariableStatement: case SyntaxKind.VariableStatement:
// If a VariableStatement is exported, then it is ES6 syntax. // If a VariableStatement is exported, then it is either ES6 or TypeScript syntax.
if (node.flags & NodeFlags.Export) { if (node.flags & NodeFlags.Export) {
transformFlags |= TransformFlags.AssertES6; transformFlags |= TransformFlags.AssertES6 | TransformFlags.AssertTypeScript;
} }
break; break;
@ -2114,13 +2117,13 @@ namespace ts {
break; break;
case SyntaxKind.HeritageClause: case SyntaxKind.HeritageClause:
// An `extends` HertiageClause is ES6 syntax.
if ((<HeritageClause>node).token === SyntaxKind.ExtendsKeyword) { if ((<HeritageClause>node).token === SyntaxKind.ExtendsKeyword) {
// An `extends` HeritageClause is ES6 syntax.
transformFlags |= TransformFlags.AssertES6; transformFlags |= TransformFlags.AssertES6;
} }
else {
// An `implements` HeritageClause is TypeScript syntax. // An `implements` HeritageClause is TypeScript syntax.
else if ((<HeritageClause>node).token === SyntaxKind.ImplementsKeyword) { Debug.assert((<HeritageClause>node).token === SyntaxKind.ImplementsKeyword);
transformFlags |= TransformFlags.AssertTypeScript; transformFlags |= TransformFlags.AssertTypeScript;
} }

View file

@ -6,33 +6,91 @@ namespace ts {
let NodeConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; let NodeConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node;
let SourceFileConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; let SourceFileConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node;
function createNode(kind: SyntaxKind, location?: TextRange): Node { function createNode(kind: SyntaxKind, location?: TextRange, flags?: NodeFlags): Node {
const ConstructorForKind = kind === SyntaxKind.SourceFile const ConstructorForKind = kind === SyntaxKind.SourceFile
? (SourceFileConstructor || (SourceFileConstructor = objectAllocator.getSourceFileConstructor())) ? (SourceFileConstructor || (SourceFileConstructor = objectAllocator.getSourceFileConstructor()))
: (NodeConstructor || (NodeConstructor = objectAllocator.getNodeConstructor())); : (NodeConstructor || (NodeConstructor = objectAllocator.getNodeConstructor()));
return location const node = location
? new ConstructorForKind(kind, location.pos, location.end) ? new ConstructorForKind(kind, location.pos, location.end)
: new ConstructorForKind(kind, /*pos*/ -1, /*end*/ -1); : new ConstructorForKind(kind, /*pos*/ -1, /*end*/ -1);
if (flags) {
node.flags = flags;
}
return node;
} }
export function createNodeArray<T extends Node>(elements?: T[], pos?: number, end?: number): NodeArray<T> { export function createNodeArray<T extends Node>(elements?: T[], location?: TextRange): NodeArray<T> {
const array = <NodeArray<T>>(elements || []); if (elements !== undefined) {
array.pos = pos; if (isNodeArray(elements)) {
array.end = end; return elements;
}
}
else {
elements = [];
}
const array = <NodeArray<T>>elements;
if (location !== undefined) {
array.pos = location.pos;
array.end = location.end;
}
else {
array.pos = -1;
array.end = -1;
}
array.arrayKind = ArrayKind.NodeArray; array.arrayKind = ArrayKind.NodeArray;
return array; return array;
} }
export function createModifiersArray(elements?: Modifier[], pos?: number, end?: number): ModifiersArray { export function createModifiersArray(elements?: Modifier[], location?: TextRange): ModifiersArray {
const array = <ModifiersArray>(elements || []); let flags: NodeFlags;
array.pos = pos; if (elements !== undefined) {
array.end = end; if (isModifiersArray(elements)) {
return elements;
}
flags = 0;
for (const modifier of elements) {
flags |= modifierToFlag(modifier.kind);
}
}
else {
elements = [];
flags = 0;
}
const array = <ModifiersArray>elements;
if (location !== undefined) {
array.pos = location.pos;
array.end = location.end;
}
else {
array.pos = -1;
array.end = -1;
}
array.arrayKind = ArrayKind.ModifiersArray; array.arrayKind = ArrayKind.ModifiersArray;
array.flags = 0; array.flags = flags;
return array; return array;
} }
export function setModifiers<T extends Node>(node: T, modifiers: Modifier[]) {
if (modifiers !== undefined) {
const array = createModifiersArray(modifiers);
node.modifiers = array;
node.flags |= array.flags;
}
else {
node.modifiers = undefined;
}
return node;
}
export function createSynthesizedNode(kind: SyntaxKind, startsOnNewLine?: boolean): Node { export function createSynthesizedNode(kind: SyntaxKind, startsOnNewLine?: boolean): Node {
const node = <SynthesizedNode>createNode(kind, /*location*/ undefined); const node = <SynthesizedNode>createNode(kind, /*location*/ undefined);
node.startsOnNewLine = startsOnNewLine; node.startsOnNewLine = startsOnNewLine;
@ -40,11 +98,11 @@ namespace ts {
} }
export function createSynthesizedNodeArray<T extends Node>(elements?: T[]): NodeArray<T> { export function createSynthesizedNodeArray<T extends Node>(elements?: T[]): NodeArray<T> {
return createNodeArray(elements, /*pos*/ -1, /*end*/ -1); return createNodeArray(elements, /*location*/ undefined);
} }
export function createSynthesizedModifiersArray(elements?: Modifier[]): ModifiersArray { export function createSynthesizedModifiersArray(elements?: Modifier[]): ModifiersArray {
return createModifiersArray(elements, /*pos*/ -1, /*end*/ -1); return createModifiersArray(elements, /*location*/ undefined);
} }
/** /**

View file

@ -1284,17 +1284,7 @@ namespace ts {
return false; return false;
} }
export function isLiteralKind(kind: SyntaxKind): boolean {
return SyntaxKind.FirstLiteralToken <= kind && kind <= SyntaxKind.LastLiteralToken;
}
export function isTextualLiteralKind(kind: SyntaxKind): boolean {
return kind === SyntaxKind.StringLiteral || kind === SyntaxKind.NoSubstitutionTemplateLiteral;
}
export function isTemplateLiteralKind(kind: SyntaxKind): boolean {
return SyntaxKind.FirstTemplateToken <= kind && kind <= SyntaxKind.LastTemplateToken;
}
export function isNodeDescendentOf(node: Node, ancestor: Node): boolean { export function isNodeDescendentOf(node: Node, ancestor: Node): boolean {
while (node) { while (node) {
@ -1563,8 +1553,17 @@ namespace ts {
return node; return node;
} }
export function nodeStartsNewLexicalEnvironment(n: Node): boolean { export function nodeStartsNewLexicalEnvironment(node: Node): boolean {
return isFunctionLike(n) || n.kind === SyntaxKind.ModuleDeclaration || n.kind === SyntaxKind.SourceFile; const kind = node.kind;
return kind === SyntaxKind.Constructor
|| kind === SyntaxKind.FunctionExpression
|| kind === SyntaxKind.FunctionDeclaration
|| kind === SyntaxKind.ArrowFunction
|| kind === SyntaxKind.MethodDeclaration
|| kind === SyntaxKind.GetAccessor
|| kind === SyntaxKind.SetAccessor
|| kind === SyntaxKind.ModuleDeclaration
|| kind === SyntaxKind.SourceFile;
} }
/** /**
@ -2659,23 +2658,111 @@ namespace ts {
// All node tests in the following list should *not* reference parent pointers so that // All node tests in the following list should *not* reference parent pointers so that
// they may be used with transformations. // they may be used with transformations.
export function isPropertyAccessExpression(node: Node): node is PropertyAccessExpression { // Node Arrays
return node.kind === SyntaxKind.PropertyAccessExpression;
export function isNodeArray<T extends Node>(array: T[]): array is NodeArray<T> {
return (<NodeArray<T>>array).arrayKind === ArrayKind.NodeArray;
} }
export function isElementAccessExpression(node: Node): node is ElementAccessExpression { export function isModifiersArray(array: Modifier[]): array is ModifiersArray {
return node.kind === SyntaxKind.ElementAccessExpression; return (<ModifiersArray>array).arrayKind === ArrayKind.ModifiersArray;
} }
function isBindingPatternKind(kind: SyntaxKind) { // Literals
return kind === SyntaxKind.ArrayBindingPattern
|| kind === SyntaxKind.ObjectBindingPattern; export function isLiteralKind(kind: SyntaxKind): boolean {
return SyntaxKind.FirstLiteralToken <= kind && kind <= SyntaxKind.LastLiteralToken;
} }
export function isBindingPattern(node: Node): node is BindingPattern { export function isTextualLiteralKind(kind: SyntaxKind): boolean {
return node && isBindingPatternKind(node.kind); return kind === SyntaxKind.StringLiteral || kind === SyntaxKind.NoSubstitutionTemplateLiteral;
} }
export function isLiteralExpression(node: Node): node is LiteralExpression {
return isLiteralKind(node.kind);
}
// Pseudo-literals
export function isTemplateLiteralKind(kind: SyntaxKind): boolean {
return SyntaxKind.FirstTemplateToken <= kind && kind <= SyntaxKind.LastTemplateToken;
}
function isTemplateLiteralFragmentKind(kind: SyntaxKind) {
return kind === SyntaxKind.TemplateHead
|| kind === SyntaxKind.TemplateMiddle
|| kind === SyntaxKind.TemplateTail;
}
export function isTemplateLiteralFragment(node: Node): node is TemplateLiteralFragment {
return isTemplateLiteralFragmentKind(node.kind);
}
// Identifiers
export function isIdentifier(node: Node): node is Identifier {
return node.kind === SyntaxKind.Identifier;
}
// Keywords
export function isModifier(node: Node): node is Modifier {
return isModifierKind(node.kind);
}
// Names
export function isQualifiedName(node: Node): node is QualifiedName {
return node.kind === SyntaxKind.QualifiedName;
}
export function isComputedPropertyName(node: Node): node is ComputedPropertyName {
return node.kind === SyntaxKind.ComputedPropertyName;
}
export function isEntityName(node: Node): node is EntityName {
const kind = node.kind;
return kind === SyntaxKind.QualifiedName
|| kind === SyntaxKind.Identifier;
}
export function isPropertyName(node: Node): node is PropertyName {
const kind = node.kind;
return kind === SyntaxKind.Identifier
|| kind === SyntaxKind.StringLiteral
|| kind === SyntaxKind.NumericLiteral
|| kind === SyntaxKind.ComputedPropertyName;
}
export function isModuleName(node: Node): node is ModuleName {
const kind = node.kind;
return kind === SyntaxKind.Identifier
|| kind === SyntaxKind.StringLiteral;
}
export function isBindingName(node: Node): node is BindingName {
const kind = node.kind;
return kind === SyntaxKind.Identifier
|| kind === SyntaxKind.ObjectBindingPattern
|| kind === SyntaxKind.ArrayBindingPattern;
}
// Signature elements
export function isTypeParameter(node: Node): node is TypeParameterDeclaration {
return node.kind === SyntaxKind.TypeParameter;
}
export function isParameter(node: Node): node is ParameterDeclaration {
return node.kind === SyntaxKind.Parameter;
}
export function isDecorator(node: Node): node is Decorator {
return node.kind === SyntaxKind.Decorator;
}
// Type members
export function isClassElement(node: Node): node is ClassElement { export function isClassElement(node: Node): node is ClassElement {
const kind = node.kind; const kind = node.kind;
return kind === SyntaxKind.Constructor return kind === SyntaxKind.Constructor
@ -2687,37 +2774,80 @@ namespace ts {
|| kind === SyntaxKind.IndexSignature; || kind === SyntaxKind.IndexSignature;
} }
export function isQualifiedName(node: Node): node is QualifiedName { export function isObjectLiteralElement(node: Node): node is ObjectLiteralElement {
return node.kind === SyntaxKind.QualifiedName; const kind = node.kind;
return kind === SyntaxKind.PropertyAssignment
|| kind === SyntaxKind.ShorthandPropertyAssignment
|| kind === SyntaxKind.MethodDeclaration
|| kind === SyntaxKind.GetAccessor
|| kind === SyntaxKind.SetAccessor
|| kind === SyntaxKind.MissingDeclaration;
} }
export function isLiteralExpression(node: Node): node is LiteralExpression { // Type
return isLiteralKind(node.kind);
function isTypeNodeKind(kind: SyntaxKind) {
return (kind >= SyntaxKind.FirstTypeNode && kind <= SyntaxKind.LastTypeNode)
|| kind === SyntaxKind.AnyKeyword
|| kind === SyntaxKind.NumberKeyword
|| kind === SyntaxKind.BooleanKeyword
|| kind === SyntaxKind.StringKeyword
|| kind === SyntaxKind.SymbolKeyword
|| kind === SyntaxKind.VoidKeyword
|| kind === SyntaxKind.ExpressionWithTypeArguments;
} }
function isEntityNameKind(kind: SyntaxKind) { /**
return kind === SyntaxKind.QualifiedName * Node test that determines whether a node is a valid type node.
|| kind === SyntaxKind.Identifier; * This differs from the `isPartOfTypeNode` function which determines whether a node is *part*
* of a TypeNode.
*/
export function isTypeNode(node: Node): node is TypeNode {
return isTypeNodeKind(node.kind);
} }
export function isEntityName(node: Node): node is EntityName { // Binding patterns
return isEntityNameKind(node.kind);
export function isBindingPattern(node: Node): node is BindingPattern {
if (node) {
const kind = node.kind;
return kind === SyntaxKind.ArrayBindingPattern
|| kind === SyntaxKind.ObjectBindingPattern;
}
return false;
} }
export function isIdentifier(node: Node): node is Identifier { export function isBindingElement(node: Node): node is BindingElement {
return node.kind === SyntaxKind.Identifier; return node.kind === SyntaxKind.BindingElement;
} }
export function isComputedPropertyName(node: Node): node is ComputedPropertyName { // Expression
return node.kind === SyntaxKind.ComputedPropertyName;
export function isPropertyAccessExpression(node: Node): node is PropertyAccessExpression {
return node.kind === SyntaxKind.PropertyAccessExpression;
}
export function isElementAccessExpression(node: Node): node is ElementAccessExpression {
return node.kind === SyntaxKind.ElementAccessExpression;
} }
export function isBinaryExpression(node: Node): node is BinaryExpression { export function isBinaryExpression(node: Node): node is BinaryExpression {
return node.kind === SyntaxKind.BinaryExpression; return node.kind === SyntaxKind.BinaryExpression;
} }
export function isShortHandPropertyAssignment(node: Node): node is ShorthandPropertyAssignment { export function isCallExpression(node: Node): node is CallExpression {
return node.kind === SyntaxKind.ShorthandPropertyAssignment; return node.kind === SyntaxKind.CallExpression;
}
export function isTemplate(node: Node): node is Template {
const kind = node.kind;
return kind === SyntaxKind.TemplateExpression
|| kind === SyntaxKind.NoSubstitutionTemplateLiteral;
}
export function isExpressionWithTypeArguments(node: Node): node is ExpressionWithTypeArguments {
return node.kind === SyntaxKind.ExpressionWithTypeArguments;
} }
function isLeftHandSideExpressionKind(kind: SyntaxKind) { function isLeftHandSideExpressionKind(kind: SyntaxKind) {
@ -2744,7 +2874,7 @@ namespace ts {
|| kind === SyntaxKind.ThisKeyword || kind === SyntaxKind.ThisKeyword
|| kind === SyntaxKind.TrueKeyword || kind === SyntaxKind.TrueKeyword
|| kind === SyntaxKind.SuperKeyword; || kind === SyntaxKind.SuperKeyword;
} }
export function isLeftHandSideExpression(node: Node): node is LeftHandSideExpression { export function isLeftHandSideExpression(node: Node): node is LeftHandSideExpression {
return isLeftHandSideExpressionKind(node.kind); return isLeftHandSideExpressionKind(node.kind);
@ -2780,32 +2910,70 @@ namespace ts {
return isExpressionKind(node.kind); return isExpressionKind(node.kind);
} }
export function isDecorator(node: Node): node is Decorator { // Misc
return node.kind === SyntaxKind.Decorator;
export function isTemplateSpan(node: Node): node is TemplateSpan {
return node.kind === SyntaxKind.TemplateSpan;
} }
export function isModifier(node: Node): node is Modifier { // Element
return isModifierKind(node.kind);
export function isBlock(node: Node): node is Block {
return node.kind === SyntaxKind.Block;
} }
function isTypeNodeKind(kind: SyntaxKind) { export function isConciseBody(node: Node): node is ConciseBody {
return (kind >= SyntaxKind.FirstTypeNode && kind <= SyntaxKind.LastTypeNode) return isBlock(node)
|| kind === SyntaxKind.AnyKeyword || isExpression(node);
|| kind === SyntaxKind.NumberKeyword
|| kind === SyntaxKind.BooleanKeyword
|| kind === SyntaxKind.StringKeyword
|| kind === SyntaxKind.SymbolKeyword
|| kind === SyntaxKind.VoidKeyword
|| kind === SyntaxKind.ExpressionWithTypeArguments;
} }
/** export function isFunctionBody(node: Node): node is FunctionBody {
* Node test that determines whether a node is a valid type node. return isBlock(node);
* This differs from the `isPartOfTypeNode` function which determines whether a node is *part* }
* of a TypeNode.
*/ export function isForInitializer(node: Node): node is ForInitializer {
export function isTypeNode(node: Node): node is TypeNode { return isVariableDeclarationList(node)
return isTypeNodeKind(node.kind); || isExpression(node);
}
export function isVariableDeclaration(node: Node): node is VariableDeclaration {
return node.kind === SyntaxKind.VariableDeclaration;
}
export function isVariableDeclarationList(node: Node): node is VariableDeclarationList {
return node.kind === SyntaxKind.VariableDeclarationList;
}
export function isCaseBlock(node: Node): node is CaseBlock {
return node.kind === SyntaxKind.CaseBlock;
}
export function isModuleBody(node: Node): node is ModuleBody {
const kind = node.kind;
return kind === SyntaxKind.ModuleBlock
|| kind === SyntaxKind.ModuleDeclaration;
}
export function isImportClause(node: Node): node is ImportClause {
return node.kind === SyntaxKind.ImportClause;
}
export function isNamedImportBindings(node: Node): node is NamedImportBindings {
const kind = node.kind;
return kind === SyntaxKind.NamedImports
|| kind === SyntaxKind.NamespaceImport;
}
export function isImportSpecifier(node: Node): node is ImportSpecifier {
return node.kind === SyntaxKind.ImportSpecifier;
}
export function isNamedExports(node: Node): node is NamedExports {
return node.kind === SyntaxKind.NamedExports;
}
export function isExportSpecifier(node: Node): node is ExportSpecifier {
return node.kind === SyntaxKind.ExportSpecifier;
} }
function isDeclarationKind(kind: SyntaxKind) { function isDeclarationKind(kind: SyntaxKind) {
@ -2839,10 +3007,6 @@ namespace ts {
|| kind === SyntaxKind.VariableDeclaration; || kind === SyntaxKind.VariableDeclaration;
} }
export function isDeclaration(node: Node): node is Declaration {
return isDeclarationKind(node.kind);
}
function isDeclarationStatementKind(kind: SyntaxKind) { function isDeclarationStatementKind(kind: SyntaxKind) {
return kind === SyntaxKind.FunctionDeclaration return kind === SyntaxKind.FunctionDeclaration
|| kind === SyntaxKind.MissingDeclaration || kind === SyntaxKind.MissingDeclaration
@ -2856,10 +3020,6 @@ namespace ts {
|| kind === SyntaxKind.ExportAssignment; || kind === SyntaxKind.ExportAssignment;
} }
export function isDeclarationStatement(node: Node): node is DeclarationStatement {
return isDeclarationStatementKind(node.kind);
}
function isStatementKindButNotDeclarationKind(kind: SyntaxKind) { function isStatementKindButNotDeclarationKind(kind: SyntaxKind) {
return kind === SyntaxKind.BreakStatement return kind === SyntaxKind.BreakStatement
|| kind === SyntaxKind.ContinueStatement || kind === SyntaxKind.ContinueStatement
@ -2881,6 +3041,14 @@ namespace ts {
|| kind === SyntaxKind.WithStatement; || kind === SyntaxKind.WithStatement;
} }
export function isDeclaration(node: Node): node is Declaration {
return isDeclarationKind(node.kind);
}
export function isDeclarationStatement(node: Node): node is DeclarationStatement {
return isDeclarationStatementKind(node.kind);
}
/** /**
* Determines whether the node is a statement that is not also a declaration * Determines whether the node is a statement that is not also a declaration
*/ */
@ -2888,171 +3056,22 @@ namespace ts {
return isStatementKindButNotDeclarationKind(node.kind); return isStatementKindButNotDeclarationKind(node.kind);
} }
function isStatementKind(kind: SyntaxKind) { export function isStatement(node: Node): node is Statement {
const kind = node.kind;
return isStatementKindButNotDeclarationKind(kind) return isStatementKindButNotDeclarationKind(kind)
|| isDeclarationStatementKind(kind); || isDeclarationStatementKind(kind);
} }
export function isStatement(node: Node): node is Statement { // Module references
return isStatementKind(node.kind);
}
function isPropertyNameKind(kind: SyntaxKind) {
return kind === SyntaxKind.Identifier
|| kind === SyntaxKind.StringLiteral
|| kind === SyntaxKind.NumericLiteral
|| kind === SyntaxKind.ComputedPropertyName;
}
export function isPropertyName(node: Node): node is PropertyName {
return isPropertyNameKind(node.kind);
}
function isConciseBodyKind(kind: SyntaxKind) {
return kind === SyntaxKind.Block
|| isExpressionKind(kind);
}
export function isConciseBody(node: Node): node is ConciseBody {
return isConciseBodyKind(node.kind);
}
export function isTypeParameter(node: Node): node is TypeParameterDeclaration {
return node.kind === SyntaxKind.TypeParameter;
}
export function isParameter(node: Node): node is ParameterDeclaration {
return node.kind === SyntaxKind.Parameter;
}
export function isBindingElement(node: Node): node is BindingElement {
return node.kind === SyntaxKind.BindingElement;
}
function isObjectLiteralElementKind(kind: SyntaxKind) {
return kind === SyntaxKind.PropertyAssignment
|| kind === SyntaxKind.ShorthandPropertyAssignment
|| kind === SyntaxKind.MethodDeclaration
|| kind === SyntaxKind.GetAccessor
|| kind === SyntaxKind.SetAccessor
|| kind === SyntaxKind.MissingDeclaration;
}
export function isObjectLiteralElement(node: Node): node is ObjectLiteralElement {
return isObjectLiteralElementKind(node.kind);
}
function isTemplateKind(kind: SyntaxKind) {
return kind === SyntaxKind.TemplateExpression
|| kind === SyntaxKind.NoSubstitutionTemplateLiteral;
}
export function isTemplate(node: Node): node is Template {
return isTemplateKind(node.kind);
}
function isTemplateLiteralFragmentKind(kind: SyntaxKind) {
return kind === SyntaxKind.TemplateHead
|| kind === SyntaxKind.TemplateMiddle
|| kind === SyntaxKind.TemplateTail;
}
export function isTemplateLiteralFragment(node: Node): node is TemplateLiteralFragment {
return isTemplateLiteralFragmentKind(node.kind);
}
export function isTemplateSpan(node: Node): node is TemplateSpan {
return node.kind === SyntaxKind.TemplateSpan;
}
export function isHeritageClause(node: Node): node is HeritageClause {
return node.kind === SyntaxKind.HeritageClause;
}
export function isVariableDeclarationList(node: Node): node is VariableDeclarationList {
return node.kind === SyntaxKind.VariableDeclarationList;
}
function isForInitializerKind(kind: SyntaxKind) {
return kind === SyntaxKind.VariableDeclarationList
|| isExpressionKind(kind);
}
export function isForInitializer(node: Node): node is ForInitializer {
return isForInitializerKind(node.kind);
}
export function isCaseBlock(node: Node): node is CaseBlock {
return node.kind === SyntaxKind.CaseBlock;
}
export function isBlock(node: Node): node is Block {
return node.kind === SyntaxKind.Block;
}
export function isCatchClause(node: Node): node is CatchClause {
return node.kind === SyntaxKind.CatchClause;
}
export function isVariableDeclaration(node: Node): node is VariableDeclaration {
return node.kind === SyntaxKind.VariableDeclaration;
}
export function isEnumMember(node: Node): node is EnumMember {
return node.kind === SyntaxKind.EnumMember;
}
function isModuleNameKind(kind: SyntaxKind) {
return kind === SyntaxKind.Identifier
|| kind === SyntaxKind.StringLiteral;
}
export function isModuleName(node: Node): node is ModuleName {
return isModuleNameKind(node.kind);
}
function isCaseOrDefaultClauseKind(kind: SyntaxKind) {
return kind === SyntaxKind.CaseClause
|| kind === SyntaxKind.DefaultClause;
}
export function isCaseOrDefaultClause(node: Node): node is CaseOrDefaultClause {
return isCaseOrDefaultClauseKind(node.kind);
}
function isModuleReferenceKind(kind: SyntaxKind) {
return kind === SyntaxKind.ExternalModuleReference
|| isEntityNameKind(kind);
}
export function isModuleReference(node: Node): node is ModuleReference { export function isModuleReference(node: Node): node is ModuleReference {
return isModuleReferenceKind(node.kind); const kind = node.kind;
return kind === SyntaxKind.ExternalModuleReference
|| kind === SyntaxKind.QualifiedName
|| kind === SyntaxKind.Identifier;
} }
export function isImportClause(node: Node): node is ImportClause { // JSX
return node.kind === SyntaxKind.ImportClause;
}
function isNamedImportBindingsKind(kind: SyntaxKind) {
return kind === SyntaxKind.NamedImports
|| kind === SyntaxKind.NamespaceImport;
}
export function isNamedImportBindings(node: Node): node is NamedImportBindings {
return isNamedImportBindingsKind(node.kind);
}
export function isImportSpecifier(node: Node): node is ImportSpecifier {
return node.kind === SyntaxKind.ImportSpecifier;
}
export function isNamedExports(node: Node): node is NamedExports {
return node.kind === SyntaxKind.NamedExports;
}
export function isExportSpecifier(node: Node): node is ExportSpecifier {
return node.kind === SyntaxKind.ExportSpecifier;
}
export function isJsxOpeningElement(node: Node): node is JsxOpeningElement { export function isJsxOpeningElement(node: Node): node is JsxOpeningElement {
return node.kind === SyntaxKind.JsxOpeningElement; return node.kind === SyntaxKind.JsxOpeningElement;
@ -3062,55 +3081,56 @@ namespace ts {
return node.kind === SyntaxKind.JsxClosingElement; return node.kind === SyntaxKind.JsxClosingElement;
} }
function isJsxChildKind(kind: SyntaxKind) { export function isJsxChild(node: Node): node is JsxChild {
const kind = node.kind;
return kind === SyntaxKind.JsxElement return kind === SyntaxKind.JsxElement
|| kind === SyntaxKind.JsxExpression || kind === SyntaxKind.JsxExpression
|| kind === SyntaxKind.JsxSelfClosingElement || kind === SyntaxKind.JsxSelfClosingElement
|| kind === SyntaxKind.JsxText; || kind === SyntaxKind.JsxText;
} }
export function isJsxChild(node: Node): node is JsxChild { export function isJsxAttributeLike(node: Node): node is JsxAttributeLike {
return isJsxChildKind(node.kind); const kind = node.kind;
}
function isJsxAttributeLikeKind(kind: SyntaxKind) {
return kind === SyntaxKind.JsxAttribute return kind === SyntaxKind.JsxAttribute
|| kind === SyntaxKind.JsxSpreadAttribute; || kind === SyntaxKind.JsxSpreadAttribute;
} }
export function isJsxAttributeLike(node: Node): node is JsxAttributeLike { // Clauses
return isJsxAttributeLikeKind(node.kind);
export function isCaseOrDefaultClause(node: Node): node is CaseOrDefaultClause {
const kind = node.kind;
return kind === SyntaxKind.CaseClause
|| kind === SyntaxKind.DefaultClause;
} }
export function isExpressionWithTypeArguments(node: Node): node is ExpressionWithTypeArguments { export function isHeritageClause(node: Node): node is HeritageClause {
return node.kind === SyntaxKind.ExpressionWithTypeArguments; return node.kind === SyntaxKind.HeritageClause;
} }
function isModuleBodyKind(kind: SyntaxKind) { export function isCatchClause(node: Node): node is CatchClause {
return kind === SyntaxKind.ModuleBlock return node.kind === SyntaxKind.CatchClause;
|| kind === SyntaxKind.ModuleDeclaration;
} }
export function isModuleBody(node: Node): node is ModuleBody {
return isModuleBodyKind(node.kind); // Property assignments
export function isShortHandPropertyAssignment(node: Node): node is ShorthandPropertyAssignment {
const kind = node.kind;
return kind === SyntaxKind.ShorthandPropertyAssignment;
} }
function isBindingNameKind(kind: SyntaxKind) { // Enum
return kind === SyntaxKind.Identifier
|| isBindingPatternKind(kind); export function isEnumMember(node: Node): node is EnumMember {
return node.kind === SyntaxKind.EnumMember;
} }
export function isBindingName(node: Node): node is BindingName {
return isBindingNameKind(node.kind); // Synthesized
}
export function isNodeArrayNode<T extends Node>(node: Node): node is NodeArrayNode<T> { export function isNodeArrayNode<T extends Node>(node: Node): node is NodeArrayNode<T> {
return node.kind === SyntaxKind.NodeArrayNode; return node.kind === SyntaxKind.NodeArrayNode;
} }
export function isModifiersArray(array: NodeArray<Node>): array is ModifiersArray {
return array.arrayKind === ArrayKind.ModifiersArray;
}
} }
namespace ts { namespace ts {

View file

@ -2,6 +2,7 @@
/* @internal */ /* @internal */
namespace ts { namespace ts {
export type OneOrMore<T extends Node> = T | NodeArrayNode<T>;
/** /**
* Describes an edge of a Node, used when traversing a syntax tree. * Describes an edge of a Node, used when traversing a syntax tree.
*/ */
@ -469,10 +470,10 @@ namespace ts {
* @param node The Node to visit. * @param node The Node to visit.
* @param visitor The callback used to visit the Node. * @param visitor The callback used to visit the Node.
* @param test A callback to execute to verify the Node is valid. * @param test A callback to execute to verify the Node is valid.
* @param lift A callback to execute to lift a NodeArrayNode into a valid Node. * @param optional An optional value indicating whether the Node is itself optional.
* @param optional A value indicating whether the Node is optional. * @param lift An optional callback to execute to lift a NodeArrayNode into a valid Node.
*/ */
export function visitNode<T extends Node>(node: T, visitor: (node: Node) => Node, test?: (node: Node) => boolean, lift?: (node: NodeArray<Node>) => T, optional?: boolean): T { export function visitNode<T extends Node>(node: T, visitor: (node: Node) => Node, test: (node: Node) => boolean, optional?: boolean, lift?: (node: NodeArray<Node>) => T): T {
if (node === undefined) { if (node === undefined) {
return undefined; return undefined;
} }
@ -499,55 +500,56 @@ namespace ts {
* @param nodes The NodeArray to visit. * @param nodes The NodeArray to visit.
* @param visitor The callback used to visit a Node. * @param visitor The callback used to visit a Node.
* @param test A node test to execute for each node. * @param test A node test to execute for each node.
* @param start An optional value indicating the starting offset at which to start visiting.
* @param count An optional value indicating the maximum number of nodes to visit.
*/ */
export function visitNodes<T extends Node, TArray extends NodeArray<T>>(nodes: TArray, visitor: (node: Node) => Node, test?: (node: Node) => boolean): TArray { export function visitNodes<T extends Node, TArray extends NodeArray<T>>(nodes: TArray, visitor: (node: Node) => Node, test: (node: Node) => boolean, start?: number, count?: number): TArray {
if (nodes === undefined) { if (nodes === undefined) {
return undefined; return undefined;
} }
let updated: NodeArray<T> | ModifiersArray; let updated: T[];
for (let i = 0, len = nodes.length; i < len; i++) {
const node = nodes[i];
if (node === undefined) {
continue;
}
const visited = visitor(node); // Ensure start and count have valid values
const length = nodes.length;
if (start === undefined || start < 0) {
start = 0;
}
if (count === undefined || count > length - start) {
count = length - start;
}
// If we are not visiting all of the original nodes, we must always create a new array.
if (start > 0 || count < length) {
updated = [];
}
// Visit each original node.
for (let i = 0; i < count; i++) {
const node = nodes[i + start];
const visited = node && <OneOrMore<T>>visitor(node);
if (updated !== undefined || visited === undefined || visited !== node) { if (updated !== undefined || visited === undefined || visited !== node) {
if (updated === undefined) { if (updated === undefined) {
updated = isModifiersArray(nodes) // Ensure we have a copy of `nodes`, up to the current index.
? createModifiersArray(nodes.slice(0, i), nodes.pos, nodes.end) updated = nodes.slice(0, i);
: createNodeArray<T>(nodes.slice(0, i), nodes.pos, nodes.end);
} }
if (visited === undefined) { if (visited !== node) {
continue; aggregateTransformFlags(visited);
} }
if (isNodeArrayNode<T>(visited)) { addNode(updated, visited, test);
spreadNodeArrayNode(visited, updated, test);
}
else if (visited !== undefined) {
Debug.assert(test === undefined || test(visited), "Wrong node type after visit.");
if (visited !== node) {
aggregateTransformFlags(visited);
}
updated.push(<T>visited);
}
} }
} }
if (updated && isModifiersArray(updated)) { if (updated !== undefined) {
let flags: NodeFlags = 0; return <TArray>(isModifiersArray(nodes)
for (const node of updated) { ? createModifiersArray(updated, nodes)
flags |= modifierToFlag(node.kind); : createNodeArray(updated, nodes));
}
updated.flags = flags;
} }
return <TArray>updated || nodes; return nodes;
} }
/** /**
@ -555,36 +557,40 @@ namespace ts {
* *
* @param node The Node whose children will be visited. * @param node The Node whose children will be visited.
* @param visitor The callback used to visit each child. * @param visitor The callback used to visit each child.
* @param environment An optional lexical environment context for the visitor. * @param context A lexical environment context for the visitor.
*/ */
export function visitEachChild<T extends Node>(node: T, visitor: (node: Node) => Node, environment?: LexicalEnvironment): T { export function visitEachChild<T extends Node>(node: T, visitor: (node: Node) => Node, context: LexicalEnvironment): T;
export function visitEachChild<T extends Node>(node: T & Map<any>, visitor: (node: Node) => Node, context: LexicalEnvironment): T {
if (node === undefined) { if (node === undefined) {
return undefined; return undefined;
} }
const isNewLexicalEnvironment = environment !== undefined && nodeStartsNewLexicalEnvironment(node); let updated: T & Map<any>;
// If this node starts a new lexical environment, start a new lexical environment on the context.
const isNewLexicalEnvironment = nodeStartsNewLexicalEnvironment(node);
if (isNewLexicalEnvironment) { if (isNewLexicalEnvironment) {
environment.startLexicalEnvironment(); context.startLexicalEnvironment();
} }
let modifiers: NodeFlags;
let updated: T & Map<any>;
const edgeTraversalPath = nodeEdgeTraversalMap[node.kind]; const edgeTraversalPath = nodeEdgeTraversalMap[node.kind];
if (edgeTraversalPath) { if (edgeTraversalPath) {
for (const edge of edgeTraversalPath) { for (const edge of edgeTraversalPath) {
const value = (<Map<any>>node)[edge.name]; const value = <Node | NodeArray<Node>>node[edge.name];
if (value !== undefined) { if (value !== undefined) {
const visited = visitEdge(edge, value, visitor); const visited = visitEdge(edge, value, visitor);
if (updated !== undefined || visited !== value) { if (updated !== undefined || visited !== value) {
if (updated === undefined) { if (updated === undefined) {
updated = cloneNode(node, /*location*/ undefined, node.flags & ~NodeFlags.Modifier, /*parent*/ undefined, /*original*/ node); updated = cloneNode(node, /*location*/ node, node.flags & ~NodeFlags.Modifier, /*parent*/ undefined, /*original*/ node);
} }
updated[edge.name] = visited; if (visited && isArray(visited) && isModifiersArray(visited)) {
} updated[edge.name] = visited;
updated.flags |= visited.flags;
if (visited && isArray(visited) && isModifiersArray(visited)) { }
modifiers = visited.flags; else {
updated[edge.name] = visited;
}
} }
} }
} }
@ -593,14 +599,11 @@ namespace ts {
if (updated === undefined) { if (updated === undefined) {
updated = node; updated = node;
} }
else if (modifiers) {
updated.flags |= modifiers;
}
if (isNewLexicalEnvironment) { if (isNewLexicalEnvironment) {
const declarations = environment.endLexicalEnvironment(); const declarations = context.endLexicalEnvironment();
if (declarations !== undefined && declarations.length > 0) { if (declarations !== undefined && declarations.length > 0) {
updated = <T>mergeLexicalEnvironment(updated, declarations, /*nodeIsMutable*/ updated !== node); updated = <T>mergeLexicalEnvironment(updated, declarations);
} }
} }
@ -620,104 +623,177 @@ namespace ts {
*/ */
function visitEdge(edge: NodeEdge, value: Node | NodeArray<Node>, visitor: (node: Node) => Node) { function visitEdge(edge: NodeEdge, value: Node | NodeArray<Node>, visitor: (node: Node) => Node) {
return isArray(value) return isArray(value)
? visitNodes(<NodeArray<Node>>value, visitor, edge.test) ? visitNodes(<NodeArray<Node>>value, visitor, edge.test, /*start*/ undefined, /*count*/ undefined)
: visitNode(<Node>value, visitor, edge.test, edge.lift, edge.optional); : visitNode(<Node>value, visitor, edge.test, edge.optional, edge.lift);
} }
/** /**
* Spreads a NodeArrayNode into a NodeArray. * Appends a node to an array.
* *
* @param source The source NodeArrayNode. * @param to The destination array.
* @param dest The destination NodeArray. * @param from The source Node or NodeArrayNode.
* @param test The node test used to validate each node. * @param test The node test used to validate each node.
*/ */
function spreadNodeArrayNode<T extends Node>(source: NodeArrayNode<T>, dest: NodeArray<T>, test: (node: Node) => boolean) { export function addNode<T extends Node>(to: T[], from: OneOrMore<T>, test?: (node: Node) => boolean) {
for (const element of source.nodes) { if (to !== undefined && from !== undefined) {
if (element === undefined) { if (isNodeArrayNode(from)) {
continue; addNodes(to, from.nodes, test);
} }
else {
Debug.assert(test === undefined || test(from), "Wrong node type after visit.");
to.push(from);
}
}
}
Debug.assert(test === undefined || test(element), "Wrong node type after visit."); /**
dest.push(element); * Appends an array of nodes to an array.
*
* @param to The destination NodeArray.
* @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) {
for (const node of from) {
addNode(to, node, test);
}
} }
} }
/** /**
* Merge generated declarations of a lexical environment. * Merge generated declarations of a lexical environment.
*
* @param node The source node.
* @param declarations The generated lexical declarations.
*/ */
function mergeLexicalEnvironment(node: Node, declarations: Statement[], nodeIsMutable: boolean) { function mergeLexicalEnvironment(node: Node, declarations: Statement[]): Node {
const mutableNode = nodeIsMutable ? node : cloneNode(node, /*location*/ node, node.flags, /*parent*/ undefined, /*original*/ node);
switch (node.kind) { switch (node.kind) {
case SyntaxKind.SourceFile: case SyntaxKind.SourceFile:
mergeSourceFileLexicalEnvironment(<SourceFile>mutableNode, declarations); return mergeSourceFileLexicalEnvironment(<SourceFile>node, declarations);
break;
case SyntaxKind.ModuleDeclaration: case SyntaxKind.ModuleDeclaration:
mergeModuleDeclarationLexicalEnvironment(<ModuleDeclaration>mutableNode, declarations); return mergeModuleDeclarationLexicalEnvironment(<ModuleDeclaration>node, declarations);
break;
case SyntaxKind.FunctionDeclaration: case SyntaxKind.FunctionDeclaration:
case SyntaxKind.FunctionExpression: case SyntaxKind.FunctionExpression:
case SyntaxKind.ArrowFunction:
case SyntaxKind.MethodDeclaration: case SyntaxKind.MethodDeclaration:
case SyntaxKind.GetAccessor: case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor: case SyntaxKind.SetAccessor:
case SyntaxKind.Constructor: case SyntaxKind.Constructor:
mergeFunctionLikeLexicalEnvironment(<FunctionLikeDeclaration>mutableNode, declarations); case SyntaxKind.ArrowFunction:
break; return mergeFunctionLikeLexicalEnvironment(<FunctionLikeDeclaration>node, declarations);
case SyntaxKind.ModuleBlock:
case SyntaxKind.Block:
mergeBlockLexicalEnvironment(<Block>mutableNode, declarations);
break;
} }
return mutableNode; Debug.fail("Node is not a valid lexical environment.");
} }
/** /**
* Merge generated declarations of a lexical environment into a SourceFile. * Merge generated declarations of a lexical environment into a SourceFile.
*
* @param node The SourceFile node.
* @param declarations The generated lexical declarations.
*/ */
function mergeSourceFileLexicalEnvironment(node: SourceFile, declarations: Statement[]) { export function mergeSourceFileLexicalEnvironment(node: SourceFile, declarations: Statement[]) {
node.statements = mergeStatements(node.statements, declarations); if (declarations !== undefined && declarations.length) {
const mutableNode = cloneNode(node, /*location*/ node, node.flags, /*parent*/ undefined, /*original*/ node);
mutableNode.statements = mergeStatements(mutableNode.statements, declarations);
return mutableNode;
}
return node;
} }
/** /**
* Merge generated declarations of a lexical environment into a ModuleDeclaration. * Merge generated declarations of a lexical environment into a ModuleDeclaration.
*
* @param node The ModuleDeclaration node.
* @param declarations The generated lexical declarations.
*/ */
function mergeModuleDeclarationLexicalEnvironment(node: ModuleDeclaration, declarations: Statement[]) { export function mergeModuleDeclarationLexicalEnvironment(node: ModuleDeclaration, declarations: Statement[]) {
Debug.assert(node.body.kind === SyntaxKind.ModuleBlock); Debug.assert(node.body.kind === SyntaxKind.ModuleBlock);
node.body = <ModuleBlock>mergeLexicalEnvironment(node.body, declarations, /*nodeIsMutable*/ false); if (declarations !== undefined && declarations.length) {
const mutableNode = cloneNode(node, /*location*/ node, node.flags, /*parent*/ undefined, /*original*/ node);
mutableNode.body = mergeBlockLexicalEnvironment(<ModuleBlock>node.body, declarations);
return mutableNode;
}
return node;
} }
/** /**
* Merge generated declarations of a lexical environment into a FunctionLikeDeclaration. * Merge generated declarations of a lexical environment into a FunctionLikeDeclaration.
*
* @param node The function-like node.
* @param declarations The generated lexical declarations.
*/ */
function mergeFunctionLikeLexicalEnvironment(node: FunctionLikeDeclaration, declarations: Statement[]) { function mergeFunctionLikeLexicalEnvironment(node: FunctionLikeDeclaration, declarations: Statement[]) {
Debug.assert(node.body !== undefined); Debug.assert(node.body !== undefined);
if (node.body.kind === SyntaxKind.Block) { if (declarations !== undefined && declarations.length) {
node.body = <Block>mergeLexicalEnvironment(node.body, declarations, /*nodeIsMutable*/ false); const mutableNode = cloneNode(node, /*location*/ node, node.flags, /*parent*/ undefined, /*original*/ node);
mutableNode.body = mergeConciseBodyLexicalEnvironment(mutableNode.body, declarations);
return mutableNode;
} }
else {
node.body = createBlock([ return node;
createReturn(<Expression>node.body), }
...declarations
]); /**
* Merges generated lexical declarations into the FunctionBody of a non-arrow function-like declaration.
*
* @param node The ConciseBody of an arrow function.
* @param declarations The lexical declarations to merge.
*/
export function mergeFunctionBodyLexicalEnvironment(body: FunctionBody, declarations: Statement[]) {
if (declarations !== undefined && declarations.length > 0) {
return mergeBlockLexicalEnvironment(body, declarations);
} }
return body;
}
/**
* Merges generated lexical declarations into the ConciseBody of an ArrowFunction.
*
* @param node The ConciseBody of an arrow function.
* @param declarations The lexical declarations to merge.
*/
export function mergeConciseBodyLexicalEnvironment(body: ConciseBody, declarations: Statement[]) {
if (declarations !== undefined && declarations.length > 0) {
if (isBlock(body)) {
return mergeBlockLexicalEnvironment(body, declarations);
}
else {
return createBlock([
createReturn(body),
...declarations
]);
}
}
return body;
} }
/** /**
* Merge generated declarations of a lexical environment into a FunctionBody or ModuleBlock. * Merge generated declarations of a lexical environment into a FunctionBody or ModuleBlock.
*
* @param node The block into which to merge lexical declarations.
* @param declarations The lexical declarations to merge.
*/ */
function mergeBlockLexicalEnvironment(node: FunctionBody | ModuleBlock, declarations: Statement[]) { function mergeBlockLexicalEnvironment<T extends Block>(node: T, declarations: Statement[]) {
node.statements = mergeStatements(node.statements, declarations); const mutableNode = cloneNode(node, /*location*/ node, node.flags, /*parent*/ undefined, /*original*/ node);
mutableNode.statements = mergeStatements(node.statements, declarations);
return mutableNode;
} }
/** /**
* Merge generated declarations of a lexical environment into a NodeArray of Statement. * Merge generated declarations of a lexical environment into a NodeArray of Statement.
*
* @param statements The node array to concatentate with the supplied lexical declarations.
* @param declarations The lexical declarations to merge.
*/ */
function mergeStatements(statements: NodeArray<Statement>, declarations: Statement[]) { function mergeStatements(statements: NodeArray<Statement>, declarations: Statement[]) {
return createNodeArray(statements.concat(declarations), statements.pos, statements.end); return createNodeArray(concatenate(statements, declarations), /*location*/ statements);
} }
/** /**