Merge branch 'transforms-flags' into transforms-transformer
This commit is contained in:
commit
ceae78bea0
4 changed files with 525 additions and 368 deletions
|
@ -1962,16 +1962,20 @@ namespace ts {
|
|||
transformFlags = TransformFlags.AssertTypeScript;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case SyntaxKind.ExpressionStatement:
|
||||
// if (node.flags & NodeFlags.Generated) {
|
||||
// let expression = (<ExpressionStatement>node).expression;
|
||||
// if (expression.kind === SyntaxKind.CallExpression
|
||||
// && (<CallExpression>expression).expression.kind === SyntaxKind.SuperKeyword) {
|
||||
// transformFlags |= TransformFlags.AssertES6;
|
||||
// }
|
||||
// }
|
||||
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;
|
||||
|
||||
|
@ -2082,17 +2086,16 @@ namespace ts {
|
|||
|
||||
case SyntaxKind.VariableDeclarationList:
|
||||
// If a VariableDeclarationList is `let` or `const`, then it is ES6 syntax.
|
||||
if (node.flags & NodeFlags.Let
|
||||
|| node.flags & NodeFlags.Const) {
|
||||
if (node.flags & NodeFlags.BlockScoped) {
|
||||
transformFlags |= TransformFlags.AssertES6;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
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) {
|
||||
transformFlags |= TransformFlags.AssertES6;
|
||||
transformFlags |= TransformFlags.AssertES6 | TransformFlags.AssertTypeScript;
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -2114,13 +2117,13 @@ namespace ts {
|
|||
break;
|
||||
|
||||
case SyntaxKind.HeritageClause:
|
||||
// An `extends` HertiageClause is ES6 syntax.
|
||||
if ((<HeritageClause>node).token === SyntaxKind.ExtendsKeyword) {
|
||||
// An `extends` HeritageClause is ES6 syntax.
|
||||
transformFlags |= TransformFlags.AssertES6;
|
||||
}
|
||||
|
||||
// An `implements` HeritageClause is TypeScript syntax.
|
||||
else if ((<HeritageClause>node).token === SyntaxKind.ImplementsKeyword) {
|
||||
else {
|
||||
// An `implements` HeritageClause is TypeScript syntax.
|
||||
Debug.assert((<HeritageClause>node).token === SyntaxKind.ImplementsKeyword);
|
||||
transformFlags |= TransformFlags.AssertTypeScript;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,33 +6,91 @@ namespace ts {
|
|||
let NodeConstructor: 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
|
||||
? (SourceFileConstructor || (SourceFileConstructor = objectAllocator.getSourceFileConstructor()))
|
||||
: (NodeConstructor || (NodeConstructor = objectAllocator.getNodeConstructor()));
|
||||
|
||||
return location
|
||||
const node = location
|
||||
? new ConstructorForKind(kind, location.pos, location.end)
|
||||
: 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> {
|
||||
const array = <NodeArray<T>>(elements || []);
|
||||
array.pos = pos;
|
||||
array.end = end;
|
||||
export function createNodeArray<T extends Node>(elements?: T[], location?: TextRange): NodeArray<T> {
|
||||
if (elements !== undefined) {
|
||||
if (isNodeArray(elements)) {
|
||||
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;
|
||||
return array;
|
||||
}
|
||||
|
||||
export function createModifiersArray(elements?: Modifier[], pos?: number, end?: number): ModifiersArray {
|
||||
const array = <ModifiersArray>(elements || []);
|
||||
array.pos = pos;
|
||||
array.end = end;
|
||||
export function createModifiersArray(elements?: Modifier[], location?: TextRange): ModifiersArray {
|
||||
let flags: NodeFlags;
|
||||
if (elements !== undefined) {
|
||||
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.flags = 0;
|
||||
array.flags = flags;
|
||||
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 {
|
||||
const node = <SynthesizedNode>createNode(kind, /*location*/ undefined);
|
||||
node.startsOnNewLine = startsOnNewLine;
|
||||
|
@ -40,11 +98,11 @@ namespace ts {
|
|||
}
|
||||
|
||||
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 {
|
||||
return createModifiersArray(elements, /*pos*/ -1, /*end*/ -1);
|
||||
return createModifiersArray(elements, /*location*/ undefined);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1284,17 +1284,7 @@ namespace ts {
|
|||
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 {
|
||||
while (node) {
|
||||
|
@ -1563,8 +1553,17 @@ namespace ts {
|
|||
return node;
|
||||
}
|
||||
|
||||
export function nodeStartsNewLexicalEnvironment(n: Node): boolean {
|
||||
return isFunctionLike(n) || n.kind === SyntaxKind.ModuleDeclaration || n.kind === SyntaxKind.SourceFile;
|
||||
export function nodeStartsNewLexicalEnvironment(node: Node): boolean {
|
||||
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
|
||||
// they may be used with transformations.
|
||||
|
||||
export function isPropertyAccessExpression(node: Node): node is PropertyAccessExpression {
|
||||
return node.kind === SyntaxKind.PropertyAccessExpression;
|
||||
// Node Arrays
|
||||
|
||||
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 {
|
||||
return node.kind === SyntaxKind.ElementAccessExpression;
|
||||
export function isModifiersArray(array: Modifier[]): array is ModifiersArray {
|
||||
return (<ModifiersArray>array).arrayKind === ArrayKind.ModifiersArray;
|
||||
}
|
||||
|
||||
function isBindingPatternKind(kind: SyntaxKind) {
|
||||
return kind === SyntaxKind.ArrayBindingPattern
|
||||
|| kind === SyntaxKind.ObjectBindingPattern;
|
||||
// Literals
|
||||
|
||||
export function isLiteralKind(kind: SyntaxKind): boolean {
|
||||
return SyntaxKind.FirstLiteralToken <= kind && kind <= SyntaxKind.LastLiteralToken;
|
||||
}
|
||||
|
||||
export function isBindingPattern(node: Node): node is BindingPattern {
|
||||
return node && isBindingPatternKind(node.kind);
|
||||
export function isTextualLiteralKind(kind: SyntaxKind): boolean {
|
||||
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 {
|
||||
const kind = node.kind;
|
||||
return kind === SyntaxKind.Constructor
|
||||
|
@ -2687,37 +2774,80 @@ namespace ts {
|
|||
|| kind === SyntaxKind.IndexSignature;
|
||||
}
|
||||
|
||||
export function isQualifiedName(node: Node): node is QualifiedName {
|
||||
return node.kind === SyntaxKind.QualifiedName;
|
||||
export function isObjectLiteralElement(node: Node): node is ObjectLiteralElement {
|
||||
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 {
|
||||
return isLiteralKind(node.kind);
|
||||
// Type
|
||||
|
||||
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
|
||||
|| kind === SyntaxKind.Identifier;
|
||||
/**
|
||||
* Node test that determines whether a node is a valid type node.
|
||||
* 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 {
|
||||
return isEntityNameKind(node.kind);
|
||||
// Binding patterns
|
||||
|
||||
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 {
|
||||
return node.kind === SyntaxKind.Identifier;
|
||||
export function isBindingElement(node: Node): node is BindingElement {
|
||||
return node.kind === SyntaxKind.BindingElement;
|
||||
}
|
||||
|
||||
export function isComputedPropertyName(node: Node): node is ComputedPropertyName {
|
||||
return node.kind === SyntaxKind.ComputedPropertyName;
|
||||
// Expression
|
||||
|
||||
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 {
|
||||
return node.kind === SyntaxKind.BinaryExpression;
|
||||
}
|
||||
|
||||
export function isShortHandPropertyAssignment(node: Node): node is ShorthandPropertyAssignment {
|
||||
return node.kind === SyntaxKind.ShorthandPropertyAssignment;
|
||||
export function isCallExpression(node: Node): node is CallExpression {
|
||||
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) {
|
||||
|
@ -2744,7 +2874,7 @@ namespace ts {
|
|||
|| kind === SyntaxKind.ThisKeyword
|
||||
|| kind === SyntaxKind.TrueKeyword
|
||||
|| kind === SyntaxKind.SuperKeyword;
|
||||
}
|
||||
}
|
||||
|
||||
export function isLeftHandSideExpression(node: Node): node is LeftHandSideExpression {
|
||||
return isLeftHandSideExpressionKind(node.kind);
|
||||
|
@ -2780,32 +2910,70 @@ namespace ts {
|
|||
return isExpressionKind(node.kind);
|
||||
}
|
||||
|
||||
export function isDecorator(node: Node): node is Decorator {
|
||||
return node.kind === SyntaxKind.Decorator;
|
||||
// Misc
|
||||
|
||||
export function isTemplateSpan(node: Node): node is TemplateSpan {
|
||||
return node.kind === SyntaxKind.TemplateSpan;
|
||||
}
|
||||
|
||||
export function isModifier(node: Node): node is Modifier {
|
||||
return isModifierKind(node.kind);
|
||||
// Element
|
||||
|
||||
export function isBlock(node: Node): node is Block {
|
||||
return node.kind === SyntaxKind.Block;
|
||||
}
|
||||
|
||||
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;
|
||||
export function isConciseBody(node: Node): node is ConciseBody {
|
||||
return isBlock(node)
|
||||
|| isExpression(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Node test that determines whether a node is a valid type node.
|
||||
* 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 isFunctionBody(node: Node): node is FunctionBody {
|
||||
return isBlock(node);
|
||||
}
|
||||
|
||||
export function isForInitializer(node: Node): node is ForInitializer {
|
||||
return isVariableDeclarationList(node)
|
||||
|| 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) {
|
||||
|
@ -2839,10 +3007,6 @@ namespace ts {
|
|||
|| kind === SyntaxKind.VariableDeclaration;
|
||||
}
|
||||
|
||||
export function isDeclaration(node: Node): node is Declaration {
|
||||
return isDeclarationKind(node.kind);
|
||||
}
|
||||
|
||||
function isDeclarationStatementKind(kind: SyntaxKind) {
|
||||
return kind === SyntaxKind.FunctionDeclaration
|
||||
|| kind === SyntaxKind.MissingDeclaration
|
||||
|
@ -2856,10 +3020,6 @@ namespace ts {
|
|||
|| kind === SyntaxKind.ExportAssignment;
|
||||
}
|
||||
|
||||
export function isDeclarationStatement(node: Node): node is DeclarationStatement {
|
||||
return isDeclarationStatementKind(node.kind);
|
||||
}
|
||||
|
||||
function isStatementKindButNotDeclarationKind(kind: SyntaxKind) {
|
||||
return kind === SyntaxKind.BreakStatement
|
||||
|| kind === SyntaxKind.ContinueStatement
|
||||
|
@ -2881,6 +3041,14 @@ namespace ts {
|
|||
|| 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
|
||||
*/
|
||||
|
@ -2888,171 +3056,22 @@ namespace ts {
|
|||
return isStatementKindButNotDeclarationKind(node.kind);
|
||||
}
|
||||
|
||||
function isStatementKind(kind: SyntaxKind) {
|
||||
export function isStatement(node: Node): node is Statement {
|
||||
const kind = node.kind;
|
||||
return isStatementKindButNotDeclarationKind(kind)
|
||||
|| isDeclarationStatementKind(kind);
|
||||
}
|
||||
|
||||
export function isStatement(node: Node): node is Statement {
|
||||
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);
|
||||
}
|
||||
// Module references
|
||||
|
||||
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 {
|
||||
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;
|
||||
}
|
||||
// JSX
|
||||
|
||||
export function isJsxOpeningElement(node: Node): node is JsxOpeningElement {
|
||||
return node.kind === SyntaxKind.JsxOpeningElement;
|
||||
|
@ -3062,55 +3081,56 @@ namespace ts {
|
|||
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
|
||||
|| kind === SyntaxKind.JsxExpression
|
||||
|| kind === SyntaxKind.JsxSelfClosingElement
|
||||
|| kind === SyntaxKind.JsxText;
|
||||
}
|
||||
|
||||
export function isJsxChild(node: Node): node is JsxChild {
|
||||
return isJsxChildKind(node.kind);
|
||||
}
|
||||
|
||||
function isJsxAttributeLikeKind(kind: SyntaxKind) {
|
||||
export function isJsxAttributeLike(node: Node): node is JsxAttributeLike {
|
||||
const kind = node.kind;
|
||||
return kind === SyntaxKind.JsxAttribute
|
||||
|| kind === SyntaxKind.JsxSpreadAttribute;
|
||||
}
|
||||
|
||||
export function isJsxAttributeLike(node: Node): node is JsxAttributeLike {
|
||||
return isJsxAttributeLikeKind(node.kind);
|
||||
// Clauses
|
||||
|
||||
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 {
|
||||
return node.kind === SyntaxKind.ExpressionWithTypeArguments;
|
||||
export function isHeritageClause(node: Node): node is HeritageClause {
|
||||
return node.kind === SyntaxKind.HeritageClause;
|
||||
}
|
||||
|
||||
function isModuleBodyKind(kind: SyntaxKind) {
|
||||
return kind === SyntaxKind.ModuleBlock
|
||||
|| kind === SyntaxKind.ModuleDeclaration;
|
||||
export function isCatchClause(node: Node): node is CatchClause {
|
||||
return node.kind === SyntaxKind.CatchClause;
|
||||
}
|
||||
|
||||
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) {
|
||||
return kind === SyntaxKind.Identifier
|
||||
|| isBindingPatternKind(kind);
|
||||
// Enum
|
||||
|
||||
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> {
|
||||
return node.kind === SyntaxKind.NodeArrayNode;
|
||||
}
|
||||
|
||||
export function isModifiersArray(array: NodeArray<Node>): array is ModifiersArray {
|
||||
return array.arrayKind === ArrayKind.ModifiersArray;
|
||||
}
|
||||
}
|
||||
|
||||
namespace ts {
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
/* @internal */
|
||||
namespace ts {
|
||||
export type OneOrMore<T extends Node> = T | NodeArrayNode<T>;
|
||||
/**
|
||||
* 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 visitor The callback used to visit the Node.
|
||||
* @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 A value indicating whether the Node is optional.
|
||||
* @param optional An optional value indicating whether the Node is itself 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) {
|
||||
return undefined;
|
||||
}
|
||||
|
@ -499,55 +500,56 @@ namespace ts {
|
|||
* @param nodes The NodeArray to visit.
|
||||
* @param visitor The callback used to visit a 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) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
let updated: NodeArray<T> | ModifiersArray;
|
||||
for (let i = 0, len = nodes.length; i < len; i++) {
|
||||
const node = nodes[i];
|
||||
if (node === undefined) {
|
||||
continue;
|
||||
}
|
||||
let updated: T[];
|
||||
|
||||
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) {
|
||||
updated = isModifiersArray(nodes)
|
||||
? createModifiersArray(nodes.slice(0, i), nodes.pos, nodes.end)
|
||||
: createNodeArray<T>(nodes.slice(0, i), nodes.pos, nodes.end);
|
||||
// Ensure we have a copy of `nodes`, up to the current index.
|
||||
updated = nodes.slice(0, i);
|
||||
}
|
||||
|
||||
if (visited === undefined) {
|
||||
continue;
|
||||
if (visited !== node) {
|
||||
aggregateTransformFlags(visited);
|
||||
}
|
||||
|
||||
if (isNodeArrayNode<T>(visited)) {
|
||||
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);
|
||||
}
|
||||
addNode(updated, visited, test);
|
||||
}
|
||||
}
|
||||
|
||||
if (updated && isModifiersArray(updated)) {
|
||||
let flags: NodeFlags = 0;
|
||||
for (const node of updated) {
|
||||
flags |= modifierToFlag(node.kind);
|
||||
}
|
||||
|
||||
updated.flags = flags;
|
||||
if (updated !== undefined) {
|
||||
return <TArray>(isModifiersArray(nodes)
|
||||
? createModifiersArray(updated, nodes)
|
||||
: createNodeArray(updated, nodes));
|
||||
}
|
||||
|
||||
return <TArray>updated || nodes;
|
||||
return nodes;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -555,36 +557,40 @@ namespace ts {
|
|||
*
|
||||
* @param node The Node whose children will be visited.
|
||||
* @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) {
|
||||
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) {
|
||||
environment.startLexicalEnvironment();
|
||||
context.startLexicalEnvironment();
|
||||
}
|
||||
|
||||
let modifiers: NodeFlags;
|
||||
let updated: T & Map<any>;
|
||||
const edgeTraversalPath = nodeEdgeTraversalMap[node.kind];
|
||||
if (edgeTraversalPath) {
|
||||
for (const edge of edgeTraversalPath) {
|
||||
const value = (<Map<any>>node)[edge.name];
|
||||
const value = <Node | NodeArray<Node>>node[edge.name];
|
||||
if (value !== undefined) {
|
||||
const visited = visitEdge(edge, value, visitor);
|
||||
if (updated !== undefined || visited !== value) {
|
||||
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)) {
|
||||
modifiers = visited.flags;
|
||||
if (visited && isArray(visited) && isModifiersArray(visited)) {
|
||||
updated[edge.name] = visited;
|
||||
updated.flags |= visited.flags;
|
||||
}
|
||||
else {
|
||||
updated[edge.name] = visited;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -593,14 +599,11 @@ namespace ts {
|
|||
if (updated === undefined) {
|
||||
updated = node;
|
||||
}
|
||||
else if (modifiers) {
|
||||
updated.flags |= modifiers;
|
||||
}
|
||||
|
||||
if (isNewLexicalEnvironment) {
|
||||
const declarations = environment.endLexicalEnvironment();
|
||||
const declarations = context.endLexicalEnvironment();
|
||||
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) {
|
||||
return isArray(value)
|
||||
? visitNodes(<NodeArray<Node>>value, visitor, edge.test)
|
||||
: visitNode(<Node>value, visitor, edge.test, edge.lift, edge.optional);
|
||||
? visitNodes(<NodeArray<Node>>value, visitor, edge.test, /*start*/ undefined, /*count*/ undefined)
|
||||
: 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 dest The destination NodeArray.
|
||||
* @param to The destination array.
|
||||
* @param from The source Node or NodeArrayNode.
|
||||
* @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) {
|
||||
for (const element of source.nodes) {
|
||||
if (element === undefined) {
|
||||
continue;
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
*
|
||||
* @param node The source node.
|
||||
* @param declarations The generated lexical declarations.
|
||||
*/
|
||||
function mergeLexicalEnvironment(node: Node, declarations: Statement[], nodeIsMutable: boolean) {
|
||||
const mutableNode = nodeIsMutable ? node : cloneNode(node, /*location*/ node, node.flags, /*parent*/ undefined, /*original*/ node);
|
||||
function mergeLexicalEnvironment(node: Node, declarations: Statement[]): Node {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.SourceFile:
|
||||
mergeSourceFileLexicalEnvironment(<SourceFile>mutableNode, declarations);
|
||||
break;
|
||||
return mergeSourceFileLexicalEnvironment(<SourceFile>node, declarations);
|
||||
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
mergeModuleDeclarationLexicalEnvironment(<ModuleDeclaration>mutableNode, declarations);
|
||||
break;
|
||||
return mergeModuleDeclarationLexicalEnvironment(<ModuleDeclaration>node, declarations);
|
||||
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.ArrowFunction:
|
||||
case SyntaxKind.MethodDeclaration:
|
||||
case SyntaxKind.GetAccessor:
|
||||
case SyntaxKind.SetAccessor:
|
||||
case SyntaxKind.Constructor:
|
||||
mergeFunctionLikeLexicalEnvironment(<FunctionLikeDeclaration>mutableNode, declarations);
|
||||
break;
|
||||
|
||||
case SyntaxKind.ModuleBlock:
|
||||
case SyntaxKind.Block:
|
||||
mergeBlockLexicalEnvironment(<Block>mutableNode, declarations);
|
||||
break;
|
||||
case SyntaxKind.ArrowFunction:
|
||||
return mergeFunctionLikeLexicalEnvironment(<FunctionLikeDeclaration>node, declarations);
|
||||
}
|
||||
|
||||
return mutableNode;
|
||||
Debug.fail("Node is not a valid lexical environment.");
|
||||
}
|
||||
|
||||
/**
|
||||
* 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[]) {
|
||||
node.statements = mergeStatements(node.statements, declarations);
|
||||
export function mergeSourceFileLexicalEnvironment(node: SourceFile, declarations: Statement[]) {
|
||||
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.
|
||||
*
|
||||
* @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);
|
||||
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.
|
||||
*
|
||||
* @param node The function-like node.
|
||||
* @param declarations The generated lexical declarations.
|
||||
*/
|
||||
function mergeFunctionLikeLexicalEnvironment(node: FunctionLikeDeclaration, declarations: Statement[]) {
|
||||
Debug.assert(node.body !== undefined);
|
||||
if (node.body.kind === SyntaxKind.Block) {
|
||||
node.body = <Block>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 = mergeConciseBodyLexicalEnvironment(mutableNode.body, declarations);
|
||||
return mutableNode;
|
||||
}
|
||||
else {
|
||||
node.body = createBlock([
|
||||
createReturn(<Expression>node.body),
|
||||
...declarations
|
||||
]);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @param node The block into which to merge lexical declarations.
|
||||
* @param declarations The lexical declarations to merge.
|
||||
*/
|
||||
function mergeBlockLexicalEnvironment(node: FunctionBody | ModuleBlock, declarations: Statement[]) {
|
||||
node.statements = mergeStatements(node.statements, declarations);
|
||||
function mergeBlockLexicalEnvironment<T extends Block>(node: T, declarations: Statement[]) {
|
||||
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.
|
||||
*
|
||||
* @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[]) {
|
||||
return createNodeArray(statements.concat(declarations), statements.pos, statements.end);
|
||||
return createNodeArray(concatenate(statements, declarations), /*location*/ statements);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in a new issue