diff --git a/src/compiler/comments.ts b/src/compiler/comments.ts index a7c7c34ab40..8ee7878d1e6 100644 --- a/src/compiler/comments.ts +++ b/src/compiler/comments.ts @@ -296,7 +296,7 @@ namespace ts { }, emitTrailingComments(range: TextRange, comments: CommentRange[]): void { const commentStart = performance.mark(); - emitLeadingComments(range, comments); + emitTrailingComments(range, comments); performance.measure("commentTime", commentStart); }, emitLeadingDetachedComments(range: TextRange, contextNode?: Node, ignoreNodeCallback?: (contextNode: Node) => boolean): void { @@ -324,8 +324,8 @@ namespace ts { function setSourceFile(sourceFile: SourceFile) { currentSourceFile = sourceFile; - currentText = sourceFile.text; - currentLineMap = getLineStarts(sourceFile); + currentText = currentSourceFile.text; + currentLineMap = getLineStarts(currentSourceFile); detachedCommentsInfo = undefined; consumedCommentRanges = {}; leadingCommentRangePositions = {}; diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index d04d7f0fd0d..8427b1af0af 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -3,8 +3,6 @@ /* @internal */ namespace ts { - const synthesizedLocation: TextRange = { pos: -1, end: -1 }; - let NodeConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; let SourceFileConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; @@ -22,6 +20,20 @@ namespace ts { return node; } + function updateNode(updated: T, original: T): T { + updated.original = original; + if (original.transformId) { + updated.transformId = original.transformId; + updated.emitFlags = original.emitFlags; + updated.commentRange = original.commentRange; + updated.sourceMapRange = original.sourceMapRange; + } + if (original.startsOnNewLine) { + updated.startsOnNewLine = true; + } + return updated; + } + export function createNodeArray(elements?: T[], location?: TextRange, hasTrailingComma?: boolean): NodeArray { if (elements) { if (isNodeArray(elements)) { @@ -137,7 +149,8 @@ namespace ts { name.text = ""; name.originalKeywordKind = SyntaxKind.Unknown; name.autoGenerateKind = GeneratedIdentifierKind.Auto; - name.autoGenerateId = nextAutoGenerateId++; + name.autoGenerateId = nextAutoGenerateId; + nextAutoGenerateId++; if (recordTempVariable) { recordTempVariable(name); } @@ -149,7 +162,8 @@ namespace ts { name.text = ""; name.originalKeywordKind = SyntaxKind.Unknown; name.autoGenerateKind = GeneratedIdentifierKind.Loop; - name.autoGenerateId = nextAutoGenerateId++; + name.autoGenerateId = nextAutoGenerateId; + nextAutoGenerateId++; return name; } @@ -158,7 +172,8 @@ namespace ts { name.text = text; name.originalKeywordKind = SyntaxKind.Unknown; name.autoGenerateKind = GeneratedIdentifierKind.Unique; - name.autoGenerateId = nextAutoGenerateId++; + name.autoGenerateId = nextAutoGenerateId; + nextAutoGenerateId++; return name; } @@ -168,7 +183,8 @@ namespace ts { name.text = ""; name.originalKeywordKind = SyntaxKind.Unknown; name.autoGenerateKind = GeneratedIdentifierKind.Node; - name.autoGenerateId = nextAutoGenerateId++; + name.autoGenerateId = nextAutoGenerateId; + nextAutoGenerateId++; return name; } @@ -199,22 +215,30 @@ namespace ts { // Type members - export function createMethod(modifiers: Modifier[], asteriskToken: Node, name: string | PropertyName, parameters: ParameterDeclaration[], body: Block, location?: TextRange) { - const node = createNode(SyntaxKind.MethodDeclaration, location); - node.decorators = undefined; + export function createMethod(decorators: Decorator[], modifiers: Modifier[], asteriskToken: Node, name: string | PropertyName, typeParameters: TypeParameterDeclaration[], parameters: ParameterDeclaration[], type: TypeNode, body: Block, location?: TextRange, flags?: NodeFlags) { + const node = createNode(SyntaxKind.MethodDeclaration, location, flags); + node.decorators = decorators ? createNodeArray(decorators) : undefined; node.modifiers = modifiers ? createNodeArray(modifiers) : undefined; node.asteriskToken = asteriskToken; node.name = typeof name === "string" ? createIdentifier(name) : name; - node.typeParameters = undefined; + node.typeParameters = typeParameters ? createNodeArray(typeParameters) : undefined; node.parameters = createNodeArray(parameters); + node.type = type; node.body = body; return node; } - export function createConstructor(parameters: ParameterDeclaration[], body: Block, location?: TextRange) { - const node = createNode(SyntaxKind.Constructor, location); - node.decorators = undefined; - node.modifiers = undefined; + export function updateMethod(node: MethodDeclaration, decorators: Decorator[], modifiers: Modifier[], asteriskToken: Node, name: PropertyName, typeParameters: TypeParameterDeclaration[], parameters: ParameterDeclaration[], type: TypeNode, body: Block) { + if (node.decorators !== decorators || node.modifiers !== modifiers || node.asteriskToken !== asteriskToken || node.name !== name || node.typeParameters !== typeParameters || node.parameters !== parameters || node.type !== type || node.body !== body) { + return updateNode(createMethod(decorators, modifiers, asteriskToken, name, typeParameters, parameters, type, body, /*location*/ node, node.flags), node); + } + return node; + } + + export function createConstructor(decorators: Decorator[], modifiers: Modifier[], parameters: ParameterDeclaration[], body: Block, location?: TextRange, flags?: NodeFlags) { + const node = createNode(SyntaxKind.Constructor, location, flags); + node.decorators = decorators ? createNodeArray(decorators) : undefined; + node.modifiers = modifiers ? createNodeArray(modifiers) : undefined; node.typeParameters = undefined; node.parameters = createNodeArray(parameters); node.type = undefined; @@ -222,9 +246,35 @@ namespace ts { return node; } - export function createGetAccessor(modifiers: Modifier[], name: string | PropertyName, parameters: ParameterDeclaration[], body: Block, location?: TextRange) { - const node = createNode(SyntaxKind.GetAccessor, location); - node.decorators = undefined; + export function updateConstructor(node: ConstructorDeclaration, decorators: Decorator[], modifiers: Modifier[], parameters: ParameterDeclaration[], body: Block) { + if (node.decorators !== decorators || node.modifiers !== modifiers || node.parameters !== parameters || node.body !== body) { + return updateNode(createConstructor(decorators, modifiers, parameters, body, /*location*/ node, node.flags), node); + } + return node; + } + + export function createGetAccessor(decorators: Decorator[], modifiers: Modifier[], name: string | PropertyName, parameters: ParameterDeclaration[], type: TypeNode, body: Block, location?: TextRange, flags?: NodeFlags) { + const node = createNode(SyntaxKind.GetAccessor, location, flags); + node.decorators = decorators ? createNodeArray(decorators) : undefined; + node.modifiers = modifiers ? createNodeArray(modifiers) : undefined; + node.name = typeof name === "string" ? createIdentifier(name) : name; + node.typeParameters = undefined; + node.parameters = createNodeArray(parameters); + node.type = type; + node.body = body; + return node; + } + + export function updateGetAccessor(node: GetAccessorDeclaration, decorators: Decorator[], modifiers: Modifier[], name: PropertyName, parameters: ParameterDeclaration[], type: TypeNode, body: Block) { + if (node.decorators !== decorators || node.modifiers !== modifiers || node.name !== name || node.parameters !== parameters || node.type !== type || node.body !== body) { + return updateNode(createGetAccessor(decorators, modifiers, name, parameters, type, body, /*location*/ node, node.flags), node); + } + return node; + } + + export function createSetAccessor(decorators: Decorator[], modifiers: Modifier[], name: string | PropertyName, parameters: ParameterDeclaration[], body: Block, location?: TextRange, flags?: NodeFlags) { + const node = createNode(SyntaxKind.SetAccessor, location, flags); + node.decorators = decorators ? createNodeArray(decorators) : undefined; node.modifiers = modifiers ? createNodeArray(modifiers) : undefined; node.name = typeof name === "string" ? createIdentifier(name) : name; node.typeParameters = undefined; @@ -233,33 +283,46 @@ namespace ts { return node; } - export function createSetAccessor(modifiers: Modifier[], name: string | PropertyName, parameters: ParameterDeclaration[], body: Block, location?: TextRange) { - const node = createNode(SyntaxKind.SetAccessor, location); - node.decorators = undefined; - node.modifiers = modifiers ? createNodeArray(modifiers) : undefined; - node.name = typeof name === "string" ? createIdentifier(name) : name; - node.typeParameters = undefined; - node.parameters = createNodeArray(parameters); - node.body = body; + export function updateSetAccessor(node: SetAccessorDeclaration, decorators: Decorator[], modifiers: Modifier[], name: PropertyName, parameters: ParameterDeclaration[], body: Block) { + if (node.decorators !== decorators || node.modifiers !== modifiers || node.name !== name || node.parameters !== parameters || node.body !== body) { + return updateNode(createSetAccessor(decorators, modifiers, name, parameters, body, /*location*/ node, node.flags), node); + } return node; } export function createParameter(name: string | Identifier | BindingPattern, initializer?: Expression, location?: TextRange) { - return createParameterWithDotDotDotToken(/*dotDotDotToken*/ undefined, name, initializer, location); + return createParameterDeclaration( + /*decorators*/ undefined, + /*modifiers*/ undefined, + /*dotDotDotToken*/ undefined, + name, + /*questionToken*/ undefined, + /*type*/ undefined, + initializer, + location + ); } - export function createParameterWithDotDotDotToken(dotDotDotToken: Node, name: string | Identifier | BindingPattern, initializer?: Expression, location?: TextRange) { - const node = createNode(SyntaxKind.Parameter, location); - node.decorators = undefined; - node.modifiers = undefined; + export function createParameterDeclaration(decorators: Decorator[], modifiers: Modifier[], dotDotDotToken: Node, name: string | Identifier | BindingPattern, questionToken: Node, type: TypeNode, initializer: Expression, location?: TextRange, flags?: NodeFlags) { + const node = createNode(SyntaxKind.Parameter, location, flags); + node.decorators = decorators ? createNodeArray(decorators) : undefined; + node.modifiers = modifiers ? createNodeArray(modifiers) : undefined; node.dotDotDotToken = dotDotDotToken; node.name = typeof name === "string" ? createIdentifier(name) : name; - node.questionToken = undefined; - node.type = undefined; + node.questionToken = questionToken; + node.type = type; node.initializer = initializer ? parenthesizeExpressionForList(initializer) : undefined; return node; } + export function updateParameterDeclaration(node: ParameterDeclaration, decorators: Decorator[], modifiers: Modifier[], dotDotDotToken: Node, name: BindingName, questionToken: Node, type: TypeNode, initializer: Expression) { + if (node.decorators !== decorators || node.modifiers !== modifiers || node.dotDotDotToken !== dotDotDotToken || node.name !== name || node.questionToken !== questionToken || node.type !== type || node.initializer !== initializer) { + return updateNode(createParameterDeclaration(decorators, modifiers, dotDotDotToken, name, questionToken, type, initializer, /*location*/ node, /*flags*/ node.flags), node); + } + + return node; + } + // Expression export function createArrayLiteral(elements?: Expression[], location?: TextRange, multiLine?: boolean) { @@ -281,13 +344,24 @@ namespace ts { } export function createPropertyAccess(expression: Expression, name: string | Identifier, location?: TextRange) { - const node = createNode(SyntaxKind.PropertyAccessExpression, location, /*flags*/ undefined); + return createPropertyAccessWithDotToken(expression, createSynthesizedNode(SyntaxKind.DotToken), name, location, /*flags*/ undefined); + } + + export function createPropertyAccessWithDotToken(expression: Expression, dotToken: Node, name: string | Identifier, location?: TextRange, flags?: NodeFlags) { + const node = createNode(SyntaxKind.PropertyAccessExpression, location, flags); node.expression = parenthesizeForAccess(expression); - node.dotToken = createSynthesizedNode(SyntaxKind.DotToken); + node.dotToken = dotToken; node.name = typeof name === "string" ? createIdentifier(name) : name; return node; } + export function updatePropertyAccess(node: PropertyAccessExpression, expression: Expression, name: Identifier) { + if (node.expression !== expression || node.name !== name) { + return updateNode(createPropertyAccessWithDotToken(expression, node.dotToken, name, /*location*/ node, node.flags), node); + } + return node; + } + export function createElementAccess(expression: Expression, index: number | Expression, location?: TextRange) { const node = createNode(SyntaxKind.ElementAccessExpression, location); node.expression = parenthesizeForAccess(expression); @@ -295,19 +369,37 @@ namespace ts { return node; } - export function createCall(expression: Expression, argumentsArray: Expression[], location?: TextRange) { - const node = createNode(SyntaxKind.CallExpression, location); + export function createCall(expression: Expression, typeArguments: TypeNode[], argumentsArray: Expression[], location?: TextRange, flags?: NodeFlags) { + const node = createNode(SyntaxKind.CallExpression, location, flags); node.expression = parenthesizeForAccess(expression); + if (typeArguments) { + node.typeArguments = createNodeArray(typeArguments); + } + node.arguments = parenthesizeListElements(createNodeArray(argumentsArray)); return node; } - export function createNew(expression: Expression, argumentsArray: Expression[], location?: TextRange) { - const node = createNode(SyntaxKind.NewExpression, location); + export function updateCall(node: CallExpression, expression: Expression, typeArguments: TypeNode[], argumentsArray: Expression[]) { + if (expression !== node.expression || typeArguments !== node.typeArguments || argumentsArray !== node.arguments) { + return updateNode(createCall(expression, typeArguments, argumentsArray, /*location*/ node, node.flags), node); + } + + return node; + } + + export function createNew(expression: Expression, typeArguments: TypeNode[], argumentsArray: Expression[], location?: TextRange, flags?: NodeFlags) { + const node = createNode(SyntaxKind.NewExpression, location, flags); node.expression = parenthesizeForNew(expression); - node.arguments = argumentsArray - ? parenthesizeListElements(createNodeArray(argumentsArray)) - : undefined; + node.typeArguments = typeArguments ? createNodeArray(typeArguments) : undefined; + node.arguments = argumentsArray ? parenthesizeListElements(createNodeArray(argumentsArray)) : undefined; + return node; + } + + export function updateNew(node: NewExpression, expression: Expression, typeArguments: TypeNode[], argumentsArray: Expression[]) { + if (node.expression !== expression || node.typeArguments !== typeArguments || node.arguments !== argumentsArray) { + return updateNode(createNew(expression, typeArguments, argumentsArray, /*location*/ node, node.flags), node); + } return node; } @@ -317,33 +409,43 @@ namespace ts { return node; } - export function createFunctionExpression(asteriskToken: Node, name: string | Identifier, parameters: ParameterDeclaration[], body: Block, location?: TextRange, original?: Node) { - const node = createNode(SyntaxKind.FunctionExpression, location); + export function createFunctionExpression(asteriskToken: Node, name: string | Identifier, typeParameters: TypeParameterDeclaration[], parameters: ParameterDeclaration[], type: TypeNode, body: Block, location?: TextRange, flags?: NodeFlags) { + const node = createNode(SyntaxKind.FunctionExpression, location, flags); node.modifiers = undefined; node.asteriskToken = asteriskToken; node.name = typeof name === "string" ? createIdentifier(name) : name; - node.typeParameters = undefined; + node.typeParameters = typeParameters ? createNodeArray(typeParameters) : undefined; node.parameters = createNodeArray(parameters); - node.type = undefined; + node.type = type; node.body = body; - if (original) { - node.original = original; - } - return node; } - export function createArrowFunction(parameters: ParameterDeclaration[], body: Expression | Block, location?: TextRange) { - const node = createNode(SyntaxKind.ArrowFunction, location); - node.modifiers = undefined; - node.typeParameters = undefined; + export function updateFunctionExpression(node: FunctionExpression, name: Identifier, typeParameters: TypeParameterDeclaration[], parameters: ParameterDeclaration[], type: TypeNode, body: Block) { + if (node.name !== name || node.typeParameters !== typeParameters || node.parameters !== parameters || node.type !== type || node.body !== body) { + return updateNode(createFunctionExpression(node.asteriskToken, name, typeParameters, parameters, type, body, /*location*/ node, node.flags), node); + } + return node; + } + + export function createArrowFunction(modifiers: Modifier[], typeParameters: TypeParameterDeclaration[], parameters: ParameterDeclaration[], type: TypeNode, equalsGreaterThanToken: Node, body: ConciseBody, location?: TextRange, flags?: NodeFlags) { + const node = createNode(SyntaxKind.ArrowFunction, location, flags); + node.modifiers = modifiers ? createNodeArray(modifiers) : undefined; + node.typeParameters = typeParameters ? createNodeArray(typeParameters) : undefined; node.parameters = createNodeArray(parameters); - node.type = undefined; - node.equalsGreaterThanToken = createNode(SyntaxKind.EqualsGreaterThanToken); + node.type = type; + node.equalsGreaterThanToken = equalsGreaterThanToken || createNode(SyntaxKind.EqualsGreaterThanToken); node.body = parenthesizeConciseBody(body); return node; } + export function updateArrowFunction(node: ArrowFunction, modifiers: Modifier[], typeParameters: TypeParameterDeclaration[], parameters: ParameterDeclaration[], type: TypeNode, body: ConciseBody) { + if (node.modifiers !== modifiers || node.typeParameters !== typeParameters || node.parameters !== parameters || node.type !== type || node.body !== body) { + return updateNode(createArrowFunction(modifiers, typeParameters, parameters, type, node.equalsGreaterThanToken, body, /*location*/ node, node.flags), node); + } + return node; + } + export function createTypeOf(expression: Expression) { const node = createNode(SyntaxKind.TypeOfExpression); node.expression = parenthesizePrefixOperand(expression); @@ -371,10 +473,21 @@ namespace ts { } export function createBinary(left: Expression, operator: SyntaxKind, right: Expression, location?: TextRange) { + return createBinaryWithOperatorToken(left, createSynthesizedNode(operator), right, location); + } + + export function createBinaryWithOperatorToken(left: Expression, operatorToken: Node, right: Expression, location?: TextRange) { const node = createNode(SyntaxKind.BinaryExpression, location); - node.left = parenthesizeBinaryOperand(operator, left, /*isLeftSideOfBinary*/ true, /*leftOperand*/ undefined); - node.operatorToken = createSynthesizedNode(operator); - node.right = parenthesizeBinaryOperand(operator, right, /*isLeftSideOfBinary*/ false, node.left); + node.left = parenthesizeBinaryOperand(operatorToken.kind, left, /*isLeftSideOfBinary*/ true, /*leftOperand*/ undefined); + node.operatorToken = operatorToken; + node.right = parenthesizeBinaryOperand(operatorToken.kind, right, /*isLeftSideOfBinary*/ false, node.left); + return node; + } + + export function updateBinary(node: BinaryExpression, left: Expression, right: Expression) { + if (node.left !== left || node.right !== right) { + return updateNode(createBinaryWithOperatorToken(left, node.operatorToken, right, /*location*/ node), node); + } return node; } @@ -425,8 +538,8 @@ namespace ts { // Element - export function createBlock(statements: Statement[], location?: TextRange, multiLine?: boolean): Block { - const block = createNode(SyntaxKind.Block, location); + export function createBlock(statements: Statement[], location?: TextRange, multiLine?: boolean, flags?: NodeFlags): Block { + const block = createNode(SyntaxKind.Block, location, flags); block.statements = createNodeArray(statements); if (multiLine) { block.multiLine = true; @@ -434,20 +547,42 @@ namespace ts { return block; } - export function createVariableStatement(modifiers: Modifier[], declarationList: VariableDeclarationList | VariableDeclaration[], location?: TextRange): VariableStatement { - const node = createNode(SyntaxKind.VariableStatement, location); + export function updateBlock(node: Block, statements: Statement[]) { + if (statements !== node.statements) { + return updateNode(createBlock(statements, /*location*/ node, node.multiLine, node.flags), node); + } + + return node; + } + + export function createVariableStatement(modifiers: Modifier[], declarationList: VariableDeclarationList | VariableDeclaration[], location?: TextRange, flags?: NodeFlags): VariableStatement { + const node = createNode(SyntaxKind.VariableStatement, location, flags); node.decorators = undefined; node.modifiers = modifiers ? createNodeArray(modifiers) : undefined; node.declarationList = isArray(declarationList) ? createVariableDeclarationList(declarationList) : declarationList; return node; } + export function updateVariableStatement(node: VariableStatement, modifiers: Modifier[], declarationList: VariableDeclarationList): VariableStatement { + if (node.modifiers !== modifiers || node.declarationList !== declarationList) { + return updateNode(createVariableStatement(modifiers, declarationList, /*location*/ node, node.flags), node); + } + return node; + } + export function createVariableDeclarationList(declarations: VariableDeclaration[], location?: TextRange, flags?: NodeFlags): VariableDeclarationList { const node = createNode(SyntaxKind.VariableDeclarationList, location, flags); node.declarations = createNodeArray(declarations); return node; } + export function updateVariableDeclarationList(node: VariableDeclarationList, declarations: VariableDeclaration[]) { + if (node.declarations !== declarations) { + return updateNode(createVariableDeclarationList(declarations, /*location*/ node, node.flags), node); + } + return node; + } + export function createLetDeclarationList(declarations: VariableDeclaration[], location?: TextRange) { return createVariableDeclarationList(declarations, location, NodeFlags.Let); } @@ -456,32 +591,51 @@ namespace ts { return createVariableDeclarationList(declarations, location, NodeFlags.Const); } - export function createVariableDeclaration(name: string | BindingPattern | Identifier, initializer?: Expression, location?: TextRange): VariableDeclaration { - const node = createNode(SyntaxKind.VariableDeclaration, location); + export function createVariableDeclaration(name: string | BindingPattern | Identifier, type?: TypeNode, initializer?: Expression, location?: TextRange, flags?: NodeFlags): VariableDeclaration { + const node = createNode(SyntaxKind.VariableDeclaration, location, flags); node.name = typeof name === "string" ? createIdentifier(name) : name; + node.type = type; node.initializer = initializer !== undefined ? parenthesizeExpressionForList(initializer) : undefined; return node; } + export function updateVariableDeclaration(node: VariableDeclaration, name: BindingName, type: TypeNode, initializer: Expression) { + if (node.name !== name || node.type !== type || node.initializer !== initializer) { + return updateNode(createVariableDeclaration(name, type, initializer, /*location*/ node, node.flags), node); + } + return node; + } + export function createEmptyStatement(location: TextRange) { return createNode(SyntaxKind.EmptyStatement, location); } - export function createStatement(expression: Expression, location?: TextRange): ExpressionStatement { - const node = createNode(SyntaxKind.ExpressionStatement, location); + export function createStatement(expression: Expression, location?: TextRange, flags?: NodeFlags): ExpressionStatement { + const node = createNode(SyntaxKind.ExpressionStatement, location, flags); node.expression = parenthesizeExpressionForExpressionStatement(expression); return node; } - export function createIf(expression: Expression, thenStatement: Statement, elseStatement?: Statement, location?: TextRange, options?: { startOnNewLine?: boolean; }) { + export function updateStatement(node: ExpressionStatement, expression: Expression) { + if (node.expression !== expression) { + return updateNode(createStatement(expression, /*location*/ node, node.flags), node); + } + + return node; + } + + export function createIf(expression: Expression, thenStatement: Statement, elseStatement?: Statement, location?: TextRange) { const node = createNode(SyntaxKind.IfStatement, location); node.expression = expression; node.thenStatement = thenStatement; node.elseStatement = elseStatement; - if (options && options.startOnNewLine) { - node.startsOnNewLine = true; - } + return node; + } + export function updateIf(node: IfStatement, expression: Expression, thenStatement: Statement, elseStatement: Statement) { + if (node.expression !== expression || node.thenStatement !== thenStatement || node.elseStatement !== elseStatement) { + return updateNode(createIf(expression, thenStatement, elseStatement, /*location*/ node), node); + } return node; } @@ -550,18 +704,29 @@ namespace ts { return node; } - export function createFunctionDeclaration(modifiers: Modifier[], asteriskToken: Node, name: string | Identifier, parameters: ParameterDeclaration[], body: Block, location?: TextRange, original?: Node) { - const node = createNode(SyntaxKind.FunctionDeclaration, location); - node.decorators = undefined; + export function updateReturn(node: ReturnStatement, expression: Expression) { + if (node.expression !== expression) { + return updateNode(createReturn(expression, /*location*/ node), node); + } + return node; + } + + export function createFunctionDeclaration(decorators: Decorator[], modifiers: Modifier[], asteriskToken: Node, name: string | Identifier, typeParameters: TypeParameterDeclaration[], parameters: ParameterDeclaration[], type: TypeNode, body: Block, location?: TextRange, flags?: NodeFlags) { + const node = createNode(SyntaxKind.FunctionDeclaration, location, flags); + node.decorators = decorators ? createNodeArray(decorators) : undefined; node.modifiers = modifiers ? createNodeArray(modifiers) : undefined; node.asteriskToken = asteriskToken; node.name = typeof name === "string" ? createIdentifier(name) : name; - node.typeParameters = undefined; + node.typeParameters = typeParameters ? createNodeArray(typeParameters) : undefined; node.parameters = createNodeArray(parameters); - node.type = undefined; + node.type = type; node.body = body; - if (original) { - node.original = original; + return node; + } + + export function updateFunctionDeclaration(node: FunctionDeclaration, decorators: Decorator[], modifiers: Modifier[], name: Identifier, typeParameters: TypeParameterDeclaration[], parameters: ParameterDeclaration[], type: TypeNode, body: Block) { + if (node.decorators !== decorators || node.modifiers !== modifiers || node.name !== name || node.typeParameters !== typeParameters || node.parameters !== parameters || node.type !== type || node.body !== body) { + return updateNode(createFunctionDeclaration(decorators, modifiers, node.asteriskToken, name, typeParameters, parameters, type, body, /*location*/ node, node.flags), node); } return node; } @@ -630,6 +795,46 @@ namespace ts { return node; } + // Top-level nodes + + export function updateSourceFileNode(node: SourceFile, statements: Statement[]) { + if (node.statements !== statements) { + const updated = createNode(SyntaxKind.SourceFile, /*location*/ node, node.flags); + updated.statements = createNodeArray(statements); + updated.endOfFileToken = node.endOfFileToken; + updated.fileName = node.fileName; + updated.path = node.path; + updated.text = node.text; + updated.amdDependencies = node.amdDependencies; + updated.moduleName = node.moduleName; + updated.referencedFiles = node.referencedFiles; + updated.typeReferenceDirectives = node.typeReferenceDirectives; + updated.languageVariant = node.languageVariant; + updated.isDeclarationFile = node.isDeclarationFile; + updated.renamedDependencies = node.renamedDependencies; + updated.hasNoDefaultLib = node.hasNoDefaultLib; + updated.languageVersion = node.languageVersion; + updated.scriptKind = node.scriptKind; + updated.externalModuleIndicator = node.externalModuleIndicator; + updated.commonJsModuleIndicator = node.commonJsModuleIndicator; + updated.identifiers = node.identifiers; + updated.nodeCount = node.nodeCount; + updated.identifierCount = node.identifierCount; + updated.symbolCount = node.symbolCount; + updated.parseDiagnostics = node.parseDiagnostics; + updated.bindDiagnostics = node.bindDiagnostics; + updated.lineMap = node.lineMap; + updated.classifiableNames = node.classifiableNames; + updated.resolvedModules = node.resolvedModules; + updated.resolvedTypeReferenceDirectiveNames = node.resolvedTypeReferenceDirectiveNames; + updated.imports = node.imports; + updated.moduleAugmentations = node.moduleAugmentations; + return updateNode(updated, node); + } + + return node; + } + // Transformation nodes /** @@ -744,13 +949,21 @@ namespace ts { } export function createRestParameter(name: string | Identifier) { - const node = createParameterWithDotDotDotToken(createSynthesizedNode(SyntaxKind.DotDotDotToken), name, /*initializer*/ undefined); - return node; + return createParameterDeclaration( + /*decorators*/ undefined, + /*modifiers*/ undefined, + createSynthesizedNode(SyntaxKind.DotDotDotToken), + name, + /*questionToken*/ undefined, + /*type*/ undefined, + /*initializer*/ undefined + ); } export function createFunctionCall(func: Expression, thisArg: Expression, argumentsList: Expression[], location?: TextRange) { return createCall( createPropertyAccess(func, "call"), + /*typeArguments*/ undefined, [ thisArg, ...argumentsList @@ -778,6 +991,7 @@ namespace ts { export function createFunctionApply(func: Expression, thisArg: Expression, argumentsExpression: Expression, location?: TextRange) { return createCall( createPropertyAccess(func, "apply"), + /*typeArguments*/ undefined, [ thisArg, argumentsExpression @@ -792,12 +1006,13 @@ namespace ts { argumentsList.push(typeof start === "number" ? createLiteral(start) : start); } - return createCall(createPropertyAccess(array, "slice"), argumentsList); + return createCall(createPropertyAccess(array, "slice"), /*typeArguments*/ undefined, argumentsList); } export function createArrayConcat(array: Expression, values: Expression[]) { return createCall( createPropertyAccess(array, "concat"), + /*typeArguments*/ undefined, values ); } @@ -805,6 +1020,7 @@ namespace ts { export function createMathPow(left: Expression, right: Expression, location?: TextRange) { return createCall( createPropertyAccess(createIdentifier("Math"), "pow"), + /*typeArguments*/ undefined, [left, right], location ); @@ -839,6 +1055,7 @@ namespace ts { createReactNamespace(reactNamespace, parentElement), "createElement" ), + /*typeArguments*/ undefined, argumentsList, location ); @@ -849,6 +1066,7 @@ namespace ts { export function createExtendsHelper(name: Identifier) { return createCall( createIdentifier("__extends"), + /*typeArguments*/ undefined, [ name, createIdentifier("_super") @@ -859,6 +1077,7 @@ namespace ts { export function createAssignHelper(attributesSegments: Expression[]) { return createCall( createIdentifier("__assign"), + /*typeArguments*/ undefined, attributesSegments ); } @@ -866,6 +1085,7 @@ namespace ts { export function createParamHelper(expression: Expression, parameterOffset: number, location?: TextRange) { return createCall( createIdentifier("__param"), + /*typeArguments*/ undefined, [ createLiteral(parameterOffset), expression @@ -877,6 +1097,7 @@ namespace ts { export function createMetadataHelper(metadataKey: string, metadataValue: Expression) { return createCall( createIdentifier("__metadata"), + /*typeArguments*/ undefined, [ createLiteral(metadataKey), metadataValue @@ -895,12 +1116,13 @@ namespace ts { } } - return createCall(createIdentifier("__decorate"), argumentsArray, location); + return createCall(createIdentifier("__decorate"), /*typeArguments*/ undefined, argumentsArray, location); } export function createAwaiterHelper(hasLexicalArguments: boolean, promiseConstructor: EntityName | Expression, body: Block) { return createCall( createIdentifier("__awaiter"), + /*typeArguments*/ undefined, [ createThis(), hasLexicalArguments ? createIdentifier("arguments") : createVoidZero(), @@ -908,7 +1130,9 @@ namespace ts { createFunctionExpression( createNode(SyntaxKind.AsteriskToken), /*name*/ undefined, - [], + /*typeParameters*/ undefined, + /*parameters*/ [], + /*type*/ undefined, body ) ] @@ -918,6 +1142,7 @@ namespace ts { export function createHasOwnProperty(target: LeftHandSideExpression, propertyName: Expression) { return createCall( createPropertyAccess(target, "hasOwnProperty"), + /*typeArguments*/ undefined, [propertyName] ); } @@ -925,6 +1150,7 @@ namespace ts { function createObjectCreate(prototype: Expression) { return createCall( createPropertyAccess(createIdentifier("Object"), "create"), + /*typeArguments*/ undefined, [prototype] ); } @@ -932,7 +1158,11 @@ namespace ts { function createGeti(target: LeftHandSideExpression) { // name => super[name] return createArrowFunction( + /*modifiers*/ undefined, + /*typeParameters*/ undefined, [createParameter("name")], + /*type*/ undefined, + /*equalsGreaterThanToken*/ undefined, createElementAccess( target, createIdentifier("name") @@ -943,10 +1173,14 @@ namespace ts { function createSeti(target: LeftHandSideExpression) { // (name, value) => super[name] = value return createArrowFunction( + /*modifiers*/ undefined, + /*typeParameters*/ undefined, [ createParameter("name"), createParameter("value") ], + /*type*/ undefined, + /*equalsGreaterThanToken*/ undefined, createAssignment( createElementAccess( target, @@ -969,6 +1203,7 @@ namespace ts { createConstDeclarationList([ createVariableDeclaration( "cache", + /*type*/ undefined, createObjectCreate(createNull()) ) ]) @@ -976,13 +1211,16 @@ namespace ts { // get value() { return geti(name); } const getter = createGetAccessor( + /*decorators*/ undefined, /*modifiers*/ undefined, "value", - [], + /*parameters*/ [], + /*type*/ undefined, createBlock([ createReturn( createCall( createIdentifier("geti"), + /*typeArguments*/ undefined, [createIdentifier("name")] ) ) @@ -991,6 +1229,7 @@ namespace ts { // set value(v) { seti(name, v); } const setter = createSetAccessor( + /*decorators*/ undefined, /*modifiers*/ undefined, "value", [createParameter("v")], @@ -998,6 +1237,7 @@ namespace ts { createStatement( createCall( createIdentifier("seti"), + /*typeArguments*/ undefined, [ createIdentifier("name"), createIdentifier("v") @@ -1010,7 +1250,11 @@ namespace ts { // return name => cache[name] || ... const getOrCreateAccessorsForName = createReturn( createArrowFunction( + /*modifiers*/ undefined, + /*typeParameters*/ undefined, [createParameter("name")], + /*type*/ undefined, + /*equalsGreaterThanToken*/ undefined, createLogicalOr( createElementAccess( createIdentifier("cache"), @@ -1041,21 +1285,25 @@ namespace ts { createConstDeclarationList([ createVariableDeclaration( "_super", + /*type*/ undefined, createCall( createParen( createFunctionExpression( /*asteriskToken*/ undefined, /*name*/ undefined, + /*typeParameters*/ undefined, [ createParameter("geti"), createParameter("seti") ], + /*type*/ undefined, createBlock([ createCache, getOrCreateAccessorsForName ]) ) ), + /*typeArguments*/ undefined, [ createGeti(createSuper()), createSeti(createSuper()) @@ -1072,6 +1320,7 @@ namespace ts { createConstDeclarationList([ createVariableDeclaration( "_super", + /*type*/ undefined, createGeti(createSuper()) ) ]) diff --git a/src/compiler/sourcemap.ts b/src/compiler/sourcemap.ts index de056196bd0..123b658cd90 100644 --- a/src/compiler/sourcemap.ts +++ b/src/compiler/sourcemap.ts @@ -508,10 +508,6 @@ namespace ts { return skipTrivia(currentSourceText, rangeHasDecorators ? (range as Node).decorators.end : range.pos); } - function getStartPos(range: TextRange) { - return skipTrivia(currentSourceText, range.pos); - } - /** * Emits a mapping for the start of a range. * @@ -701,7 +697,7 @@ namespace ts { */ function setSourceFile(sourceFile: SourceFile) { currentSourceFile = sourceFile; - currentSourceText = sourceFile.text; + currentSourceText = currentSourceFile.text; // Add the file to tsFilePaths // If sourceroot option: Use the relative path corresponding to the common directory path @@ -720,10 +716,10 @@ namespace ts { sourceMapData.sourceMapSources.push(source); // The one that can be used from program to get the actual source file - sourceMapData.inputSourceFileNames.push(sourceFile.fileName); + sourceMapData.inputSourceFileNames.push(currentSourceFile.fileName); if (compilerOptions.inlineSources) { - sourceMapData.sourceMapSourcesContent.push(sourceFile.text); + sourceMapData.sourceMapSourcesContent.push(currentSourceFile.text); } } } diff --git a/src/compiler/transformer.ts b/src/compiler/transformer.ts index a448893f345..6642c83007a 100644 --- a/src/compiler/transformer.ts +++ b/src/compiler/transformer.ts @@ -156,7 +156,9 @@ namespace ts { * @param transforms An array of Transformers. */ export function transformFiles(resolver: EmitResolver, host: EmitHost, sourceFiles: SourceFile[], transformers: Transformer[]) { - const transformId = nextTransformId++; + const transformId = nextTransformId; + nextTransformId++; + const tokenSourceMapRanges: Map = { }; const lexicalEnvironmentVariableDeclarationsStack: VariableDeclaration[][] = []; const lexicalEnvironmentFunctionDeclarationsStack: FunctionDeclaration[][] = []; diff --git a/src/compiler/transformers/destructuring.ts b/src/compiler/transformers/destructuring.ts index 53f314c7504..2d39b3a1c59 100644 --- a/src/compiler/transformers/destructuring.ts +++ b/src/compiler/transformers/destructuring.ts @@ -98,7 +98,7 @@ namespace ts { return declarations; function emitAssignment(name: Identifier, value: Expression, location: TextRange) { - const declaration = createVariableDeclaration(name, value, location); + const declaration = createVariableDeclaration(name, /*type*/ undefined, value, location); // NOTE: this completely disables source maps, but aligns with the behavior of // `emitAssignment` in the old emitter. @@ -134,7 +134,7 @@ namespace ts { return declarations; function emitAssignment(name: Identifier, value: Expression, location: TextRange, original: Node) { - const declaration = createVariableDeclaration(name, value, location); + const declaration = createVariableDeclaration(name, /*type*/ undefined, value, location); declaration.original = original; // NOTE: this completely disables source maps, but aligns with the behavior of diff --git a/src/compiler/transformers/es6.ts b/src/compiler/transformers/es6.ts index 1c412f98af7..9c814affd50 100644 --- a/src/compiler/transformers/es6.ts +++ b/src/compiler/transformers/es6.ts @@ -554,6 +554,7 @@ namespace ts { createVariableDeclarationList([ createVariableDeclaration( getDeclarationName(node, /*allowComments*/ true), + /*type*/ undefined, transformClassLikeDeclarationToExpression(node) ) ]), @@ -621,7 +622,9 @@ namespace ts { const classFunction = createFunctionExpression( /*asteriskToken*/ undefined, /*name*/ undefined, + /*typeParameters*/ undefined, extendsClauseElement ? [createParameter("_super")] : [], + /*type*/ undefined, transformClassBody(node, extendsClauseElement) ); @@ -645,6 +648,7 @@ namespace ts { return createParen( createCall( outer, + /*typeArguments*/ undefined, extendsClauseElement ? [visitNode(extendsClauseElement.expression, visitor, isExpression)] : [] @@ -717,10 +721,13 @@ namespace ts { const hasSynthesizedSuper = hasSynthesizedDefaultSuperCall(constructor, extendsClauseElement !== undefined); statements.push( createFunctionDeclaration( + /*decorators*/ undefined, /*modifiers*/ undefined, /*asteriskToken*/ undefined, getDeclarationName(node), + /*typeParameters*/ undefined, transformConstructorParameters(constructor, hasSynthesizedSuper), + /*type*/ undefined, transformConstructorBody(constructor, node, extendsClauseElement, hasSynthesizedSuper), /*location*/ constructor || node ) @@ -967,10 +974,9 @@ namespace ts { NodeEmitFlags.SingleLine | NodeEmitFlags.NoTrailingSourceMap | NodeEmitFlags.NoTokenSourceMaps ), /*elseStatement*/ undefined, - /*location*/ parameter, - { startOnNewLine: true } + /*location*/ parameter ); - + statement.startsOnNewLine = true; setNodeEmitFlags(statement, NodeEmitFlags.NoTokenSourceMaps | NodeEmitFlags.NoTrailingSourceMap); statements.push(statement); } @@ -1018,6 +1024,7 @@ namespace ts { createVariableDeclarationList([ createVariableDeclaration( declarationName, + /*type*/ undefined, createArrayLiteral([]) ) ]), @@ -1030,7 +1037,7 @@ namespace ts { // } const forStatement = createFor( createVariableDeclarationList([ - createVariableDeclaration(temp, createLiteral(restIndex)) + createVariableDeclaration(temp, /*type*/ undefined, createLiteral(restIndex)) ], /*location*/ parameter), createLessThan( temp, @@ -1073,6 +1080,7 @@ namespace ts { createVariableDeclarationList([ createVariableDeclaration( "_this", + /*type*/ undefined, createThis() ) ]) @@ -1228,6 +1236,7 @@ namespace ts { return createCall( createPropertyAccess(createIdentifier("Object"), "defineProperty"), + /*typeArguments*/ undefined, [ target, propertyName, @@ -1271,15 +1280,19 @@ namespace ts { * @param node a FunctionDeclaration node. */ function visitFunctionDeclaration(node: FunctionDeclaration): FunctionDeclaration { - return createFunctionDeclaration( - /*modifiers*/ undefined, - node.asteriskToken, - node.name, - visitNodes(node.parameters, visitor, isParameter), - transformFunctionBody(node), - /*location*/ node, - /*original*/ node - ); + return setOriginalNode( + createFunctionDeclaration( + /*decorators*/ undefined, + /*modifiers*/ undefined, + node.asteriskToken, + node.name, + /*typeParameters*/ undefined, + visitNodes(node.parameters, visitor, isParameter), + /*type*/ undefined, + transformFunctionBody(node), + /*location*/ node + ), + /*original*/ node); } /** @@ -1295,12 +1308,16 @@ namespace ts { containingNonArrowFunction = node; } - const expression = createFunctionExpression( - node.asteriskToken, - name, - visitNodes(node.parameters, visitor, isParameter), - saveStateAndInvoke(node, transformFunctionBody), - location, + const expression = setOriginalNode( + createFunctionExpression( + node.asteriskToken, + name, + /*typeParameters*/ undefined, + visitNodes(node.parameters, visitor, isParameter), + /*type*/ undefined, + saveStateAndInvoke(node, transformFunctionBody), + location + ), /*original*/ node ); @@ -1755,6 +1772,7 @@ namespace ts { createVariableDeclarationList([ createVariableDeclaration( firstOriginalDeclaration ? firstOriginalDeclaration.name : createTempVariable(/*recordTempVariable*/ undefined), + /*type*/ undefined, createElementAccess(rhsReference, counter) ) ], /*location*/ moveRangePos(initializer, -1)), @@ -1818,8 +1836,8 @@ namespace ts { const forStatement = createFor( createVariableDeclarationList([ - createVariableDeclaration(counter, createLiteral(0), /*location*/ moveRangePos(node.expression, -1)), - createVariableDeclaration(rhsReference, expression, /*location*/ node.expression) + createVariableDeclaration(counter, /*type*/ undefined, createLiteral(0), /*location*/ moveRangePos(node.expression, -1)), + createVariableDeclaration(rhsReference, /*type*/ undefined, expression, /*location*/ node.expression) ], /*location*/ node.expression), createLessThan( counter, @@ -1996,11 +2014,14 @@ namespace ts { [ createVariableDeclaration( functionName, + /*type*/ undefined, setNodeEmitFlags( createFunctionExpression( /*asteriskToken*/ undefined, /*name*/ undefined, + /*typeParameters*/ undefined, loopParameters, + /*type*/ undefined, loopBody ), currentState.containsLexicalThis @@ -2027,6 +2048,7 @@ namespace ts { (extraVariableDeclarations || (extraVariableDeclarations = [])).push( createVariableDeclaration( currentState.argumentsName, + /*type*/ undefined, createIdentifier("arguments") ) ); @@ -2047,8 +2069,9 @@ namespace ts { (extraVariableDeclarations || (extraVariableDeclarations = [])).push( createVariableDeclaration( currentState.thisName, + /*type*/ undefined, createIdentifier("this") - ) + ) ); } } @@ -2140,7 +2163,7 @@ namespace ts { !state.labeledNonLocalBreaks && !state.labeledNonLocalContinues; - const call = createCall(loopFunctionExpressionName, map(parameters, p => p.name)); + const call = createCall(loopFunctionExpressionName, /*typeArguments*/ undefined, map(parameters, p => p.name)); if (isSimpleLoop) { statements.push(createStatement(call)); copyOutParameters(state.loopOutParameters, CopyDirection.ToOriginal, statements); @@ -2150,7 +2173,7 @@ namespace ts { const stateVariable = createVariableStatement( /*modifiers*/ undefined, createVariableDeclarationList( - [createVariableDeclaration(loopResultName, call)] + [createVariableDeclaration(loopResultName, /*type*/ undefined, call)] ) ); statements.push(stateVariable); @@ -2474,6 +2497,7 @@ namespace ts { thisArg, transformAndSpreadElements(createNodeArray([createVoidZero(), ...node.arguments]), /*needsUniqueCopy*/ false, /*multiLine*/ false, /*hasTrailingComma*/ false) ), + /*typeArguments*/ undefined, [] ); } @@ -2586,7 +2610,7 @@ namespace ts { inlineExpressions([ createAssignment(temp, createArrayLiteral(cookedStrings)), createAssignment(createPropertyAccess(temp, "raw"), createArrayLiteral(rawStrings)), - createCall(tag, templateArguments) + createCall(tag, /*typeArguments*/ undefined, templateArguments) ]) ); } @@ -2894,20 +2918,6 @@ namespace ts { return getDeclarationName(node, allowComments, allowSourceMaps, NodeEmitFlags.LocalName); } - /** - * Gets the export name for a declaration for use in expressions. - * - * An export name will *always* be prefixed with an module or namespace export modifier - * like "exports." if one is required. - * - * @param node The declaration. - * @param allowComments A value indicating whether comments may be emitted for the name. - * @param allowSourceMaps A value indicating whether source maps may be emitted for the name. - */ - function getExportName(node: ClassDeclaration | ClassExpression | FunctionDeclaration, allowComments?: boolean, allowSourceMaps?: boolean) { - return getDeclarationName(node, allowComments, allowSourceMaps, NodeEmitFlags.ExportName); - } - /** * Gets the name of a declaration, without source map or comments. * diff --git a/src/compiler/transformers/module/es6.ts b/src/compiler/transformers/module/es6.ts index 742f208d61c..5bf8a972aff 100644 --- a/src/compiler/transformers/module/es6.ts +++ b/src/compiler/transformers/module/es6.ts @@ -50,7 +50,7 @@ namespace ts { return undefined; // do not emit export equals for ES6 } const original = getOriginalNode(node); - return nodeIsSynthesized(original) || resolver.isValueAliasDeclaration(original) ? node: undefined; + return nodeIsSynthesized(original) || resolver.isValueAliasDeclaration(original) ? node : undefined; } function visitExportDeclaration(node: ExportDeclaration): ExportDeclaration { @@ -64,7 +64,7 @@ namespace ts { if (node.exportClause === newExportClause) { return node; } - return newExportClause + return newExportClause ? createExportDeclaration(newExportClause, node.moduleSpecifier) : undefined; } @@ -106,12 +106,12 @@ namespace ts { const newNamedBindings = visitNode(node.namedBindings, visitor, isNamedImportBindings, /*optional*/ true); return newDefaultImport !== node.name || newNamedBindings !== node.namedBindings ? createImportClause(newDefaultImport, newNamedBindings) - : node; + : node; } function visitNamedBindings(node: NamedImportBindings): VisitResult { if (node.kind === SyntaxKind.NamespaceImport) { - return resolver.isReferencedAliasDeclaration(node) ? node: undefined; + return resolver.isReferencedAliasDeclaration(node) ? node : undefined; } else { const newNamedImportElements = visitNodes((node).elements, visitor, isImportSpecifier); diff --git a/src/compiler/transformers/module/module.ts b/src/compiler/transformers/module/module.ts index c413a73113a..625e90ea02e 100644 --- a/src/compiler/transformers/module/module.ts +++ b/src/compiler/transformers/module/module.ts @@ -147,6 +147,7 @@ namespace ts { createStatement( createCall( define, + /*typeArguments*/ undefined, [ // Add the module name (if provided). ...(moduleName ? [moduleName] : []), @@ -167,11 +168,13 @@ namespace ts { createFunctionExpression( /*asteriskToken*/ undefined, /*name*/ undefined, + /*typeParameters*/ undefined, [ createParameter("require"), createParameter("exports"), ...importAliasNames ], + /*type*/ undefined, transformAsynchronousModuleBody(node) ) ] @@ -307,6 +310,7 @@ namespace ts { variables.push( createVariableDeclaration( getSynthesizedClone(namespaceDeclaration.name), + /*type*/ undefined, createRequireCall(node) ) ); @@ -319,6 +323,7 @@ namespace ts { variables.push( createVariableDeclaration( getGeneratedNameForNode(node), + /*type*/ undefined, createRequireCall(node) ) ); @@ -327,6 +332,7 @@ namespace ts { variables.push( createVariableDeclaration( getSynthesizedClone(namespaceDeclaration.name), + /*type*/ undefined, getGeneratedNameForNode(node) ) ); @@ -350,6 +356,7 @@ namespace ts { createVariableDeclarationList([ createVariableDeclaration( getSynthesizedClone(namespaceDeclaration.name), + /*type*/ undefined, getGeneratedNameForNode(node), /*location*/ node ) @@ -390,6 +397,7 @@ namespace ts { createVariableDeclarationList([ createVariableDeclaration( getSynthesizedClone(node.name), + /*type*/ undefined, createRequireCall(node) ) ], @@ -431,6 +439,7 @@ namespace ts { createVariableDeclarationList([ createVariableDeclaration( generatedName, + /*type*/ undefined, createRequireCall(node) ) ]), @@ -460,6 +469,7 @@ namespace ts { return createStatement( createCall( createIdentifier("__export"), + /*typeArguments*/ undefined, [ moduleKind !== ModuleKind.AMD ? createRequireCall(node) @@ -517,6 +527,7 @@ namespace ts { createStatement( createCall( createPropertyAccess(createIdentifier("Object"), "defineProperty"), + /*typeArguments*/ undefined, [ createIdentifier("exports"), createLiteral("__esModule"), @@ -608,7 +619,7 @@ namespace ts { if (hasModifier(node, ModifierFlags.Export)) { const variables = getInitializedVariables(node.declarationList); if (variables.length > 0) { - let inlineAssignments = createStatement( + const inlineAssignments = createStatement( inlineExpressions( map(variables, transformInitializedVariable) ), @@ -637,7 +648,7 @@ namespace ts { function addExportMemberAssignmentsForBindingName(resultStatements: Statement[], name: BindingName): void { if (isBindingPattern(name)) { for (const element of name.elements) { - addExportMemberAssignmentsForBindingName(resultStatements, element.name) + addExportMemberAssignmentsForBindingName(resultStatements, element.name); } } else { @@ -671,10 +682,13 @@ namespace ts { statements.push( setOriginalNode( createFunctionDeclaration( + /*decorators*/ undefined, /*modifiers*/ undefined, /*asteriskToken*/ undefined, name, + /*typeParameters*/ undefined, node.parameters, + /*type*/ undefined, node.body, /*location*/ node ), @@ -772,6 +786,7 @@ namespace ts { /*modifiers*/ undefined, [createVariableDeclaration( getDeclarationName(node), + /*type*/ undefined, createPropertyAccess(createIdentifier("exports"), getDeclarationName(node)) )], /*location*/ node @@ -907,7 +922,7 @@ namespace ts { args.push(moduleName); } - return createCall(createIdentifier("require"), args); + return createCall(createIdentifier("require"), /*typeArguments*/ undefined, args); } function createExportStatement(name: Identifier, value: Expression, location?: TextRange) { diff --git a/src/compiler/transformers/module/system.ts b/src/compiler/transformers/module/system.ts index 6c1169713c7..1f601ae4b55 100644 --- a/src/compiler/transformers/module/system.ts +++ b/src/compiler/transformers/module/system.ts @@ -12,10 +12,6 @@ namespace ts { const { getNodeEmitFlags, setNodeEmitFlags, - getCommentRange, - setCommentRange, - getSourceMapRange, - setSourceMapRange, startLexicalEnvironment, endLexicalEnvironment, hoistVariableDeclaration, @@ -114,10 +110,12 @@ namespace ts { const body = createFunctionExpression( /*asteriskToken*/ undefined, /*name*/ undefined, + /*typeParameters*/ undefined, [ createParameter(exportFunctionForFile), createParameter(contextObjectForFile) ], + /*type*/ undefined, setNodeEmitFlags( createBlock(statements, /*location*/ undefined, /*multiLine*/ true), NodeEmitFlags.EmitEmitHelpers @@ -131,6 +129,7 @@ namespace ts { createStatement( createCall( createPropertyAccess(createIdentifier("System"), "register"), + /*typeArguments*/ undefined, moduleName ? [moduleName, dependencies, body] : [dependencies, body] @@ -204,6 +203,7 @@ namespace ts { createVariableDeclarationList([ createVariableDeclaration( "__moduleName", + /*type*/ undefined, createLogicalAnd( contextObjectForFile, createPropertyAccess(contextObjectForFile, "id") @@ -244,7 +244,9 @@ namespace ts { createFunctionExpression( /*asteriskToken*/ undefined, /*name*/ undefined, - [], + /*typeParameters*/ undefined, + /*parameters*/ [], + /*type*/ undefined, createBlock( executeStatements, /*location*/ undefined, @@ -328,6 +330,7 @@ namespace ts { createVariableDeclarationList([ createVariableDeclaration( exportedNamesStorageRef, + /*type*/ undefined, createObjectLiteral(exportedNames, /*location*/ undefined, /*multiline*/ true) ) ]) @@ -397,6 +400,7 @@ namespace ts { createStatement( createCall( exportFunctionForFile, + /*typeArguments*/ undefined, [createObjectLiteral(properties, /*location*/ undefined, /*multiline*/ true)] ) ) @@ -412,6 +416,7 @@ namespace ts { createStatement( createCall( exportStarFunction, + /*typeArguments*/ undefined, [parameterName] ) ) @@ -425,7 +430,9 @@ namespace ts { createFunctionExpression( /*asteriskToken*/ undefined, /*name*/ undefined, + /*typeParameters*/ undefined, [createParameter(parameterName)], + /*type*/ undefined, createBlock(statements, /*location*/ undefined, /*multiLine*/ true) ) ); @@ -651,10 +658,13 @@ namespace ts { // If the function is exported, ensure it has a name and rewrite the function without any export flags. const name = node.name || getGeneratedNameForNode(node); const newNode = createFunctionDeclaration( + /*decorators*/ undefined, /*modifiers*/ undefined, node.asteriskToken, name, + /*typeParameters*/ undefined, node.parameters, + /*type*/ undefined, node.body, /*location*/ node); @@ -1199,23 +1209,27 @@ namespace ts { addNode(statements, createFunctionDeclaration( + /*decorators*/ undefined, /*modifiers*/ undefined, /*asteriskToken*/ undefined, exportStarFunction, + /*typeParameters*/ undefined, [createParameter(m)], + /*type*/ undefined, createBlock([ createVariableStatement( /*modifiers*/ undefined, createVariableDeclarationList([ createVariableDeclaration( exports, + /*type*/ undefined, createObjectLiteral([]) ) ]) ), createForIn( createVariableDeclarationList([ - createVariableDeclaration(n) + createVariableDeclaration(n, /*type*/ undefined) ]), m, createBlock([ @@ -1236,6 +1250,7 @@ namespace ts { createStatement( createCall( exportFunctionForFile, + /*typeArguments*/ undefined, [exports] ) ) @@ -1255,7 +1270,7 @@ namespace ts { */ function createExportExpression(name: Identifier | StringLiteral, value: Expression) { const exportName = isIdentifier(name) ? createLiteral(name.text) : name; - return createCall(exportFunctionForFile, [exportName, value]); + return createCall(exportFunctionForFile, /*typeArguments*/ undefined, [exportName, value]); } /** diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index ff253ba23d4..d51e5c20b86 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -675,6 +675,7 @@ namespace ts { createLetDeclarationList([ createVariableDeclaration( getDeclarationName(node, /*allowComments*/ true), + /*type*/ undefined, classExpression ) ]), @@ -769,6 +770,8 @@ namespace ts { return startOnNewLine( setOriginalNode( createConstructor( + /*decorators*/ undefined, + /*modifiers*/ undefined, parameters, body, /*location*/ constructor || node @@ -836,6 +839,7 @@ namespace ts { createStatement( createCall( createSuper(), + /*typeArguments*/ undefined, [createSpread(parameters[0].name)] ) ) @@ -1478,13 +1482,13 @@ namespace ts { if (compilerOptions.emitDecoratorMetadata) { let properties: ObjectLiteralElement[]; if (shouldAddTypeMetadata(node)) { - (properties || (properties = [])).push(createPropertyAssignment("type", createArrowFunction([], serializeTypeOfNode(node)))); + (properties || (properties = [])).push(createPropertyAssignment("type", createArrowFunction(/*modifiers*/ undefined, /*typeParameters*/ undefined, [], /*type*/ undefined, /*equalsGreaterThanToken*/ undefined, serializeTypeOfNode(node)))); } if (shouldAddParamTypesMetadata(node)) { - (properties || (properties = [])).push(createPropertyAssignment("paramTypes", createArrowFunction([], serializeParameterTypesOfNode(node)))); + (properties || (properties = [])).push(createPropertyAssignment("paramTypes", createArrowFunction(/*modifiers*/ undefined, /*typeParameters*/ undefined, [], /*type*/ undefined, /*equalsGreaterThanToken*/ undefined, serializeParameterTypesOfNode(node)))); } if (shouldAddReturnTypeMetadata(node)) { - (properties || (properties = [])).push(createPropertyAssignment("returnType", createArrowFunction([], serializeReturnTypeOfNode(node)))); + (properties || (properties = [])).push(createPropertyAssignment("returnType", createArrowFunction(/*modifiers*/ undefined, /*typeParameters*/ undefined, [], /*type*/ undefined, /*equalsGreaterThanToken*/ undefined, serializeReturnTypeOfNode(node)))); } if (properties) { decoratorExpressions.push(createMetadataHelper("design:typeinfo", createObjectLiteral(properties, /*location*/ undefined, /*multiLine*/ true))); @@ -1933,10 +1937,13 @@ namespace ts { } const method = createMethod( + /*decorators*/ undefined, visitNodes(node.modifiers, visitor, isModifier), node.asteriskToken, visitPropertyNameOfClassElement(node), + /*typeParameters*/ undefined, visitNodes(node.parameters, visitor, isParameter), + /*type*/ undefined, transformFunctionBody(node), /*location*/ node ); @@ -1975,9 +1982,11 @@ namespace ts { } const accessor = createGetAccessor( + /*decorators*/ undefined, visitNodes(node.modifiers, visitor, isModifier), visitPropertyNameOfClassElement(node), visitNodes(node.parameters, visitor, isParameter), + /*type*/ undefined, node.body ? visitEachChild(node.body, visitor, context) : createBlock([]), /*location*/ node ); @@ -2006,6 +2015,7 @@ namespace ts { } const accessor = createSetAccessor( + /*decorators*/ undefined, visitNodes(node.modifiers, visitor, isModifier), visitPropertyNameOfClassElement(node), visitNodes(node.parameters, visitor, isParameter), @@ -2038,10 +2048,13 @@ namespace ts { } const func = createFunctionDeclaration( + /*decorators*/ undefined, visitNodes(node.modifiers, visitor, isModifier), node.asteriskToken, node.name, + /*typeParameters*/ undefined, visitNodes(node.parameters, visitor, isParameter), + /*type*/ undefined, transformFunctionBody(node), /*location*/ node ); @@ -2072,7 +2085,9 @@ namespace ts { const func = createFunctionExpression( node.asteriskToken, node.name, + /*typeParameters*/ undefined, visitNodes(node.parameters, visitor, isParameter), + /*type*/ undefined, transformFunctionBody(node), /*location*/ node ); @@ -2089,7 +2104,11 @@ namespace ts { */ function visitArrowFunction(node: ArrowFunction) { const func = createArrowFunction( + /*modifiers*/ undefined, + /*typeParameters*/ undefined, visitNodes(node.parameters, visitor, isParameter), + /*type*/ undefined, + node.equalsGreaterThanToken, transformConciseBody(node), /*location*/ node ); @@ -2211,9 +2230,13 @@ namespace ts { return undefined; } - const parameter = createParameterWithDotDotDotToken( + const parameter = createParameterDeclaration( + /*decorators*/ undefined, + /*modifiers*/ undefined, node.dotDotDotToken, visitNode(node.name, visitor, isBindingName), + /*questionToken*/ undefined, + /*type*/ undefined, visitNode(node.initializer, visitor, isExpression), /*location*/ moveRangePastModifiers(node) ); @@ -2358,6 +2381,7 @@ namespace ts { /*modifiers*/ undefined, [createVariableDeclaration( getDeclarationName(node), + /*type*/ undefined, getExportName(node) )], /*location*/ node @@ -2398,9 +2422,12 @@ namespace ts { createFunctionExpression( /*asteriskToken*/ undefined, /*name*/ undefined, + /*typeParameters*/ undefined, [createParameter(paramName)], + /*type*/ undefined, transformEnumBody(node, innerName) ), + /*typeArguments*/ undefined, [createLogicalOr( exportName, createAssignment( @@ -2532,8 +2559,7 @@ namespace ts { : undefined, [ createVariableDeclaration( - getDeclarationName(node, /*allowComments*/ false, /*allowSourceMaps*/ true), - /*initializer*/ undefined + getDeclarationName(node, /*allowComments*/ false, /*allowSourceMaps*/ true) ) ] ); @@ -2630,9 +2656,12 @@ namespace ts { createFunctionExpression( /*asteriskToken*/ undefined, /*name*/ undefined, + /*typeParameters*/ undefined, [createParameter(parameterName)], + /*type*/ undefined, transformModuleBody(node, containerName) ), + /*typeArguments*/ undefined, [moduleArg] ), /*location*/ node @@ -2748,6 +2777,7 @@ namespace ts { createVariableDeclarationList([ createVariableDeclaration( node.name, + /*type*/ undefined, moduleReference ) ]), @@ -2944,19 +2974,6 @@ namespace ts { } } - function getDeclarationNameExpression(node: DeclarationStatement) { - const name = getDeclarationName(node); - if (isNamespaceExport(node)) { - return getNamespaceMemberName(name); - } - else { - // We set the "ExportName" flag to indicate to any module transformer - // downstream that any `exports.` prefix should be added. - setNodeEmitFlags(name, getNodeEmitFlags(name) | NodeEmitFlags.ExportName); - return name; - } - } - function getClassPrototype(node: ClassExpression | ClassDeclaration) { return createPropertyAccess(getDeclarationName(node), "prototype"); } @@ -3060,7 +3077,7 @@ namespace ts { currentDecoratedClassAliases[getOriginalNodeId(node)] = decoratedClassAliases[getOriginalNodeId(node)]; } else if (node.kind === SyntaxKind.Identifier) { - const declaration = resolver.getReferencedValueDeclaration(node) + const declaration = resolver.getReferencedValueDeclaration(node); if (declaration && isClassWithDecorators(declaration)) { currentDecoratedClassAliases[getOriginalNodeId(declaration)] = decoratedClassAliases[getOriginalNodeId(declaration)]; } @@ -3203,6 +3220,7 @@ namespace ts { : substituteElementAccessExpression(expression); return createCall( createPropertyAccess(argumentExpression, "call"), + /*typeArguments*/ undefined, [ createThis(), ...node.arguments @@ -3248,6 +3266,7 @@ namespace ts { return createPropertyAccess( createCall( createIdentifier("_super"), + /*typeArguments*/ undefined, [argumentExpression] ), "value", @@ -3257,6 +3276,7 @@ namespace ts { else { return createCall( createIdentifier("_super"), + /*typeArguments*/ undefined, [argumentExpression], location ); diff --git a/src/compiler/tsc.ts b/src/compiler/tsc.ts index 3bc554aa973..e2b6a77457d 100644 --- a/src/compiler/tsc.ts +++ b/src/compiler/tsc.ts @@ -6,6 +6,11 @@ namespace ts { fileWatcher?: FileWatcher; } + interface Statistic { + name: string; + value: string; + } + let reportDiagnostic = reportDiagnosticSimply; function reportDiagnostics(diagnostics: Diagnostic[], host: CompilerHost): void { @@ -235,18 +240,6 @@ namespace ts { return s; } - function reportStatisticalValue(name: string, value: string) { - sys.write(padRight(name + ":", 20) + padLeft(value.toString(), 10) + sys.newLine); - } - - function reportCountStatistic(name: string, count: number) { - reportStatisticalValue(name, "" + count); - } - - function reportTimeStatistic(name: string, time: number) { - reportStatisticalValue(name, (time / 1000).toFixed(2) + "s"); - } - function isJSONSupported() { return typeof JSON === "object" && typeof JSON.parse === "function"; } @@ -554,8 +547,10 @@ namespace ts { } function compile(fileNames: string[], compilerOptions: CompilerOptions, compilerHost: CompilerHost) { + let statistics: Statistic[]; if (compilerOptions.diagnostics || compilerOptions.extendedDiagnostics) { performance.enable(); + statistics = []; } const program = createProgram(fileNames, compilerOptions, compilerHost); @@ -601,6 +596,7 @@ namespace ts { reportTimeStatistic("Check time", checkTime); reportTimeStatistic("Emit time", emitTime); reportTimeStatistic("Total time", programTime + bindTime + checkTime + emitTime); + reportStatistics(); performance.disable(); } @@ -642,6 +638,36 @@ namespace ts { } return ExitStatus.Success; } + + function reportStatistics() { + let nameSize = 0; + let valueSize = 0; + for (const { name, value } of statistics) { + if (name.length > nameSize) { + nameSize = name.length; + } + + if (value.length > valueSize) { + valueSize = value.length; + } + } + + for (const { name, value } of statistics) { + sys.write(padRight(name + ":", nameSize + 2) + padLeft(value.toString(), valueSize) + sys.newLine); + } + } + + function reportStatisticalValue(name: string, value: string) { + statistics.push({ name, value }); + } + + function reportCountStatistic(name: string, count: number) { + reportStatisticalValue(name, "" + count); + } + + function reportTimeStatistic(name: string, time: number) { + reportStatisticalValue(name, (time / 1000).toFixed(2) + "s"); + } } function printVersion() { diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 65cae23684d..11df44c99b9 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -3110,12 +3110,18 @@ namespace ts { return false; } + const syntaxKindCache: Map = {}; + export function formatSyntaxKind(kind: SyntaxKind): string { const syntaxKindEnum = (ts).SyntaxKind; if (syntaxKindEnum) { + if (syntaxKindCache[kind]) { + return syntaxKindCache[kind]; + } + for (const name in syntaxKindEnum) { if (syntaxKindEnum[name] === kind) { - return kind.toString() + " (" + name + ")"; + return syntaxKindCache[kind] = kind.toString() + " (" + name + ")"; } } } diff --git a/src/compiler/visitor.ts b/src/compiler/visitor.ts index d9f3e457602..856571d221b 100644 --- a/src/compiler/visitor.ts +++ b/src/compiler/visitor.ts @@ -607,11 +607,393 @@ namespace ts { * @param context A lexical environment context for the visitor. */ export function visitEachChild(node: T, visitor: (node: Node) => VisitResult, context: LexicalEnvironment): T; - export function visitEachChild(node: T & Map, visitor: (node: Node) => VisitResult, context: LexicalEnvironment): T { + export function visitEachChild(node: Node, visitor: (node: Node) => VisitResult, context: LexicalEnvironment): Node { if (node === undefined) { return undefined; } + const kind = node.kind; + // No need to visit nodes with no children. + if ((kind > SyntaxKind.FirstToken && kind <= SyntaxKind.LastToken)) { + return node; + } + + // Special cases for frequent visitors to improve performance. + let visited: Node; + switch (kind) { + case SyntaxKind.ThisType: + case SyntaxKind.StringLiteralType: + case SyntaxKind.SemicolonClassElement: + case SyntaxKind.EmptyStatement: + case SyntaxKind.OmittedExpression: + case SyntaxKind.DebuggerStatement: + // No need to visit nodes with no children. + return node; + + // Signature elements + + case SyntaxKind.Parameter: + visited = visitEachChildOfParameter(node, visitor); + break; + + // Type member + + case SyntaxKind.MethodDeclaration: + visited = visitEachChildOfMethod(node, visitor, context); + break; + + case SyntaxKind.Constructor: + visited = visitEachChildOfConstructor(node, visitor, context); + break; + + case SyntaxKind.GetAccessor: + visited = visitEachChildOfGetAccessor(node, visitor, context); + break; + + case SyntaxKind.SetAccessor: + visited = visitEachChildOfSetAccessor(node, visitor, context); + break; + + // Expression + + case SyntaxKind.PropertyAccessExpression: + visited = visitEachChildOfPropertyAccess(node, visitor); + break; + + case SyntaxKind.CallExpression: + visited = visitEachChildOfCall(node, visitor); + break; + + case SyntaxKind.NewExpression: + visited = visitEachChildOfNew(node, visitor); + break; + + case SyntaxKind.BinaryExpression: + visited = visitEachChildOfBinary(node, visitor); + break; + + case SyntaxKind.FunctionExpression: + visited = visitEachChildOfFunctionExpression(node, visitor, context); + break; + + case SyntaxKind.ArrowFunction: + visited = visitEachChildOfArrowFunction(node, visitor, context); + break; + + // Element + + case SyntaxKind.Block: + visited = visitEachChildOfBlock(node, visitor); + break; + + case SyntaxKind.VariableStatement: + visited = visitEachChildOfVaribleStatement(node, visitor); + break; + + case SyntaxKind.ExpressionStatement: + visited = visitEachChildOfStatement(node, visitor); + break; + + case SyntaxKind.IfStatement: + visited = visitEachChildOfIf(node, visitor); + break; + + case SyntaxKind.ReturnStatement: + visited = visitEachChildOfReturn(node, visitor); + break; + + case SyntaxKind.VariableDeclaration: + visited = visitEachChildOfVariableDeclaration(node, visitor); + break; + + case SyntaxKind.VariableDeclarationList: + visited = visitEachChildOfVariableDeclarationList(node, visitor); + break; + + case SyntaxKind.FunctionDeclaration: + visited = visitEachChildOfFunctionDeclaration(node, visitor, context); + break; + + // Top-level nodes + + case SyntaxKind.SourceFile: + visited = visitEachChildOfSourceFile(node, visitor, context); + break; + + default: + visited = visitEachChildOfNode(node, visitor, context); + break; + } + + if (visited !== node) { + aggregateTransformFlags(visited); + } + + return visited; + } + + function visitEachChildOfSourceFile(node: SourceFile, visitor: (node: Node) => VisitResult, context: LexicalEnvironment) { + context.startLexicalEnvironment(); + const statements = visitNodes(node.statements, visitor, isStatement); + const declarations = context.endLexicalEnvironment(); + return updateSourceFileNode(node, + createNodeArray(concatenate(statements, declarations), statements) + ); + } + + function visitEachChildOfCall(node: CallExpression, visitor: (node: Node) => VisitResult) { + return updateCall(node, + visitNode(node.expression, visitor, isExpression), + visitNodes(node.typeArguments, visitor, isTypeNode), + visitNodes(node.arguments, visitor, isExpression) + ); + } + + function visitEachChildOfParameter(node: ParameterDeclaration, visitor: (node: Node) => VisitResult) { + return updateParameterDeclaration(node, + visitNodes(node.decorators, visitor, isDecorator), + visitNodes(node.modifiers, visitor, isModifier), + node.dotDotDotToken, + visitNode(node.name, visitor, isBindingName), + node.questionToken, + visitNode(node.type, visitor, isTypeNode, /*optional*/ true), + visitNode(node.initializer, visitor, isExpression, /*optional*/ true) + ); + } + + function visitEachChildOfStatement(node: ExpressionStatement, visitor: (node: Node) => VisitResult) { + return updateStatement(node, + visitNode(node.expression, visitor, isExpression) + ); + } + + function visitEachChildOfVaribleStatement(node: VariableStatement, visitor: (node: Node) => VisitResult) { + return updateVariableStatement(node, + visitNodes(node.modifiers, visitor, isModifier), + visitNode(node.declarationList, visitor, isVariableDeclarationList) + ); + } + + function visitEachChildOfVariableDeclarationList(node: VariableDeclarationList, visitor: (node: Node) => VisitResult) { + return updateVariableDeclarationList(node, + visitNodes(node.declarations, visitor, isVariableDeclaration) + ); + } + + function visitEachChildOfVariableDeclaration(node: VariableDeclaration, visitor: (node: Node) => VisitResult) { + return updateVariableDeclaration(node, + visitNode(node.name, visitor, isBindingName), + visitNode(node.type, visitor, isTypeNode, /*optional*/ true), + visitNode(node.initializer, visitor, isExpression, /*optional*/ true) + ); + } + + function visitEachChildOfConstructor(node: ConstructorDeclaration, visitor: (node: Node) => VisitResult, context: LexicalEnvironment) { + const decorators = visitNodes(node.decorators, visitor, isDecorator); + const modifiers = visitNodes(node.modifiers, visitor, isModifier); + context.startLexicalEnvironment(); + const parameters = visitNodes(node.parameters, visitor, isParameter); + const body = visitNode(node.body, visitor, isFunctionBody, /*optional*/ true); + const declarations = context.endLexicalEnvironment(); + return updateConstructor(node, + decorators, + modifiers, + parameters, + body ? updateBlock(body, createNodeArray(concatenate(body.statements, declarations), body.statements)) : undefined + ); + } + + function visitEachChildOfMethod(node: MethodDeclaration, visitor: (node: Node) => VisitResult, context: LexicalEnvironment) { + const decorators = visitNodes(node.decorators, visitor, isDecorator); + const modifiers = visitNodes(node.modifiers, visitor, isModifier); + const name = visitNode(node.name, visitor, isPropertyName); + const typeParameters = visitNodes(node.typeParameters, visitor, isTypeParameter); + context.startLexicalEnvironment(); + const parameters = visitNodes(node.parameters, visitor, isParameter); + const type = visitNode(node.type, visitor, isTypeNode, /*optional*/ true); + const body = visitNode(node.body, visitor, isFunctionBody, /*optional*/ true); + const declarations = context.endLexicalEnvironment(); + return updateMethod(node, + decorators, + modifiers, + node.asteriskToken, + name, + typeParameters, + parameters, + type, + body ? updateBlock(body, createNodeArray(concatenate(body.statements, declarations), body.statements)) : undefined + ); + } + + function visitEachChildOfGetAccessor(node: GetAccessorDeclaration, visitor: (node: Node) => VisitResult, context: LexicalEnvironment) { + const decorators = visitNodes(node.decorators, visitor, isDecorator); + const modifiers = visitNodes(node.modifiers, visitor, isModifier); + const name = visitNode(node.name, visitor, isPropertyName); + context.startLexicalEnvironment(); + const parameters = visitNodes(node.parameters, visitor, isParameter); + const type = visitNode(node.type, visitor, isTypeNode, /*optional*/ true); + const body = visitNode(node.body, visitor, isFunctionBody, /*optional*/ true); + const declarations = context.endLexicalEnvironment(); + return updateGetAccessor(node, + decorators, + modifiers, + name, + parameters, + type, + body ? updateBlock(body, createNodeArray(concatenate(body.statements, declarations), body.statements)) : undefined + ); + } + + function visitEachChildOfSetAccessor(node: SetAccessorDeclaration, visitor: (node: Node) => VisitResult, context: LexicalEnvironment) { + const decorators = visitNodes(node.decorators, visitor, isDecorator); + const modifiers = visitNodes(node.modifiers, visitor, isModifier); + const name = visitNode(node.name, visitor, isPropertyName); + context.startLexicalEnvironment(); + const parameters = visitNodes(node.parameters, visitor, isParameter); + const body = visitNode(node.body, visitor, isFunctionBody, /*optional*/ true); + const declarations = context.endLexicalEnvironment(); + return updateSetAccessor(node, + decorators, + modifiers, + name, + parameters, + body ? updateBlock(body, createNodeArray(concatenate(body.statements, declarations), body.statements)) : undefined + ); + } + + function visitEachChildOfBlock(node: Block, visitor: (node: Node) => VisitResult) { + return updateBlock(node, + visitNodes(node.statements, visitor, isStatement) + ); + } + + function visitEachChildOfPropertyAccess(node: PropertyAccessExpression, visitor: (node: Node) => VisitResult) { + return updatePropertyAccess(node, + visitNode(node.expression, visitor, isExpression), + visitNode(node.name, visitor, isIdentifier) + ); + } + + function visitEachChildOfIf(node: IfStatement, visitor: (node: Node) => VisitResult) { + return updateIf(node, + visitNode(node.expression, visitor, isExpression), + visitNode(node.thenStatement, visitor, isStatement, /*optional*/ false, liftToBlock), + visitNode(node.elseStatement, visitor, isStatement, /*optional*/ true, liftToBlock) + ); + } + + function visitEachChildOfBinary(node: BinaryExpression, visitor: (node: Node) => VisitResult) { + return updateBinary(node, + visitNode(node.left, visitor, isExpression), + visitNode(node.right, visitor, isExpression) + ); + } + + function visitEachChildOfReturn(node: ReturnStatement, visitor: (node: Node) => VisitResult) { + return updateReturn(node, + visitNode(node.expression, visitor, isExpression, /*optional*/ true) + ); + } + + function visitEachChildOfFunctionDeclaration(node: FunctionDeclaration, visitor: (node: Node) => VisitResult, context: LexicalEnvironment) { + const decorators = visitNodes(node.decorators, visitor, isDecorator); + const modifiers = visitNodes(node.modifiers, visitor, isModifier); + const name = visitNode(node.name, visitor, isIdentifier, /*optional*/ true); + const typeParameters = visitNodes(node.typeParameters, visitor, isTypeParameter); + context.startLexicalEnvironment(); + const parameters = visitNodes(node.parameters, visitor, isParameter); + const type = visitNode(node.type, visitor, isTypeNode, /*optional*/ true); + const body = visitNode(node.body, visitor, isFunctionBody, /*optional*/ true); + const declarations = context.endLexicalEnvironment(); + return updateFunctionDeclaration(node, + decorators, + modifiers, + name, + typeParameters, + parameters, + type, + body ? updateBlock(body, createNodeArray(concatenate(body.statements, declarations), body.statements)) : undefined + ); + } + + function visitEachChildOfFunctionExpression(node: FunctionExpression, visitor: (node: Node) => VisitResult, context: LexicalEnvironment) { + const name = visitNode(node.name, visitor, isIdentifier, /*optional*/ true); + const typeParameters = visitNodes(node.typeParameters, visitor, isTypeParameter); + context.startLexicalEnvironment(); + const parameters = visitNodes(node.parameters, visitor, isParameter); + const type = visitNode(node.type, visitor, isTypeNode, /*optional*/ true); + const body = visitNode(node.body, visitor, isFunctionBody, /*optional*/ true); + const declarations = context.endLexicalEnvironment(); + return updateFunctionExpression(node, + name, + typeParameters, + parameters, + type, + body ? updateBlock(body, createNodeArray(concatenate(body.statements, declarations), body.statements)) : undefined + ); + } + + function visitEachChildOfArrowFunction(node: ArrowFunction, visitor: (node: Node) => VisitResult, context: LexicalEnvironment) { + const modifiers = visitNodes(node.modifiers, visitor, isModifier); + const typeParameters = visitNodes(node.typeParameters, visitor, isTypeParameter); + context.startLexicalEnvironment(); + const parameters = visitNodes(node.parameters, visitor, isParameter); + const type = visitNode(node.type, visitor, isTypeNode, /*optional*/ true); + let body = visitNode(node.body, visitor, isConciseBody, /*optional*/ true); + const declarations = context.endLexicalEnvironment(); + if (declarations && declarations.length) { + const statements: Statement[] = []; + let statementsLocation: TextRange; + let multiLine = false; + if (isBlock(body)) { + addRange(statements, body.statements); + statementsLocation = body.statements; + multiLine = body.multiLine; + } + else { + statements.push(createReturn(body, /*location*/ body)); + statementsLocation = body; + multiLine = true; + } + + addRange(statements, declarations); + body = createBlock( + createNodeArray(statements, statementsLocation), + /*location*/ body, + multiLine + ); + } + + return updateArrowFunction(node, + modifiers, + typeParameters, + parameters, + type, + body + ); + } + + function visitEachChildOfNew(node: NewExpression, visitor: (node: Node) => VisitResult) { + return updateNew(node, + visitNode(node.expression, visitor, isExpression), + visitNodes(node.typeArguments, visitor, isTypeNode), + visitNodes(node.arguments, visitor, isExpression) + ); + } + + /** + * Visits each child of a Node using the supplied visitor, possibly returning a new Node of the same kind in its place. + * + * @param node The Node whose children will be visited. + * @param visitor The callback used to visit each child. + * @param context A lexical environment context for the visitor. + */ + function visitEachChildOfNode(node: T, visitor: (node: Node) => VisitResult, context: LexicalEnvironment): T; + function visitEachChildOfNode(node: T & Map, visitor: (node: Node) => VisitResult, context: LexicalEnvironment): T { + // const markName = `visitEachChild-${formatSyntaxKind(node.kind)}`; + // const measureName = `visitEachChildTime-${formatSyntaxKind(node.kind)}`; + // performance.mark(markName); + let updated: T & Map; // If this node starts a new lexical environment, start a new lexical environment on the context. @@ -626,6 +1008,8 @@ namespace ts { const value = >node[edge.name]; if (value !== undefined) { let visited: Node | NodeArray; + // performance.measure(measureName, markName); + if (isArray(value)) { const visitedArray = visitNodesWorker(value, visitor, edge.test, edge.parenthesize, node, 0, value.length); visited = visitedArray; @@ -634,6 +1018,7 @@ namespace ts { visited = visitNodeWorker(value, visitor, edge.test, edge.optional, edge.lift, edge.parenthesize, node); } + // performance.mark(markName); if (updated !== undefined || visited !== value) { if (updated === undefined) { updated = getMutableClone(node); @@ -659,10 +1044,10 @@ namespace ts { } if (updated !== node) { - aggregateTransformFlags(updated); updated.original = node; } + // performance.measure(measureName, markName); return updated; }