Adds ES6 transformer

This commit is contained in:
Ron Buckton
2016-02-19 17:01:02 -08:00
parent dd2dc78dd6
commit c759b633d6
23 changed files with 2537 additions and 429 deletions
+9
View File
@@ -238,6 +238,7 @@ function concatenateFiles(destinationFile, sourceFiles) {
}
var useDebugMode = true;
var useTransforms = process.env.USE_TRANSFORMS || false;
var host = (process.env.host || process.env.TYPESCRIPT_HOST || "node");
var compilerFilename = "tsc.js";
var LKGCompiler = path.join(LKGDirectory, compilerFilename);
@@ -297,6 +298,10 @@ function compileFile(outFile, sources, prereqs, prefixes, useBuiltCompiler, noOu
options += " --stripInternal"
}
if (useBuiltCompiler && useTransforms) {
options += " --experimentalTransforms"
}
var cmd = host + " " + compilerPath + " " + options + " ";
cmd = cmd + sources.join(" ");
console.log(cmd + "\n");
@@ -420,6 +425,10 @@ task("setDebugMode", function() {
useDebugMode = true;
});
task("setTransforms", function() {
useTransforms = true;
});
task("configure-nightly", [configureNightlyJs], function() {
var cmd = host + " " + configureNightlyJs + " " + packageJson + " " + programTs;
console.log(cmd);
+21 -15
View File
@@ -1971,20 +1971,6 @@ namespace ts {
break;
case SyntaxKind.ExpressionStatement:
if (nodeIsSynthesized(node)) {
const expression = (<ExpressionStatement>node).expression;
if (nodeIsSynthesized(expression)
&& isCallExpression(expression)
&& expression.expression.kind === SyntaxKind.SuperKeyword) {
// A synthesized call to `super` should be transformed to a cleaner emit
// when transpiling to ES5/3.
transformFlags |= TransformFlags.AssertES6;
}
}
break;
case SyntaxKind.BinaryExpression:
if (isDestructuringAssignment(node)) {
// Destructuring assignments are ES6 syntax.
@@ -2093,7 +2079,7 @@ namespace ts {
case SyntaxKind.VariableDeclarationList:
// If a VariableDeclarationList is `let` or `const`, then it is ES6 syntax.
if (node.flags & NodeFlags.BlockScoped) {
transformFlags |= TransformFlags.AssertES6;
transformFlags |= TransformFlags.AssertES6 | TransformFlags.ContainsBlockScopedBinding;
}
break;
@@ -2106,6 +2092,26 @@ namespace ts {
break;
case SyntaxKind.LabeledStatement:
// A labeled statement containing a block scoped binding *may* need to be transformed from ES6.
if (subtreeFlags & TransformFlags.ContainsBlockScopedBinding
&& isIterationStatement(this, /*lookInLabeledStatements*/ true)) {
transformFlags |= TransformFlags.AssertES6;
}
break;
case SyntaxKind.DoStatement:
case SyntaxKind.WhileStatement:
case SyntaxKind.ForStatement:
case SyntaxKind.ForInStatement:
// A loop containing a block scoped binding *may* need to be transformed from ES6.
if (subtreeFlags & TransformFlags.ContainsBlockScopedBinding) {
transformFlags |= TransformFlags.AssertES6;
}
break;
case SyntaxKind.ClassDeclaration:
case SyntaxKind.ClassExpression:
// A ClassDeclarations or ClassExpression is ES6 syntax.
+6 -4
View File
@@ -16672,11 +16672,13 @@ namespace ts {
}
// Modifiers are never allowed on properties except for 'async' on a method declaration
forEach(prop.modifiers, mod => {
if (mod.kind !== SyntaxKind.AsyncKeyword || prop.kind !== SyntaxKind.MethodDeclaration) {
grammarErrorOnNode(mod, Diagnostics._0_modifier_cannot_be_used_here, getTextOfNode(mod));
if (prop.modifiers) {
for (const mod of prop.modifiers) {
if (mod.kind !== SyntaxKind.AsyncKeyword || prop.kind !== SyntaxKind.MethodDeclaration) {
grammarErrorOnNode(mod, Diagnostics._0_modifier_cannot_be_used_here, getTextOfNode(mod));
}
}
});
}
// ECMA-262 11.1.5 Object Initialiser
// If previous is not undefined then throw a SyntaxError exception if any of the following conditions are true
+5
View File
@@ -320,6 +320,11 @@ namespace ts {
name: "allowSyntheticDefaultImports",
type: "boolean",
description: Diagnostics.Allow_default_imports_from_modules_with_no_default_export_This_does_not_affect_code_emit_just_typechecking
},
{
name: "experimentalTransforms",
type: "boolean",
experimental: true
}
];
+88 -54
View File
@@ -5,11 +5,15 @@ namespace ts {
export interface CommentWriter {
reset(): void;
setSourceFile(sourceFile: SourceFile): void;
getLeadingCommentsToEmit(node: TextRange): CommentRange[];
getTrailingCommentsToEmit(node: TextRange): CommentRange[];
emitDetachedComments(node: TextRange): void;
emitLeadingComments(node: TextRange, comments?: CommentRange[]): void;
emitTrailingComments(node: TextRange, comments?: CommentRange[]): void;
getLeadingComments(range: Node, getAdditionalRange?: (range: Node) => Node): CommentRange[];
getLeadingComments(range: TextRange): CommentRange[];
getLeadingCommentsOfPosition(pos: number): CommentRange[];
getTrailingComments(range: Node, getAdditionalRange?: (range: Node) => Node): CommentRange[];
getTrailingComments(range: TextRange): CommentRange[];
getTrailingCommentsOfPosition(pos: number): CommentRange[];
emitLeadingComments(range: TextRange, comments?: CommentRange[]): void;
emitTrailingComments(range: TextRange, comments?: CommentRange[]): void;
emitDetachedComments(range: TextRange): void;
}
export function createCommentWriter(host: EmitHost, writer: EmitTextWriter, sourceMap: SourceMapWriter): CommentWriter {
@@ -25,8 +29,8 @@ namespace ts {
// This maps start->end for a comment range. See `hasConsumedCommentRange` and
// `consumeCommentRange` for usage.
let consumedCommentRanges: number[];
let leadingCommentRangeNodeStarts: boolean[];
let trailingCommentRangeNodeEnds: boolean[];
let leadingCommentRangePositions: boolean[];
let trailingCommentRangePositions: boolean[];
return compilerOptions.removeComments
? createCommentRemovingWriter()
@@ -36,11 +40,13 @@ namespace ts {
return {
reset,
setSourceFile,
getLeadingCommentsToEmit(node: TextRange): CommentRange[] { return undefined; },
getTrailingCommentsToEmit(node: TextRange): CommentRange[] { return undefined; },
getLeadingComments(range: TextRange, getAdditionalRange?: (range: TextRange) => TextRange): CommentRange[] { return undefined; },
getLeadingCommentsOfPosition(pos: number): CommentRange[] { return undefined; },
getTrailingComments(range: TextRange, getAdditionalRange?: (range: TextRange) => TextRange): CommentRange[] { return undefined; },
getTrailingCommentsOfPosition(pos: number): CommentRange[] { return undefined; },
emitLeadingComments(range: TextRange, comments?: CommentRange[]): void { },
emitTrailingComments(range: TextRange, comments?: CommentRange[]): void { },
emitDetachedComments,
emitLeadingComments(node: TextRange, comments?: CommentRange[]): void { },
emitTrailingComments(node: TextRange, comments?: CommentRange[]): void { },
};
function emitDetachedComments(node: TextRange): void {
@@ -53,41 +59,85 @@ namespace ts {
return {
reset,
setSourceFile,
getLeadingCommentsToEmit,
getTrailingCommentsToEmit,
emitDetachedComments,
getLeadingComments,
getLeadingCommentsOfPosition,
getTrailingComments,
getTrailingCommentsOfPosition,
emitLeadingComments,
emitTrailingComments,
emitDetachedComments,
};
function getLeadingCommentsToEmit(node: TextRange) {
if (nodeIsSynthesized(node)) {
return;
function getLeadingComments(range: TextRange | Node, getAdditionalRange?: (range: Node) => Node) {
let comments = getLeadingCommentsOfPosition(range.pos);
if (getAdditionalRange) {
let additionalRange = getAdditionalRange(<Node>range);
while (additionalRange) {
comments = concatenate(
getLeadingCommentsOfPosition(additionalRange.pos),
comments
);
additionalRange = getAdditionalRange(additionalRange);
}
}
if (!leadingCommentRangeNodeStarts[node.pos]) {
leadingCommentRangeNodeStarts[node.pos] = true;
const comments = hasDetachedComments(node.pos)
? getLeadingCommentsWithoutDetachedComments()
: getLeadingCommentRanges(currentText, node.pos);
return consumeCommentRanges(comments);
}
return noComments;
return comments;
}
function getTrailingCommentsToEmit(node: TextRange) {
if (nodeIsSynthesized(node)) {
return;
function getTrailingComments(range: TextRange | Node, getAdditionalRange?: (range: Node) => Node) {
let comments = getTrailingCommentsOfPosition(range.end);
if (getAdditionalRange) {
let additionalRange = getAdditionalRange(<Node>range);
while (additionalRange) {
comments = concatenate(
comments,
getTrailingCommentsOfPosition(additionalRange.end)
);
additionalRange = getAdditionalRange(additionalRange);
}
}
if (!trailingCommentRangeNodeEnds[node.end]) {
trailingCommentRangeNodeEnds[node.end] = true;
const comments = getTrailingCommentRanges(currentText, node.end);
return consumeCommentRanges(comments);
return comments;
}
function getLeadingCommentsOfPosition(pos: number) {
if (positionIsSynthesized(pos) || leadingCommentRangePositions[pos]) {
return undefined;
}
return noComments;
leadingCommentRangePositions[pos] = true;
const comments = hasDetachedComments(pos)
? getLeadingCommentsWithoutDetachedComments()
: getLeadingCommentRanges(currentText, pos);
return consumeCommentRanges(comments);
}
function getTrailingCommentsOfPosition(pos: number) {
if (positionIsSynthesized(pos) || trailingCommentRangePositions[pos]) {
return undefined;
}
trailingCommentRangePositions[pos] = true;
const comments = getTrailingCommentRanges(currentText, pos);
return consumeCommentRanges(comments);
}
function emitLeadingComments(range: TextRange, comments = getLeadingComments(range)) {
emitNewLineBeforeLeadingComments(currentLineMap, writer, range, comments);
// Leading comments are emitted at /*leading comment1 */space/*leading comment*/space
emitComments(currentText, currentLineMap, writer, comments, /*leadingSeparator*/ false, /*trailingSeparator*/ true, newLine, writeComment);
}
function emitTrailingComments(range: TextRange, comments = getTrailingComments(range)) {
// trailing comments are emitted at space/*trailing comment1 */space/*trailing comment*/
emitComments(currentText, currentLineMap, writer, comments, /*leadingSeparator*/ true, /*trailingSeparator*/ false, newLine, writeComment);
}
function emitDetachedComments(range: TextRange) {
emitDetachedCommentsAndUpdateCommentsInfo(range, /*removeComments*/ false);
}
function hasConsumedCommentRange(comment: CommentRange) {
@@ -136,22 +186,6 @@ namespace ts {
return noComments;
}
function emitLeadingComments(range: TextRange, leadingComments: CommentRange[] = getLeadingCommentsToEmit(range)) {
emitNewLineBeforeLeadingComments(currentLineMap, writer, range, leadingComments);
// Leading comments are emitted at /*leading comment1 */space/*leading comment*/space
emitComments(currentText, currentLineMap, writer, leadingComments, /*trailingSeparator*/ true, newLine, writeComment);
}
function emitTrailingComments(range: TextRange, trailingComments = getTrailingCommentsToEmit(range)) {
// trailing comments are emitted at space/*trailing comment1 */space/*trailing comment*/
emitComments(currentText, currentLineMap, writer, trailingComments, /*trailingSeparator*/ false, newLine, writeComment);
}
function emitDetachedComments(range: TextRange) {
emitDetachedCommentsAndUpdateCommentsInfo(range, /*removeComments*/ false);
}
}
function reset() {
@@ -160,8 +194,8 @@ namespace ts {
currentLineMap = undefined;
detachedCommentsInfo = undefined;
consumedCommentRanges = undefined;
trailingCommentRangeNodeEnds = undefined;
leadingCommentRangeNodeStarts = undefined;
trailingCommentRangePositions = undefined;
leadingCommentRangePositions = undefined;
}
function setSourceFile(sourceFile: SourceFile) {
@@ -170,8 +204,8 @@ namespace ts {
currentLineMap = getLineStarts(sourceFile);
detachedCommentsInfo = undefined;
consumedCommentRanges = [];
leadingCommentRangeNodeStarts = [];
trailingCommentRangeNodeEnds = [];
leadingCommentRangePositions = [];
trailingCommentRangePositions = [];
}
function hasDetachedComments(pos: number) {
+8 -8
View File
@@ -292,9 +292,9 @@ namespace ts {
return ~low;
}
export function reduceLeft<T, U>(array: T[], f: (memo: U, value: T) => U, initial: U): U;
export function reduceLeft<T>(array: T[], f: (memo: T, value: T) => T): T;
export function reduceLeft<T>(array: T[], f: (memo: T, value: T) => T, initial?: T): T {
export function reduceLeft<T, U>(array: T[], f: (memo: U, value: T, i: number) => U, initial: U): U;
export function reduceLeft<T>(array: T[], f: (memo: T, value: T, i: number) => T): T;
export function reduceLeft<T>(array: T[], f: (memo: T, value: T, i: number) => T, initial?: T): T {
if (array) {
const count = array.length;
if (count > 0) {
@@ -308,7 +308,7 @@ namespace ts {
result = initial;
}
while (pos < count) {
result = f(result, array[pos]);
result = f(result, array[pos], pos);
pos++;
}
return result;
@@ -317,9 +317,9 @@ namespace ts {
return initial;
}
export function reduceRight<T, U>(array: T[], f: (memo: U, value: T) => U, initial: U): U;
export function reduceRight<T>(array: T[], f: (memo: T, value: T) => T): T;
export function reduceRight<T>(array: T[], f: (memo: T, value: T) => T, initial?: T): T {
export function reduceRight<T, U>(array: T[], f: (memo: U, value: T, i: number) => U, initial: U): U;
export function reduceRight<T>(array: T[], f: (memo: T, value: T, i: number) => T): T;
export function reduceRight<T>(array: T[], f: (memo: T, value: T, i: number) => T, initial?: T): T {
if (array) {
let pos = array.length - 1;
if (pos >= 0) {
@@ -332,7 +332,7 @@ namespace ts {
result = initial;
}
while (pos >= 0) {
result = f(result, array[pos]);
result = f(result, array[pos], pos);
pos--;
}
return result;
+4 -4
View File
@@ -91,7 +91,7 @@ namespace ts {
// Emit reference in dts, if the file reference was not already emitted
if (referencedFile && !contains(emittedReferencedFiles, referencedFile)) {
// Add a reference to generated dts file,
// global file reference is added only
// global file reference is added only
// - if it is not bundled emit (because otherwise it would be self reference)
// - and it is not already added
if (writeReferencePath(referencedFile, !isBundledEmit && !addedGlobalFileReference)) {
@@ -144,7 +144,7 @@ namespace ts {
if (!isBundledEmit && isExternalModule(sourceFile) && sourceFile.moduleAugmentations.length && !resultHasExternalModuleIndicator) {
// if file was external module with augmentations - this fact should be preserved in .d.ts as well.
// in case if we didn't write any external module specifiers in .d.ts we need to emit something
// in case if we didn't write any external module specifiers in .d.ts we need to emit something
// that will force compiler to think that this file is an external module - 'export {}' is a reasonable choice here.
write("export {};");
writeLine();
@@ -349,7 +349,7 @@ namespace ts {
const jsDocComments = getJsDocCommentsFromText(declaration, currentText);
emitNewLineBeforeLeadingComments(currentLineMap, writer, declaration, jsDocComments);
// jsDoc comments are emitted at /*leading comment1 */space/*leading comment*/space
emitComments(currentText, currentLineMap, writer, jsDocComments, /*trailingSeparator*/ true, newLine, writeCommentRange);
emitComments(currentText, currentLineMap, writer, jsDocComments, /*leadingSeparator*/ false, /*trailingSeparator*/ true, newLine, writeCommentRange);
}
}
@@ -736,7 +736,7 @@ namespace ts {
function emitExternalModuleSpecifier(parent: ImportEqualsDeclaration | ImportDeclaration | ExportDeclaration | ModuleDeclaration) {
// emitExternalModuleSpecifier is usually called when we emit something in the.d.ts file that will make it an external module (i.e. import/export declarations).
// the only case when it is not true is when we call it to emit correct name for module augmentation - d.ts files with just module augmentations are not considered
// the only case when it is not true is when we call it to emit correct name for module augmentation - d.ts files with just module augmentations are not considered
// external modules since they are indistingushable from script files with ambient modules. To fix this in such d.ts files we'll emit top level 'export {}'
// so compiler will treat them as external modules.
resultHasExternalModuleIndicator = resultHasExternalModuleIndicator || parent.kind !== SyntaxKind.ModuleDeclaration;
+48 -18
View File
@@ -287,12 +287,8 @@ namespace ts {
_i = 0x10000000, // Use/preference flag for '_i'
}
export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFile: SourceFile): EmitResult {
return printFiles(resolver, host, targetSourceFile);
}
// targetSourceFile is when users only want one file in entire project to be emitted. This is used in compileOnSave feature
export function legacyEmitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFile: SourceFile): EmitResult {
export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFile: SourceFile): EmitResult {
// emit output for the __extends helper function
const extendsHelper = `
var __extends = (this && this.__extends) || function (d, b) {
@@ -1919,7 +1915,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
if (multiLine) {
decreaseIndent();
writeLine();
}
write(")");
@@ -2246,6 +2241,13 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
return node;
}
function skipAssertions(node: Expression): Expression {
while (node.kind === SyntaxKind.TypeAssertionExpression || node.kind === SyntaxKind.AsExpression) {
node = (<ParenthesizedExpression | AssertionExpression>node).expression;
}
return node;
}
function emitCallTarget(node: Expression): Expression {
if (node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.ThisKeyword || node.kind === SyntaxKind.SuperKeyword) {
emit(node);
@@ -2695,7 +2697,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
}
function synthesizedNodeStartsOnNewLine(node: Node) {
return nodeIsSynthesized(node) && (<SynthesizedNode>node).startsOnNewLine;
return nodeIsSynthesized(node) && node.startsOnNewLine;
}
function emitConditionalExpression(node: ConditionalExpression) {
@@ -3312,8 +3314,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
// we can't reuse 'arr' because it might be modified within the body of the loop.
const counter = createTempVariable(TempFlags._i);
const rhsReference = createSynthesizedNode(SyntaxKind.Identifier) as Identifier;
rhsReference.text = node.expression.kind === SyntaxKind.Identifier ?
makeUniqueName((<Identifier>node.expression).text) :
const expressionWithoutAssertions = skipAssertions(node.expression);
rhsReference.text = expressionWithoutAssertions.kind === SyntaxKind.Identifier ?
makeUniqueName((<Identifier>expressionWithoutAssertions).text) :
makeTempVariableName(TempFlags.Auto);
// This is the let keyword for the counter and rhsReference. The let keyword for
@@ -4328,7 +4331,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
writeLine();
emitStart(restParam);
emitNodeWithCommentsAndWithoutSourcemap(restParam.name);
write("[" + tempName + " - " + restIndex + "] = arguments[" + tempName + "];");
write(restIndex > 0
? `[${tempName} - ${restIndex}] = arguments[${tempName}];`
: `[${tempName}] = arguments[${tempName}];`);
emitEnd(restParam);
decreaseIndent();
writeLine();
@@ -5344,6 +5349,18 @@ const _super = (function (geti, seti) {
write(" = ");
}
const staticProperties = getInitializedProperties(node, /*isStatic*/ true);
const isClassExpressionWithStaticProperties = staticProperties.length > 0 && node.kind === SyntaxKind.ClassExpression;
let tempVariable: Identifier;
if (isClassExpressionWithStaticProperties) {
tempVariable = createAndRecordTempVariable(TempFlags.Auto);
write("(");
increaseIndent();
emit(tempVariable);
write(" = ");
}
write("(function (");
const baseTypeNode = getClassExtendsHeritageClauseElement(node);
if (baseTypeNode) {
@@ -5373,9 +5390,6 @@ const _super = (function (geti, seti) {
writeLine();
emitConstructor(node, baseTypeNode);
emitMemberFunctionsForES5AndLower(node);
emitPropertyDeclarations(node, getInitializedProperties(node, /*isStatic*/ true));
writeLine();
emitDecoratorsOfClass(node, /*decoratedClassAlias*/ undefined);
writeLine();
emitToken(SyntaxKind.CloseBraceToken, node.members.end, () => {
write("return ");
@@ -5402,7 +5416,23 @@ const _super = (function (geti, seti) {
write("))");
if (node.kind === SyntaxKind.ClassDeclaration) {
write(";");
emitPropertyDeclarations(node, staticProperties);
writeLine();
emitDecoratorsOfClass(node, /*decoratedClassAlias*/ undefined);
}
else if (isClassExpressionWithStaticProperties) {
for (const property of staticProperties) {
write(",");
writeLine();
emitPropertyDeclaration(node, property, /*receiver*/ tempVariable, /*isExpression*/ true);
}
write(",");
writeLine();
emit(tempVariable);
decreaseIndent();
write(")");
}
emitEnd(node);
if (node.kind === SyntaxKind.ClassDeclaration) {
@@ -7941,7 +7971,7 @@ const _super = (function (geti, seti) {
emitNewLineBeforeLeadingComments(currentLineMap, writer, node, leadingComments);
// Leading comments are emitted at /*leading comment1 */space/*leading comment*/space
emitComments(currentText, currentLineMap, writer, leadingComments, /*trailingSeparator*/ true, newLine, writeComment);
emitComments(currentText, currentLineMap, writer, leadingComments, /*leadingSeparator*/ false, /*trailingSeparator*/ true, newLine, writeComment);
}
function emitTrailingComments(node: Node) {
@@ -7953,7 +7983,7 @@ const _super = (function (geti, seti) {
const trailingComments = getTrailingCommentsToEmit(node);
// trailing comments are emitted at space/*trailing comment1 */space/*trailing comment*/
emitComments(currentText, currentLineMap, writer, trailingComments, /*trailingSeparator*/ false, newLine, writeComment);
emitComments(currentText, currentLineMap, writer, trailingComments, /*leadingSeparator*/ true, /*trailingSeparator*/ false, newLine, writeComment);
}
/**
@@ -7968,8 +7998,8 @@ const _super = (function (geti, seti) {
const trailingComments = getTrailingCommentRanges(currentText, pos);
// trailing comments are emitted at space/*trailing comment1 */space/*trailing comment*/
emitComments(currentText, currentLineMap, writer, trailingComments, /*trailingSeparator*/ true, newLine, writeComment);
// trailing comments of a position are emitted at /*trailing comment1 */space/*trailing comment*/space
emitComments(currentText, currentLineMap, writer, trailingComments, /*leadingSeparator*/ false, /*trailingSeparator*/ true, newLine, writeComment);
}
function emitLeadingCommentsOfPositionWorker(pos: number) {
@@ -7990,7 +8020,7 @@ const _super = (function (geti, seti) {
emitNewLineBeforeLeadingComments(currentLineMap, writer, { pos: pos, end: pos }, leadingComments);
// Leading comments are emitted at /*leading comment1 */space/*leading comment*/space
emitComments(currentText, currentLineMap, writer, leadingComments, /*trailingSeparator*/ true, newLine, writeComment);
emitComments(currentText, currentLineMap, writer, leadingComments, /*leadingSeparator*/ false, /*trailingSeparator*/ true, newLine, writeComment);
}
function emitDetachedCommentsAndUpdateCommentsInfo(node: TextRange) {
+295 -52
View File
@@ -92,7 +92,7 @@ namespace ts {
}
export function createSynthesizedNode(kind: SyntaxKind, startsOnNewLine?: boolean): Node {
const node = <SynthesizedNode>createNode(kind, /*location*/ undefined);
const node = createNode(kind, /*location*/ undefined);
node.startsOnNewLine = startsOnNewLine;
return node;
}
@@ -153,20 +153,20 @@ namespace ts {
// Literals
export function createLiteral(value: string): StringLiteral;
export function createLiteral(value: number): LiteralExpression;
export function createLiteral(value: string | number | boolean): PrimaryExpression;
export function createLiteral(value: string | number | boolean): PrimaryExpression {
export function createLiteral(value: string, location?: TextRange): StringLiteral;
export function createLiteral(value: number, location?: TextRange): LiteralExpression;
export function createLiteral(value: string | number | boolean, location?: TextRange): PrimaryExpression;
export function createLiteral(value: string | number | boolean, location?: TextRange): PrimaryExpression {
if (typeof value === "number") {
const node = <LiteralExpression>createNode(SyntaxKind.NumericLiteral);
const node = <LiteralExpression>createNode(SyntaxKind.NumericLiteral, location);
node.text = value.toString();
return node;
}
else if (typeof value === "boolean") {
return <PrimaryExpression>createNode(value ? SyntaxKind.TrueKeyword : SyntaxKind.FalseKeyword);
return <PrimaryExpression>createNode(value ? SyntaxKind.TrueKeyword : SyntaxKind.FalseKeyword, location);
}
else {
const node = <StringLiteral>createNode(SyntaxKind.StringLiteral);
const node = <StringLiteral>createNode(SyntaxKind.StringLiteral, location);
node.text = String(value);
return node;
}
@@ -203,8 +203,8 @@ namespace ts {
return node;
}
export function createThis() {
const node = <PrimaryExpression>createNode(SyntaxKind.ThisKeyword);
export function createThis(location?: TextRange) {
const node = <PrimaryExpression>createNode(SyntaxKind.ThisKeyword, location);
return node;
}
@@ -267,8 +267,8 @@ namespace ts {
return node;
}
export function createParameter(name: string | Identifier | BindingPattern, initializer?: Expression) {
const node = <ParameterDeclaration>createNode(SyntaxKind.Parameter);
export function createParameter(name: string | Identifier | BindingPattern, initializer?: Expression, location?: TextRange) {
const node = <ParameterDeclaration>createNode(SyntaxKind.Parameter, location);
node.decorators = undefined;
node.modifiers = undefined;
node.dotDotDotToken = undefined;
@@ -288,8 +288,8 @@ namespace ts {
return node;
}
export function createObjectLiteral(properties?: ObjectLiteralElement[]) {
const node = <ObjectLiteralExpression>createNode(SyntaxKind.ObjectLiteralExpression);
export function createObjectLiteral(properties?: ObjectLiteralElement[], location?: TextRange) {
const node = <ObjectLiteralExpression>createNode(SyntaxKind.ObjectLiteralExpression, location);
node.properties = createNodeArray(properties);
return node;
}
@@ -316,6 +316,13 @@ namespace ts {
return node;
}
export function createNew(expression: Expression, argumentsArray: Expression[], location?: TextRange) {
const node = <NewExpression>createNode(SyntaxKind.NewExpression, location);
node.expression = parenthesizeForAccess(expression);
node.arguments = argumentsArray ? createNodeArray(argumentsArray) : undefined;
return node;
}
export function createParen(expression: Expression, location?: TextRange) {
const node = <ParenthesizedExpression>createNode(SyntaxKind.ParenthesizedExpression, location);
node.expression = expression;
@@ -347,13 +354,20 @@ namespace ts {
export function createTypeOf(expression: Expression) {
const node = <TypeOfExpression>createNode(SyntaxKind.TypeOfExpression);
node.expression = parenthesizeForUnary(expression);
node.expression = parenthesizePrefixOperand(expression);
return node;
}
export function createVoid(expression: Expression) {
const node = <VoidExpression>createNode(SyntaxKind.VoidExpression);
node.expression = parenthesizeForUnary(expression);
node.expression = parenthesizePrefixOperand(expression);
return node;
}
export function createPostfix(operand: Expression, operator: SyntaxKind, location?: TextRange) {
const node = <PostfixUnaryExpression>createNode(SyntaxKind.PostfixUnaryExpression, location);
node.operand = parenthesizePostfixOperand(operand);
node.operator = operator;
return node;
}
@@ -442,14 +456,64 @@ namespace ts {
return node;
}
export function createEmptyStatement(location: TextRange) {
return <EmptyStatement>createNode(SyntaxKind.EmptyStatement, location);
}
export function createStatement(expression: Expression, location?: TextRange): ExpressionStatement {
const node = <ExpressionStatement>createNode(SyntaxKind.ExpressionStatement, location);
node.expression = expression;
return node;
}
export function createReturn(expression?: Expression): ReturnStatement {
const node = <ReturnStatement>createSynthesizedNode(SyntaxKind.ReturnStatement);
export function createIf(expression: Expression, thenStatement: Statement, elseStatement?: Statement, location?: TextRange) {
const node = <IfStatement>createNode(SyntaxKind.IfStatement, location);
node.expression = expression;
node.thenStatement = thenStatement;
node.elseStatement = elseStatement;
return node;
}
export function createFor(initializer: ForInitializer, condition: Expression, incrementor: Expression, statement: Statement, location?: TextRange) {
const node = <ForStatement>createNode(SyntaxKind.ForStatement, location);
node.initializer = initializer;
node.condition = condition;
node.incrementor = incrementor;
node.statement = statement;
return node;
}
export function createLabel(label: string | Identifier, statement: Statement, location?: TextRange) {
const node = <LabeledStatement>createNode(SyntaxKind.LabeledStatement, location);
node.label = typeof label === "string" ? createIdentifier(label) : label;
node.statement = statement;
return node;
}
export function createDo(expression: Expression, statement: Statement, location?: TextRange) {
const node = <DoStatement>createNode(SyntaxKind.DoStatement, location);
node.expression = expression;
node.statement = statement;
return node;
}
export function createWhile(statement: Statement, expression: Expression, location?: TextRange) {
const node = <WhileStatement>createNode(SyntaxKind.WhileStatement, location);
node.statement = statement;
node.expression = expression;
return node;
}
export function createForIn(initializer: ForInitializer, expression: Expression, statement: Statement, location?: TextRange) {
const node = <ForInStatement>createNode(SyntaxKind.ForInStatement, location);
node.initializer = initializer;
node.expression = expression;
node.statement = statement;
return node;
}
export function createReturn(expression?: Expression, location?: TextRange): ReturnStatement {
const node = <ReturnStatement>createNode(SyntaxKind.ReturnStatement, location);
node.expression = expression;
return node;
}
@@ -516,9 +580,9 @@ namespace ts {
// Property assignments
export function createPropertyAssignment(name: PropertyName, initializer: Expression) {
const node = <PropertyAssignment>createNode(SyntaxKind.PropertyAssignment);
node.name = name;
export function createPropertyAssignment(name: string | PropertyName, initializer: Expression, location?: TextRange) {
const node = <PropertyAssignment>createNode(SyntaxKind.PropertyAssignment, location);
node.name = typeof name === "string" ? createIdentifier(name) : name;
node.questionToken = undefined;
node.initializer = initializer;
return node;
@@ -526,18 +590,18 @@ namespace ts {
// Compound nodes
export function createComma(left: Expression, right: Expression) {
return <Expression>createBinary(left, SyntaxKind.CommaToken, right);
}
export function createLessThan(left: Expression, right: Expression, location?: TextRange) {
return <Expression>createBinary(left, SyntaxKind.LessThanToken, right, location);
}
export function createAssignment(left: Expression, right: Expression, location?: TextRange) {
return createBinary(left, SyntaxKind.EqualsToken, right, location);
}
export function createLogicalAnd(left: Expression, right: Expression) {
return createBinary(left, SyntaxKind.AmpersandAmpersandToken, right);
}
export function createLogicalOr(left: Expression, right: Expression) {
return createBinary(left, SyntaxKind.BarBarToken, right);
}
export function createStrictEquality(left: Expression, right: Expression) {
return createBinary(left, SyntaxKind.EqualsEqualsEqualsToken, right);
}
@@ -546,8 +610,24 @@ namespace ts {
return createBinary(left, SyntaxKind.ExclamationEqualsEqualsToken, right);
}
export function createComma(left: Expression, right: Expression) {
return <Expression>createBinary(left, SyntaxKind.CommaToken, right);
export function createAdd(left: Expression, right: Expression) {
return createBinary(left, SyntaxKind.PlusToken, right);
}
export function createSubtract(left: Expression, right: Expression) {
return createBinary(left, SyntaxKind.MinusToken, right);
}
export function createPostfixIncrement(operand: Expression, location?: TextRange) {
return createPostfix(operand, SyntaxKind.PlusPlusToken, location);
}
export function createLogicalAnd(left: Expression, right: Expression) {
return createBinary(left, SyntaxKind.AmpersandAmpersandToken, right);
}
export function createLogicalOr(left: Expression, right: Expression) {
return createBinary(left, SyntaxKind.BarBarToken, right);
}
export function createVoidZero() {
@@ -566,6 +646,28 @@ namespace ts {
return node;
}
export function createFunctionCall(func: Expression, thisArg: Expression, argumentsList: Expression[], location?: TextRange) {
return createCall(
createPropertyAccess(func, "call"),
[
thisArg,
...argumentsList
],
location
);
}
export function createFunctionApply(func: Expression, thisArg: Expression, argumentsExpression: Expression, location?: TextRange) {
return createCall(
createPropertyAccess(func, "apply"),
[
thisArg,
argumentsExpression
],
location
);
}
export function createArraySlice(array: Expression, start?: number | Expression) {
const argumentsList: Expression[] = [];
if (start !== undefined) {
@@ -575,6 +677,13 @@ namespace ts {
return createCall(createPropertyAccess(array, "slice"), argumentsList);
}
export function createArrayConcat(array: Expression, values: Expression[]) {
return createCall(
createPropertyAccess(array, "concat"),
values
);
}
export function createMathPow(left: Expression, right: Expression, location?: TextRange) {
return createCall(
createPropertyAccess(createIdentifier("Math"), "pow"),
@@ -618,6 +727,16 @@ namespace ts {
// Helpers
export function createExtendsHelper(name: Identifier) {
return createCall(
createIdentifier("__extends"),
[
name,
createIdentifier("_super")
]
);
}
export function createParamHelper(expression: Expression, parameterOffset: number) {
return createCall(
createIdentifier("__param"),
@@ -671,6 +790,56 @@ namespace ts {
);
}
function createPropertyDescriptor({ get, set, value, enumerable, configurable, writable }: PropertyDescriptorOptions, preferNewLine?: boolean, location?: TextRange) {
const properties: ObjectLiteralElement[] = [];
addPropertyAssignment(properties, "get", get, preferNewLine);
addPropertyAssignment(properties, "set", set, preferNewLine);
addPropertyAssignment(properties, "value", value, preferNewLine);
addPropertyAssignment(properties, "enumerable", enumerable, preferNewLine);
addPropertyAssignment(properties, "configurable", configurable, preferNewLine);
addPropertyAssignment(properties, "writable", writable, preferNewLine);
return createObjectLiteral(properties, location)
}
function addPropertyAssignment(properties: ObjectLiteralElement[], name: string, value: boolean | Expression, preferNewLine: boolean) {
if (value !== undefined) {
const property = createPropertyAssignment(
name,
typeof value === "boolean" ? createLiteral(value) : value
);
if (preferNewLine) {
startOnNewLine(property);
}
addNode(properties, property);
}
}
export interface PropertyDescriptorOptions {
get?: Expression;
set?: Expression;
value?: Expression;
enumerable?: boolean | Expression;
configurable?: boolean | Expression;
writable?: boolean | Expression;
}
export function createObjectDefineProperty(target: Expression, memberName: Expression, descriptor: PropertyDescriptorOptions, preferNewLine?: boolean, location?: TextRange) {
return createCall(
createPropertyAccess(
createIdentifier("Object"),
"defineProperty"
),
[
target,
memberName,
createPropertyDescriptor(descriptor, preferNewLine)
],
location
);
}
function createObjectCreate(prototype: Expression) {
return createCall(
createPropertyAccess(createIdentifier("Object"), "create"),
@@ -839,6 +1008,12 @@ namespace ts {
: cloneNode(node);
}
export function createExpressionForPropertyName(memberName: PropertyName, location?: TextRange): Expression {
return isIdentifier(memberName) ? createLiteral(memberName.text, location)
: isComputedPropertyName(memberName) ? cloneNode(memberName.expression, location)
: cloneNode(memberName, location);
}
// Utilities
/**
@@ -850,11 +1025,7 @@ namespace ts {
* @param isLeftSideOfBinary A value indicating whether the operand is the left side of the
* BinaryExpression.
*/
function parenthesizeBinaryOperand(binaryOperator: SyntaxKind, operand: Expression, isLeftSideOfBinary: boolean) {
// When diagnosing whether the expression needs parentheses, the decision should be based
// on the innermost expression in a chain of nested type assertions.
operand = skipAssertions(operand);
export function parenthesizeBinaryOperand(binaryOperator: SyntaxKind, operand: Expression, isLeftSideOfBinary: boolean) {
// If the resulting expression is already parenthesized, we do not need to do any further processing.
if (operand.kind === SyntaxKind.ParenthesizedExpression) {
return operand;
@@ -968,11 +1139,7 @@ namespace ts {
*
* @param expr The expression node.
*/
function parenthesizeForAccess(expr: Expression): LeftHandSideExpression {
// When diagnosing whether the expression needs parentheses, the decision should be based
// on the innermost expression in a chain of nested type assertions.
expr = skipAssertions(expr);
export function parenthesizeForAccess(expression: Expression): LeftHandSideExpression {
// isLeftHandSideExpression is almost the correct criterion for when it is not necessary
// to parenthesize the expression before a dot. The known exceptions are:
//
@@ -981,21 +1148,86 @@ namespace ts {
// NumericLiteral
// 1.x -> not the same as (1).x
//
if (isLeftHandSideExpression(expr) &&
expr.kind !== SyntaxKind.NewExpression &&
expr.kind !== SyntaxKind.NumericLiteral) {
return expr;
if (isLeftHandSideExpression(expression) &&
expression.kind !== SyntaxKind.NewExpression &&
expression.kind !== SyntaxKind.NumericLiteral) {
return <LeftHandSideExpression>expression;
}
return createParen(expr);
return createParen(expression, /*location*/ expression);
}
function parenthesizeForUnary(operand: Expression) {
if (isUnaryExpression(operand)) {
return operand;
export function parenthesizePostfixOperand(operand: Expression) {
return isLeftHandSideExpression(operand)
? <LeftHandSideExpression>operand
: createParen(operand, /*location*/ operand);
}
export function parenthesizePrefixOperand(operand: Expression) {
return isUnaryExpression(operand)
? <UnaryExpression>operand
: createParen(operand, /*location*/ operand);
}
export function parenthesizeExpressionForList(expression: Expression) {
const expressionPrecedence = getExpressionPrecedence(expression);
const commaPrecedence = getOperatorPrecedence(SyntaxKind.BinaryExpression, SyntaxKind.CommaToken);
return expressionPrecedence > commaPrecedence
? expression
: createParen(expression, /*location*/ expression);
}
export function parenthesizeExpressionForExpressionStatement(expression: Expression) {
if (isCallExpression(expression)) {
const callee = expression.expression;
if (callee.kind === SyntaxKind.FunctionExpression
|| callee.kind === SyntaxKind.ArrowFunction) {
const clone = cloneNode(expression, expression, expression.flags, expression.parent, expression);
clone.expression = createParen(callee, /*location*/ callee);
return clone;
}
}
else if (getLeftmostExpression(expression).kind === SyntaxKind.ObjectLiteralExpression) {
return createParen(expression, /*location*/ expression);
}
return createParen(operand);
return expression;
}
function getLeftmostExpression(node: Expression): Expression {
while (true) {
switch (node.kind) {
case SyntaxKind.PostfixUnaryExpression:
node = (<PostfixUnaryExpression>node).operand;
continue;
case SyntaxKind.BinaryExpression:
node = (<BinaryExpression>node).left;
continue;
case SyntaxKind.ConditionalExpression:
node = (<ConditionalExpression>node).condition;
continue;
case SyntaxKind.CallExpression:
case SyntaxKind.ElementAccessExpression:
case SyntaxKind.PropertyAccessExpression:
node = (<CallExpression | PropertyAccessExpression | ElementAccessExpression>node).expression;
continue;
}
return node;
}
}
export function skipParentheses(node: Expression): Expression {
while (node.kind === SyntaxKind.ParenthesizedExpression
|| node.kind === SyntaxKind.TypeAssertionExpression
|| node.kind === SyntaxKind.AsExpression) {
node = (<ParenthesizedExpression | AssertionExpression>node).expression;
}
return node;
}
/**
@@ -1004,7 +1236,8 @@ namespace ts {
* @param node The expression node.
*/
function skipAssertions(node: Expression) {
while (node.kind === SyntaxKind.TypeAssertionExpression || node.kind === SyntaxKind.AsExpression) {
while (node.kind === SyntaxKind.TypeAssertionExpression
|| node.kind === SyntaxKind.AsExpression) {
node = (<AssertionExpression>node).expression;
}
@@ -1012,7 +1245,7 @@ namespace ts {
}
export function startOnNewLine<T extends Node>(node: T): T {
(<SynthesizedNode>node).startsOnNewLine = true;
node.startsOnNewLine = true;
return node;
}
@@ -1034,6 +1267,16 @@ namespace ts {
return node;
}
export function setMultiLine<T extends ObjectLiteralExpression | ArrayLiteralExpression | Block>(node: T, multiLine: boolean): T {
node.multiLine = multiLine;
return node;
}
export function setHasTrailingComma<T extends Node>(nodes: NodeArray<T>, hasTrailingComma: boolean): NodeArray<T> {
nodes.hasTrailingComma = hasTrailingComma;
return nodes;
}
export function getSynthesizedNode<T extends Node>(node: T): T {
return nodeIsSynthesized(node) ? node : cloneNode(node, /*location*/ undefined, node.flags, /*parent*/ undefined, /*original*/ node);
}
+4
View File
@@ -4069,6 +4069,10 @@ namespace ts {
function parseBlock(ignoreMissingOpenBrace: boolean, diagnosticMessage?: DiagnosticMessage): Block {
const node = <Block>createNode(SyntaxKind.Block);
if (parseExpected(SyntaxKind.OpenBraceToken, diagnosticMessage) || ignoreMissingOpenBrace) {
if (scanner.hasPrecedingLineBreak()) {
node.multiLine = true;
}
node.statements = parseList(ParsingContext.BlockStatements, parseStatement);
parseExpected(SyntaxKind.CloseBraceToken);
}
+147 -90
View File
@@ -119,13 +119,31 @@ const _super = (function (geti, seti) {
const transformers = getTransformers(compilerOptions).concat(initializePrinter);
const writer = createTextWriter(newLine);
const { write, writeTextOfNode, writeLine, increaseIndent, decreaseIndent } = writer;
const {
write,
writeTextOfNode,
writeLine,
increaseIndent,
decreaseIndent
} = writer;
const sourceMap = compilerOptions.sourceMap || compilerOptions.inlineSourceMap ? createSourceMapWriter(host, writer) : getNullSourceMapWriter();
const { emitStart, emitEnd, emitPos } = sourceMap;
const {
emitStart,
emitEnd,
emitPos
} = sourceMap;
const comments = createCommentWriter(host, writer, sourceMap);
const { emitDetachedComments, emitLeadingComments, emitTrailingComments, getLeadingCommentsToEmit, getTrailingCommentsToEmit } = comments;
const {
getLeadingComments,
getLeadingCommentsOfPosition,
getTrailingComments,
getTrailingCommentsOfPosition,
emitLeadingComments,
emitTrailingComments,
emitDetachedComments
} = comments;
let context: TransformationContext;
let startLexicalEnvironment: () => void;
@@ -233,14 +251,22 @@ const _super = (function (geti, seti) {
}
function emit(node: Node) {
emitWithWorker(node, emitWorker);
}
function emitExpression(node: Expression) {
emitWithWorker(node, emitExpressionWorker);
}
function emitWithWorker(node: Node, emitWorker: (node: Node) => void) {
if (node) {
const adviseOnEmit = isEmitNotificationEnabled(node);
if (adviseOnEmit && onBeforeEmitNode) {
onBeforeEmitNode(node);
}
const leadingComments = getLeadingCommentsToEmit(node);
const trailingComments = getTrailingCommentsToEmit(node);
const leadingComments = getLeadingComments(node, getNotEmittedParent);
const trailingComments = getTrailingComments(node, getNotEmittedParent);
emitLeadingComments(node, leadingComments);
emitStart(node);
emitWorker(node);
@@ -253,7 +279,18 @@ const _super = (function (geti, seti) {
}
}
function emitWorker(node: Node) {
function getNotEmittedParent(node: Node): Node {
if (getNodeEmitFlags(node) & NodeEmitFlags.EmitCommentsOfNotEmittedParent) {
const parent = getOriginalNode(node).parent;
if (getNodeEmitFlags(parent) & NodeEmitFlags.IsNotEmittedNode) {
return parent;
}
}
return undefined;
}
function emitWorker(node: Node): void {
const kind = node.kind;
switch (kind) {
// Pseudo-literals
@@ -358,7 +395,7 @@ const _super = (function (geti, seti) {
case SyntaxKind.ExpressionWithTypeArguments:
return emitExpressionWithTypeArguments(<ExpressionWithTypeArguments>node);
case SyntaxKind.ThisType:
return write("this");
return emitThisType(<ThisTypeNode>node);
case SyntaxKind.StringLiteralType:
return emitLiteral(<StringLiteralTypeNode>node);
@@ -374,7 +411,7 @@ const _super = (function (geti, seti) {
case SyntaxKind.TemplateSpan:
return emitTemplateSpan(<TemplateSpan>node);
case SyntaxKind.SemicolonClassElement:
return write(";");
return emitSemicolonClassElement(<SemicolonClassElement>node);
// Statements
case SyntaxKind.Block:
@@ -382,7 +419,7 @@ const _super = (function (geti, seti) {
case SyntaxKind.VariableStatement:
return emitVariableStatement(<VariableStatement>node);
case SyntaxKind.EmptyStatement:
return write(";");
return emitEmptyStatement(<EmptyStatement>node);
case SyntaxKind.ExpressionStatement:
return emitExpressionStatement(<ExpressionStatement>node);
case SyntaxKind.IfStatement:
@@ -501,23 +538,11 @@ const _super = (function (geti, seti) {
// JSDoc nodes (ignored)
}
if (isExpressionKind(kind)) {
if (isExpression(node)) {
return emitExpressionWorker(node);
}
}
function emitExpression(node: Expression) {
if (node) {
const leadingComments = getLeadingCommentsToEmit(node);
const trailingComments = getTrailingCommentsToEmit(node);
emitLeadingComments(node, leadingComments);
emitStart(node);
emitExpressionWorker(node);
emitEnd(node);
emitTrailingComments(node, trailingComments);
}
}
function emitExpressionWorker(node: Node) {
const kind = node.kind;
if (isExpressionSubstitutionEnabled(node) && tryEmitSubstitute(node, expressionSubstitution)) {
@@ -641,7 +666,7 @@ const _super = (function (geti, seti) {
const text = temporaryVariables[nodeId] || (temporaryVariables[nodeId] = makeTempVariableName(tempKindToFlags(node.tempKind)));
write(text);
}
else if (nodeIsSynthesized(node)) {
else if (nodeIsSynthesized(node) || !node.parent) {
if (getNodeEmitFlags(node) & NodeEmitFlags.UMDDefine) {
writeLines(umdHelper);
}
@@ -741,13 +766,13 @@ const _super = (function (geti, seti) {
emitModifiers(node, node.modifiers);
writeIfPresent(node.asteriskToken, "*");
emit(node.name);
emitSignatureAndBody(node);
emitSignatureAndBody(node, emitSignatureHead);
}
function emitConstructor(node: ConstructorDeclaration) {
emitModifiers(node, node.modifiers);
write("constructor");
emitSignatureAndBody(node);
emitSignatureAndBody(node, emitSignatureHead);
}
function emitAccessorDeclaration(node: AccessorDeclaration) {
@@ -755,7 +780,7 @@ const _super = (function (geti, seti) {
emitModifiers(node, node.modifiers);
write(node.kind === SyntaxKind.GetAccessor ? "get " : "set ");
emit(node.name);
emitSignatureAndBody(node);
emitSignatureAndBody(node, emitSignatureHead);
}
function emitCallSignature(node: CallSignatureDeclaration) {
@@ -785,6 +810,10 @@ const _super = (function (geti, seti) {
write(";");
}
function emitSemicolonClassElement(node: SemicolonClassElement) {
write(";");
}
//
// Types
//
@@ -851,6 +880,10 @@ const _super = (function (geti, seti) {
write(")");
}
function emitThisType(node: ThisTypeNode) {
write("this");
}
//
// Binding patterns
//
@@ -896,7 +929,7 @@ const _super = (function (geti, seti) {
write("[]");
}
else {
const preferNewLine = getNodeEmitFlags(node) & NodeEmitFlags.MultiLine ? ListFormat.PreferNewLine : ListFormat.None;
const preferNewLine = node.multiLine ? ListFormat.PreferNewLine : ListFormat.None;
emitExpressionList(node, elements, ListFormat.ArrayLiteralExpressionElements | preferNewLine);
}
}
@@ -907,7 +940,7 @@ const _super = (function (geti, seti) {
write("{}");
}
else {
const preferNewLine = getNodeEmitFlags(node) & NodeEmitFlags.MultiLine ? ListFormat.PreferNewLine : ListFormat.None;
const preferNewLine = node.multiLine ? ListFormat.PreferNewLine : ListFormat.None;
const allowTrailingComma = languageVersion >= ScriptTarget.ES5 ? ListFormat.AllowTrailingComma : ListFormat.None;
emitList(node, properties, ListFormat.ObjectLiteralExpressionProperties | allowTrailingComma | preferNewLine);
}
@@ -998,27 +1031,8 @@ const _super = (function (geti, seti) {
function emitArrowFunction(node: ArrowFunction) {
emitDecorators(node, node.decorators);
emitModifiers(node, node.modifiers);
const body = node.body;
if (isBlock(body)) {
const savedTempFlags = tempFlags;
tempFlags = 0;
startLexicalEnvironment();
emitArrowFunctionHead(node);
write(" {");
emitSignatureAndBody(node, emitArrowFunctionHead);
const startingLine = writer.getLine();
emitBlockFunctionBody(node, body);
const endingLine = writer.getLine();
emitLexicalEnvironment(endLexicalEnvironment(), /*newLine*/ startingLine !== endingLine);
tempFlags = savedTempFlags;
write("}");
}
else {
emitArrowFunctionHead(node);
write(" ");
emitExpression(body);
}
}
function emitArrowFunctionHead(node: ArrowFunction) {
@@ -1186,6 +1200,10 @@ const _super = (function (geti, seti) {
write(";");
}
function emitEmptyStatement(node: EmptyStatement) {
write(";");
}
function emitExpressionStatement(node: ExpressionStatement) {
emitExpression(node.expression);
write(";");
@@ -1353,25 +1371,27 @@ const _super = (function (geti, seti) {
emitModifiers(node, node.modifiers);
write(node.asteriskToken ? "function* " : "function ");
emit(node.name);
emitSignatureAndBody(node);
emitSignatureAndBody(node, emitSignatureHead);
}
function emitSignatureAndBody(node: FunctionDeclaration | FunctionExpression | MethodDeclaration | AccessorDeclaration | ConstructorDeclaration) {
function emitSignatureAndBody(node: FunctionLikeDeclaration, emitSignatureHead: (node: SignatureDeclaration) => void) {
const body = node.body;
if (body) {
const savedTempFlags = tempFlags;
tempFlags = 0;
startLexicalEnvironment();
emitSignatureHead(node);
write(" {");
const startingLine = writer.getLine();
emitBlockFunctionBody(node, body);
const endingLine = writer.getLine();
emitLexicalEnvironment(endLexicalEnvironment(), /*newLine*/ startingLine !== endingLine);
write("}");
tempFlags = savedTempFlags;
if (isBlock(body)) {
const savedTempFlags = tempFlags;
tempFlags = 0;
startLexicalEnvironment();
emitSignatureHead(node);
write(" {");
emitBlockFunctionBody(node, body);
write("}");
tempFlags = savedTempFlags;
}
else {
emitSignatureHead(node);
write(" ");
emitExpression(body);
}
}
else {
emitSignatureHead(node);
@@ -1388,37 +1408,49 @@ const _super = (function (geti, seti) {
function shouldEmitBlockFunctionBodyOnSingleLine(parentNode: Node, body: Block) {
const originalNode = getOriginalNode(parentNode);
if (isFunctionLike(originalNode) && !nodeIsSynthesized(originalNode) && rangeEndIsOnSameLineAsRangeStart(originalNode.body, originalNode.body)) {
for (const statement of body.statements) {
if (synthesizedNodeStartsOnNewLine(statement)) {
return false;
if (isFunctionLike(originalNode) && !nodeIsSynthesized(originalNode)) {
const body = originalNode.body;
if (isBlock(body)) {
if (rangeEndIsOnSameLineAsRangeStart(body, body)) {
for (const statement of body.statements) {
if (synthesizedNodeStartsOnNewLine(statement)) {
return false;
}
}
return true;
}
}
if (originalNode.kind === SyntaxKind.ArrowFunction && !rangeEndIsOnSameLineAsRangeStart((<ArrowFunction>originalNode).equalsGreaterThanToken, originalNode.body)) {
return false;
else {
return rangeEndIsOnSameLineAsRangeStart((<ArrowFunction>originalNode).equalsGreaterThanToken, originalNode.body);
}
return true;
}
return false;
}
function emitBlockFunctionBody(parentNode: Node, body: Block) {
// Emit all the prologue directives (like "use strict").
const startingLine = writer.getLine();
increaseIndent();
const statements = body.statements;
const statementOffset = emitPrologueDirectives(statements, /*startWithNewLine*/ true);
emitDetachedComments(body.statements);
// Emit all the prologue directives (like "use strict").
const statementOffset = emitPrologueDirectives(body.statements, /*startWithNewLine*/ true);
const helpersEmitted = emitHelpers(body);
decreaseIndent();
if (statementOffset === 0 && !helpersEmitted && shouldEmitBlockFunctionBodyOnSingleLine(parentNode, body)) {
emitList(body, statements, ListFormat.SingleLineFunctionBodyStatements);
decreaseIndent();
emitList(body, body.statements, ListFormat.SingleLineFunctionBodyStatements);
increaseIndent();
}
else {
emitList(body, statements, ListFormat.MultiLineFunctionBodyStatements, statementOffset);
emitList(body, body.statements, ListFormat.MultiLineFunctionBodyStatements, statementOffset);
}
const endingLine = writer.getLine();
emitLexicalEnvironment(endLexicalEnvironment(), /*newLine*/ startingLine !== endingLine);
emitLeadingComments(collapseTextRange(body.statements, TextRangeCollapse.CollapseToEnd));
decreaseIndent();
}
function emitClassDeclaration(node: ClassDeclaration) {
@@ -1688,6 +1720,8 @@ const _super = (function (geti, seti) {
write("case ");
emitExpression(node.expression);
write(":");
debugger;
emitCaseOrDefaultClauseStatements(node, node.statements);
}
@@ -2051,8 +2085,10 @@ const _super = (function (geti, seti) {
}
else {
// Write the opening line terminator or leading whitespace.
let shouldEmitInterveningComments = true;
if (shouldWriteLeadingLineTerminator(parentNode, children, format)) {
writeLine();
shouldEmitInterveningComments = false;
}
else if (format & ListFormat.SpaceBetweenBraces) {
write(" ");
@@ -2076,12 +2112,20 @@ const _super = (function (geti, seti) {
// Write either a line terminator or whitespace to separate the elements.
if (shouldWriteSeparatingLineTerminator(previousSibling, child, format)) {
writeLine();
shouldEmitInterveningComments = false;
}
else if (previousSibling) {
write(" ");
}
}
if (shouldEmitInterveningComments) {
emitLeadingComments(child, getTrailingCommentsOfPosition(child.pos));
}
else {
shouldEmitInterveningComments = true;
}
// Emit this child.
emit(child);
@@ -2175,7 +2219,7 @@ const _super = (function (geti, seti) {
return true;
}
else if (format & ListFormat.PreserveLines) {
if (getNodeEmitFlags(parentNode) & NodeEmitFlags.MultiLine) {
if (format & ListFormat.PreferNewLine) {
return true;
}
@@ -2217,10 +2261,10 @@ const _super = (function (geti, seti) {
function shouldWriteClosingLineTerminator(parentNode: Node, children: NodeArray<Node>, format: ListFormat) {
if (format & ListFormat.MultiLine) {
return true;
return (format & ListFormat.NoTrailingNewLine) === 0;
}
else if (format & ListFormat.PreserveLines) {
if (getNodeEmitFlags(parentNode) & NodeEmitFlags.MultiLine) {
if (format & ListFormat.PreferNewLine) {
return true;
}
@@ -2242,7 +2286,7 @@ const _super = (function (geti, seti) {
function synthesizedNodeStartsOnNewLine(node: Node, format?: ListFormat) {
if (nodeIsSynthesized(node)) {
const startsOnNewLine = (<SynthesizedNode>node).startsOnNewLine;
const startsOnNewLine = node.startsOnNewLine;
if (startsOnNewLine === undefined) {
return (format & ListFormat.PreferNewLine) !== 0;
}
@@ -2274,8 +2318,12 @@ const _super = (function (geti, seti) {
}
function needsIndentation(parent: Node, node1: Node, node2: Node): boolean {
parent = skipSynthesizedParentheses(parent);
node1 = skipSynthesizedParentheses(node1);
node2 = skipSynthesizedParentheses(node2);
// Always use a newline for synthesized code if the synthesizer desires it.
if (synthesizedNodeStartsOnNewLine(node2)) {
if (node2.startsOnNewLine) {
return true;
}
@@ -2285,6 +2333,14 @@ const _super = (function (geti, seti) {
&& !rangeEndIsOnSameLineAsRangeStart(node1, node2);
}
function skipSynthesizedParentheses(node: Node) {
while (node.kind === SyntaxKind.ParenthesizedExpression && nodeIsSynthesized(node)) {
node = (<ParenthesizedExpression>node).expression;
}
return node;
}
function getTextOfNode(node: Node, includeTrivia?: boolean) {
if (nodeIsSynthesized(node) && (isLiteralExpression(node) || isIdentifier(node))) {
return node.text;
@@ -2304,9 +2360,9 @@ const _super = (function (geti, seti) {
}
function isSingleLineEmptyBlock(block: Block) {
return (getNodeEmitFlags(block) & NodeEmitFlags.MultiLine) === 0 &&
block.statements.length === 0 &&
rangeEndIsOnSameLineAsRangeStart(block, block);
return !block.multiLine
&& block.statements.length === 0
&& rangeEndIsOnSameLineAsRangeStart(block, block);
}
function tempKindToFlags(kind: TempVariableKind) {
@@ -2361,7 +2417,7 @@ const _super = (function (geti, seti) {
function createBracketsMap() {
const brackets: string[][] = [];
brackets[ListFormat.Braces] = ["{", "}"];
brackets[ListFormat.Parenthesis] = ["(", ")"];
brackets[ListFormat.Parenthesis] = ["(",")"];
brackets[ListFormat.AngleBrackets] = ["<", ">"];
brackets[ListFormat.SquareBrackets] = ["[", "]"];
return brackets;
@@ -2407,6 +2463,7 @@ const _super = (function (geti, seti) {
// Other
PreferNewLine = 1 << 15, // Prefer adding a LineTerminator between synthesized nodes.
NoTrailingNewLine = 1 << 16, // Do not emit a trailing NewLine for a MultiLine list.
// Precomputed Formats
TypeLiteralMembers = MultiLine | Indented,
@@ -2424,7 +2481,7 @@ const _super = (function (geti, seti) {
MultiLineBlockStatements = Indented | MultiLine,
VariableDeclarationList = CommaDelimited | SingleLine,
SingleLineFunctionBodyStatements = SingleLine | SpaceBetweenBraces,
MultiLineFunctionBodyStatements = MultiLine | Indented,
MultiLineFunctionBodyStatements = MultiLine,
ClassHeritageClauses = SingleLine,
ClassMembers = Indented | MultiLine,
InterfaceMembers = Indented | MultiLine,
@@ -2433,9 +2490,9 @@ const _super = (function (geti, seti) {
NamedImportsOrExportsElements = CommaDelimited | AllowTrailingComma | SingleLine | SpaceBetweenBraces,
JsxElementChildren = SingleLine,
JsxElementAttributes = SingleLine,
CaseOrDefaultClauseStatements = Indented | MultiLine,
CaseOrDefaultClauseStatements = Indented | MultiLine | NoTrailingNewLine | OptionalIfEmpty,
HeritageClauseTypes = CommaDelimited | SingleLine,
SourceFileStatements = MultiLine,
SourceFileStatements = MultiLine | NoTrailingNewLine,
Decorators = MultiLine | Optional,
TypeArguments = CommaDelimited | SingleLine | Indented | AngleBrackets | Optional,
TypeParameters = CommaDelimited | SingleLine | Indented | AngleBrackets | Optional,
+1 -1
View File
@@ -968,7 +968,7 @@ namespace ts {
const start = new Date().getTime();
const emitResult = emitFiles(
const emitResult = (options.experimentalTransforms ? printFiles : emitFiles)(
emitResolver,
getEmitHost(writeFileCallback),
sourceFile);
+2 -3
View File
@@ -433,9 +433,7 @@ namespace ts {
/* @internal */
export function skipTrivia(text: string, pos: number, stopAfterLineBreak?: boolean): number {
// Using ! with a greater than test is a fast way of testing the following conditions:
// pos === undefined || pos === null || isNaN(pos) || pos < 0;
if (!(pos >= 0)) {
if (positionIsSynthesized(pos)) {
return pos;
}
@@ -642,6 +640,7 @@ namespace ts {
pos++;
}
}
if (collecting) {
if (!result) {
result = [];
+2 -2
View File
@@ -310,13 +310,13 @@ namespace ts {
function emitStart(range: TextRange) {
emitPos(getStartPos(range));
if ((<SynthesizedNode>range).disableSourceMap) {
if (range.disableSourceMap) {
disable();
}
}
function emitEnd(range: TextRange, stopOverridingEnd?: boolean) {
if ((<SynthesizedNode>range).disableSourceMap) {
if (range.disableSourceMap) {
enable();
}
+6 -1
View File
@@ -84,8 +84,12 @@ namespace ts {
hoistFunctionDeclaration,
startLexicalEnvironment,
endLexicalEnvironment,
identifierSubstitution: node => node,
expressionSubstitution: node => node,
enableExpressionSubstitution,
isExpressionSubstitutionEnabled,
onBeforeEmitNode: node => { },
onAfterEmitNode: node => { },
enableEmitNotification,
isEmitNotificationEnabled,
};
@@ -148,8 +152,9 @@ namespace ts {
/**
* Sets flags that control emit behavior of a node.
*/
function setNodeEmitFlags(node: Node, flags: NodeEmitFlags) {
function setNodeEmitFlags<T extends Node>(node: T, flags: NodeEmitFlags) {
nodeEmitFlags[getNodeId(node)] = flags;
return node;
}
/**
+5 -5
View File
@@ -50,7 +50,7 @@ namespace ts {
function emitAssignment(name: Identifier, value: Expression, location: TextRange) {
const expression = createAssignment(name, value, location);
if (isSimpleExpression(value)) {
(<SynthesizedNode>expression).disableSourceMap = true;
expression.disableSourceMap = true;
}
aggregateTransformFlags(expression);
@@ -82,7 +82,7 @@ namespace ts {
function emitAssignment(name: Identifier, value: Expression, location: TextRange) {
const declaration = createVariableDeclaration(name, value, location);
if (isSimpleExpression(value)) {
(<SynthesizedNode>declaration).disableSourceMap = true;
declaration.disableSourceMap = true;
}
aggregateTransformFlags(declaration);
@@ -117,7 +117,7 @@ namespace ts {
}
if (isSimpleExpression(value)) {
(<SynthesizedNode>declaration).disableSourceMap = true;
declaration.disableSourceMap = true;
}
declaration.original = original;
@@ -169,7 +169,7 @@ namespace ts {
function emitPendingAssignment(name: Expression, value: Expression, location: TextRange, original: Node) {
const expression = createAssignment(name, value, location);
if (isSimpleExpression(value)) {
(<SynthesizedNode>expression).disableSourceMap = true;
expression.disableSourceMap = true;
}
expression.original = original;
@@ -199,7 +199,7 @@ namespace ts {
function emitDestructuringAssignment(bindingTarget: Expression | ShorthandPropertyAssignment, value: Expression, location: TextRange) {
// When emitting target = value use source map node to highlight, including any temporary assignments needed for this
let target: Expression;
if (isShortHandPropertyAssignment(bindingTarget)) {
if (isShorthandPropertyAssignment(bindingTarget)) {
const initializer = visitor
? visitNode(bindingTarget.objectAssignmentInitializer, visitor, isExpression)
: bindingTarget.objectAssignmentInitializer;
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -30,7 +30,7 @@ namespace ts {
return visitBinaryExpression(<BinaryExpression>node);
}
Debug.fail("Unexpected node kind.");
Debug.fail(`Unexpected node kind: ${formatSyntaxKind(node.kind)}.`);
}
function visitBinaryExpression(node: BinaryExpression): Expression {
@@ -90,7 +90,7 @@ namespace ts {
return createMathPow(left, right, /*location*/ node);
}
else {
Debug.fail("Unexpected node kind.");
Debug.fail(`Unexpected operator kind: ${formatSyntaxKind(node.operatorToken.kind)}.`);
}
}
}
+4 -4
View File
@@ -34,7 +34,7 @@ namespace ts {
return visitJsxSelfClosingElement(<JsxSelfClosingElement>node);
}
Debug.fail("Unexpected node kind.");
Debug.fail(`Unexpected node kind: ${formatSyntaxKind(node.kind)}.`);
}
function transformJsxChildToExpression(node: JsxChild): Expression {
@@ -52,7 +52,7 @@ namespace ts {
return visitJsxSelfClosingElement(<JsxSelfClosingElement>node);
}
Debug.fail("Unexpected node kind.");
Debug.fail(`Unexpected node kind: ${formatSyntaxKind(node.kind)}.`);
}
function visitJsxElement(node: JsxElement) {
@@ -85,14 +85,14 @@ namespace ts {
properties = undefined;
}
addNode(segments, transformJsxSpreadAttributeToExpression(attr), isExpression);
addNode(segments, transformJsxSpreadAttributeToExpression(attr));
}
else {
if (!properties) {
properties = [];
}
addNode(properties, transformJsxAttributeToObjectLiteralElement(attr), isObjectLiteralElement);
addNode(properties, transformJsxAttributeToObjectLiteralElement(attr));
}
}
+108 -39
View File
@@ -31,14 +31,17 @@ namespace ts {
context.onBeforeEmitNode = onBeforeEmitNode;
context.onAfterEmitNode = onAfterEmitNode;
let hasEnabledExpressionSubstitutionForAsyncMethodsWithSuper = false;
let currentSourceFile: SourceFile;
let currentNamespace: ModuleDeclaration;
let currentNamespaceLocalName: Identifier;
let currentScope: SourceFile | Block | ModuleBlock | CaseBlock;
let currentParent: Node;
let currentNode: Node;
let combinedNodeFlags: NodeFlags;
let isRightmostExpression: boolean;
// This stack is is used to support substitutions when printing nodes.
let hasEnabledExpressionSubstitutionForAsyncMethodsWithSuper = false;
let superContainerStack: SuperContainer[];
return transformSourceFile;
@@ -61,6 +64,7 @@ namespace ts {
const savedCurrentScope = currentScope;
const savedCurrentParent = currentParent;
const savedCurrentNode = currentNode;
const savedCombinedNodeFlags = combinedNodeFlags;
const savedIsRightmostExpression = isRightmostExpression;
onBeforeVisitNode(node);
node = visitor(node);
@@ -68,6 +72,7 @@ namespace ts {
currentScope = savedCurrentScope;
currentParent = savedCurrentParent;
currentNode = savedCurrentNode;
combinedNodeFlags = savedCombinedNodeFlags;
isRightmostExpression = savedIsRightmostExpression;
return node;
}
@@ -290,7 +295,7 @@ namespace ts {
case SyntaxKind.TypeAssertionExpression:
case SyntaxKind.AsExpression:
// TypeScript type assertions are removed, but their subtrees are preserved.
return visitNode((<TypeAssertion | AsExpression>node).expression, visitor, isExpression);
return visitAssertionExpression(<AssertionExpression>node);
case SyntaxKind.EnumDeclaration:
// TypeScript enum declarations do not exist in ES6 and must be rewritten.
@@ -313,7 +318,7 @@ namespace ts {
return visitImportEqualsDeclaration(<ImportEqualsDeclaration>node);
default:
Debug.fail("Unexpected node.");
Debug.fail(`Unexpected node kind: ${formatSyntaxKind(node.kind)}.`);
break;
}
}
@@ -326,6 +331,9 @@ namespace ts {
function onBeforeVisitNode(node: Node) {
currentParent = currentNode;
currentNode = node;
combinedNodeFlags = combineNodeFlags(currentNode, currentParent, combinedNodeFlags);
switch (node.kind) {
case SyntaxKind.SourceFile:
case SyntaxKind.CaseBlock:
@@ -357,7 +365,7 @@ namespace ts {
const statements: Statement[] = [];
const modifiers = visitNodes(node.modifiers, visitor, isModifier);
const heritageClauses = visitNodes(node.heritageClauses, visitor, isHeritageClause);
const members = transformClassMembers(node, heritageClauses !== undefined);
const members = transformClassMembers(node, firstOrUndefined(heritageClauses) !== undefined);
let decoratedClassAlias: Identifier;
// emit name if
@@ -744,7 +752,10 @@ namespace ts {
// End the lexical environment.
addNodes(statements, endLexicalEnvironment());
return createBlock(statements);
return setMultiLine(
createBlock(statements, constructor ? constructor.body : undefined),
true
);
}
/**
@@ -855,7 +866,17 @@ namespace ts {
* @param receiver The receiver on which each property should be assigned.
*/
function generateInitializedPropertyStatements(node: ClassExpression | ClassDeclaration, properties: PropertyDeclaration[], receiver: LeftHandSideExpression) {
return map(generateInitializedPropertyExpressions(node, properties, receiver), expressionToStatement);
const statements: Statement[] = [];
for (const property of properties) {
statements.push(
createStatement(
transformInitializedProperty(node, property, receiver),
/*location*/ property
)
);
}
return statements;
}
/**
@@ -868,8 +889,9 @@ namespace ts {
function generateInitializedPropertyExpressions(node: ClassExpression | ClassDeclaration, properties: PropertyDeclaration[], receiver: LeftHandSideExpression) {
const expressions: Expression[] = [];
for (const property of properties) {
expressions.push(transformInitializedProperty(node, property, receiver));
expressions.push(transformInitializedProperty(node, property, receiver, /*location*/ property));
}
return expressions;
}
@@ -880,12 +902,13 @@ namespace ts {
* @param property The property declaration.
* @param receiver The object receiving the property assignment.
*/
function transformInitializedProperty(node: ClassExpression | ClassDeclaration, property: PropertyDeclaration, receiver: LeftHandSideExpression) {
function transformInitializedProperty(node: ClassExpression | ClassDeclaration, property: PropertyDeclaration, receiver: LeftHandSideExpression, location?: TextRange) {
const propertyName = visitPropertyNameOfClassElement(property);
const initializer = visitNode(property.initializer, visitor, isExpression);
return createAssignment(
createMemberAccessForPropertyName(receiver, propertyName),
initializer
initializer,
location
);
}
@@ -1467,7 +1490,7 @@ namespace ts {
break;
default:
Debug.fail("Cannot serialize unexpected type node.");
Debug.fail(`Unexpected node kind: ${formatSyntaxKind(node.kind)}.`);
break;
}
@@ -2053,7 +2076,8 @@ namespace ts {
return createStatement(
inlineExpressions(
map(variables, transformInitializedVariable)
)
),
/*location*/ node
);
}
@@ -2113,7 +2137,10 @@ namespace ts {
location = undefined;
}
const namespaceMemberName = getNamespaceMemberName(node.name);
const name = isNamespaceExport(node)
? getNamespaceMemberName(node.name)
: getSynthesizedNode(node.name);
currentNamespaceLocalName = getGeneratedNameForNode(node);
addNode(statements,
createStatement(
@@ -2127,9 +2154,9 @@ namespace ts {
)
),
[createLogicalOr(
namespaceMemberName,
name,
createAssignment(
namespaceMemberName,
name,
createObjectLiteral()
)
)]
@@ -2143,7 +2170,7 @@ namespace ts {
createVariableStatement(
/*modifiers*/ undefined,
createVariableDeclarationList([
createVariableDeclaration(node.name, namespaceMemberName)
createVariableDeclaration(node.name, name)
]),
location
)
@@ -2229,12 +2256,20 @@ namespace ts {
* @param node The await expression node.
*/
function visitAwaitExpression(node: AwaitExpression): Expression {
const expression = createYield(
visitNode(node.expression, visitor, isExpression),
const expression = setOriginalNode(
createYield(
visitNode(node.expression, visitor, isExpression),
node
),
node
);
return isRightmostExpression ? expression : createParen(expression);
return isRightmostExpression
? expression
: setOriginalNode(
createParen(expression, /*location*/ node),
node
);
}
/**
@@ -2265,11 +2300,29 @@ namespace ts {
!(expression.kind === SyntaxKind.CallExpression && currentParent.kind === SyntaxKind.NewExpression) &&
!(expression.kind === SyntaxKind.FunctionExpression && currentParent.kind === SyntaxKind.CallExpression) &&
!(expression.kind === SyntaxKind.NumericLiteral && currentParent.kind === SyntaxKind.PropertyAccessExpression)) {
return expression;
return trackChildOfNotEmittedNode(node, expression, node.expression);
}
}
return createParen(expression, node);
return setOriginalNode(
createParen(expression, node),
node
);
}
function visitAssertionExpression(node: AssertionExpression): Expression {
const expression = visitNode((<TypeAssertion | AsExpression>node).expression, visitor, isExpression);
return trackChildOfNotEmittedNode(node, expression, node.expression);
}
function trackChildOfNotEmittedNode<T extends Node>(parent: Node, child: T, original: T) {
if (!child.parent && !child.original) {
child = cloneNode(child, child, child.flags, child.parent, original);
}
setNodeEmitFlags(parent, NodeEmitFlags.IsNotEmittedNode);
setNodeEmitFlags(child, NodeEmitFlags.EmitCommentsOfNotEmittedParent);
return child;
}
/**
@@ -2305,10 +2358,14 @@ namespace ts {
location = undefined;
}
const name = isNamespaceExport(node)
? getNamespaceMemberName(node.name)
: getSynthesizedNode(node.name);
let moduleParam: Expression = createLogicalOr(
getNamespaceMemberName(node.name),
name,
createAssignment(
getNamespaceMemberName(node.name),
name,
createObjectLiteral([])
)
);
@@ -2515,13 +2572,10 @@ namespace ts {
}
function getNamespaceMemberName(name: Identifier): Expression {
name = getSynthesizedNode(name);
return currentNamespaceLocalName
? createPropertyAccess(currentNamespaceLocalName, name)
: name
return createPropertyAccess(currentNamespaceLocalName, getSynthesizedNode(name));
}
function getDeclarationName(node: ClassExpression | ClassDeclaration | FunctionDeclaration) {
function getDeclarationName(node: ClassExpression | ClassDeclaration | FunctionDeclaration | EnumDeclaration) {
return node.name ? getSynthesizedNode(node.name) : getGeneratedNameForNode(node);
}
@@ -2536,7 +2590,7 @@ namespace ts {
}
function substituteExpression(node: Expression): Expression {
node = previousExpressionSubstitution ? previousExpressionSubstitution(node) : node;
node = previousExpressionSubstitution(node);
switch (node.kind) {
case SyntaxKind.Identifier:
return substituteExpressionIdentifier(<Identifier>node);
@@ -2556,19 +2610,30 @@ namespace ts {
return node;
}
function substituteExpressionIdentifier(node: Identifier) {
if (!nodeIsSynthesized(node) && resolver.getNodeCheckFlags(node) & NodeCheckFlags.BodyScopedClassBinding) {
// Due to the emit for class decorators, any reference to the class from inside of the class body
// must instead be rewritten to point to a temporary variable to avoid issues with the double-bind
// behavior of class names in ES6.
const original = getOriginalNode(node);
const declaration = resolver.getReferencedValueDeclaration(isIdentifier(original) ? original : node);
if (declaration) {
const classAlias = currentDecoratedClassAliases[getNodeId(declaration)];
if (classAlias) {
return cloneNode(classAlias);
function substituteExpressionIdentifier(node: Identifier): Expression {
const original = getOriginalNode(node);
if (isIdentifier(original)) {
if (resolver.getNodeCheckFlags(original) & NodeCheckFlags.BodyScopedClassBinding) {
// Due to the emit for class decorators, any reference to the class from inside of the class body
// must instead be rewritten to point to a temporary variable to avoid issues with the double-bind
// behavior of class names in ES6.
const declaration = resolver.getReferencedValueDeclaration(original);
if (declaration) {
const classAlias = currentDecoratedClassAliases[getNodeId(declaration)];
if (classAlias) {
return cloneNode(classAlias);
}
}
}
const container = resolver.getReferencedExportContainer(original);
if (container && container.kind === SyntaxKind.ModuleDeclaration) {
return createPropertyAccess(
getGeneratedNameForNode(container),
cloneNode(node),
/*location*/ node
);
}
}
return node;
@@ -2652,6 +2717,8 @@ namespace ts {
}
function onBeforeEmitNode(node: Node): void {
previousOnAfterEmitNode(node);
const kind = node.kind;
if (kind === SyntaxKind.ClassDeclaration && node.decorators) {
currentDecoratedClassAliases[getOriginalNodeId(node)] = decoratedClassAliases[getOriginalNodeId(node)];
@@ -2673,6 +2740,8 @@ namespace ts {
}
function onAfterEmitNode(node: Node): void {
previousOnAfterEmitNode(node);
const kind = node.kind;
if (kind === SyntaxKind.ClassDeclaration && node.decorators) {
currentDecoratedClassAliases[getOriginalNodeId(node)] = undefined;
+21 -15
View File
@@ -20,6 +20,7 @@ namespace ts {
export interface TextRange {
pos: number;
end: number;
/* @internal */ disableSourceMap?: boolean; // Whether a synthesized text range disables source maps for its contents (used by transforms).
}
// token > SyntaxKind.Identifer => token is a keyword
@@ -449,6 +450,7 @@ namespace ts {
/* @internal */ id?: number; // Unique id (used to look up NodeLinks)
parent?: Node; // Parent node (initialized by binding)
/* @internal */ original?: Node; // The original node if this is an updated node.
/* @internal */ startsOnNewLine?: boolean; // Whether a synthesized node should start on a new line (used by transforms).
/* @internal */ jsDocComment?: JSDocComment; // JSDoc for the node, if it has any. Only for .js files.
/* @internal */ symbol?: Symbol; // Symbol declared by node (initialized by binding)
/* @internal */ locals?: SymbolTable; // Locals associated with node (initialized by binding)
@@ -1124,6 +1126,7 @@ namespace ts {
// @kind(SyntaxKind.Block)
export interface Block extends Statement {
statements: NodeArray<Statement>;
multiLine?: boolean;
}
// @kind(SyntaxKind.VariableStatement)
@@ -2466,6 +2469,7 @@ namespace ts {
allowSyntheticDefaultImports?: boolean;
allowJs?: boolean;
/* @internal */ stripInternal?: boolean;
/* @internal */ experimentalTransforms?: boolean;
// Skip checking lib.d.ts to help speed up tests.
/* @internal */ skipDefaultLibCheck?: boolean;
@@ -2767,6 +2771,7 @@ namespace ts {
ContainsParameterPropertyAssignments = 1 << 13,
ContainsSpreadElementExpression = 1 << 14,
ContainsComputedPropertyName = 1 << 15,
ContainsBlockScopedBinding = 1 << 16,
// Assertions
// - Bitmasks that are used to assert facts about the syntax of a node and its subtree.
@@ -2779,12 +2784,12 @@ namespace ts {
// - Bitmasks that exclude flags from propagating out of a specific context
// into the subtree flags of their container.
NodeExcludes = TypeScript | Jsx | ES7 | ES6,
ArrowFunctionExcludes = ContainsDecorators | ContainsDefaultValueAssignments | ContainsLexicalThis | ContainsParameterPropertyAssignments,
FunctionExcludes = ContainsDecorators | ContainsDefaultValueAssignments | ContainsCapturedLexicalThis | ContainsLexicalThis | ContainsParameterPropertyAssignments,
ConstructorExcludes = ContainsDefaultValueAssignments | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsParameterPropertyAssignments,
MethodOrAccessorExcludes = ContainsDefaultValueAssignments | ContainsLexicalThis | ContainsCapturedLexicalThis,
ArrowFunctionExcludes = ContainsDecorators | ContainsDefaultValueAssignments | ContainsLexicalThis | ContainsParameterPropertyAssignments | ContainsBlockScopedBinding,
FunctionExcludes = ContainsDecorators | ContainsDefaultValueAssignments | ContainsCapturedLexicalThis | ContainsLexicalThis | ContainsParameterPropertyAssignments | ContainsBlockScopedBinding,
ConstructorExcludes = ContainsDefaultValueAssignments | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsBlockScopedBinding,
MethodOrAccessorExcludes = ContainsDefaultValueAssignments | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsBlockScopedBinding,
ClassExcludes = ContainsDecorators | ContainsPropertyInitializer | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsComputedPropertyName | ContainsParameterPropertyAssignments,
ModuleExcludes = ContainsDecorators | ContainsLexicalThis | ContainsCapturedLexicalThis,
ModuleExcludes = ContainsDecorators | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsBlockScopedBinding,
TypeExcludes = ~ContainsTypeScript,
ObjectLiteralExcludes = ContainsDecorators | ContainsComputedPropertyName,
ArrayLiteralOrCallOrNewExcludes = ContainsSpreadElementExpression,
@@ -2792,15 +2797,16 @@ namespace ts {
/* @internal */
export const enum NodeEmitFlags {
EmitEmitHelpers = 1 << 0, // Any emit helpers should be written to this node.
EmitExportStar = 1 << 1, // The export * helper should be written to this node.
EmitSuperHelper = 1 << 2, // Emit the basic _super helper for async methods.
EmitAdvancedSuperHelper = 1 << 3, // Emit the advanced _super helper for async methods.
UMDDefine = 1 << 4, // This node should be replaced with the UMD define helper.
NoLexicalEnvironment = 1 << 5, // A new LexicalEnvironment should *not* be introduced when emitting this node, this is primarily used when printing a SystemJS module.
SingleLine = 1 << 6, // The contents of this node should be emit on a single line.
MultiLine = 1 << 7, // The contents of this node should be emit on multiple lines.
AdviseOnEmitNode = 1 << 8, // The node printer should invoke the onBeforeEmitNode and onAfterEmitNode callbacks when printing this node.
EmitEmitHelpers = 1 << 0, // Any emit helpers should be written to this node.
EmitExportStar = 1 << 1, // The export * helper should be written to this node.
EmitSuperHelper = 1 << 2, // Emit the basic _super helper for async methods.
EmitAdvancedSuperHelper = 1 << 3, // Emit the advanced _super helper for async methods.
UMDDefine = 1 << 4, // This node should be replaced with the UMD define helper.
NoLexicalEnvironment = 1 << 5, // A new LexicalEnvironment should *not* be introduced when emitting this node, this is primarily used when printing a SystemJS module.
SingleLine = 1 << 6, // The contents of this node should be emit on a single line.
AdviseOnEmitNode = 1 << 7, // The node printer should invoke the onBeforeEmitNode and onAfterEmitNode callbacks when printing this node.
IsNotEmittedNode = 1 << 8, // Is a node that is not emitted but whose comments should be preserved if possible.
EmitCommentsOfNotEmittedParent = 1 << 8, // Emits comments of missing parent nodes.
}
/** Additional context provided to `visitEachChild` */
@@ -2817,7 +2823,7 @@ namespace ts {
getCompilerOptions(): CompilerOptions;
getEmitResolver(): EmitResolver;
getNodeEmitFlags(node: Node): NodeEmitFlags;
setNodeEmitFlags(node: Node, flags: NodeEmitFlags): void;
setNodeEmitFlags<T extends Node>(node: T, flags: NodeEmitFlags): T;
hoistFunctionDeclaration(node: FunctionDeclaration): void;
hoistVariableDeclaration(node: Identifier): void;
isUniqueName(name: string): boolean;
+122 -64
View File
@@ -8,13 +8,6 @@ namespace ts {
isNoDefaultLib?: boolean;
}
export interface SynthesizedNode extends Node {
leadingCommentRanges?: CommentRange[];
trailingCommentRanges?: CommentRange[];
startsOnNewLine?: boolean;
disableSourceMap?: boolean;
}
export function getDeclarationOfKind(symbol: Symbol, kind: SyntaxKind): Declaration {
const declarations = symbol.declarations;
if (declarations) {
@@ -330,8 +323,7 @@ namespace ts {
export function isBlockScopedContainerTopLevel(node: Node): boolean {
return node.kind === SyntaxKind.SourceFile ||
node.kind === SyntaxKind.ModuleDeclaration ||
isFunctionLike(node) ||
isFunctionBlock(node);
isFunctionLike(node);
}
export function isGlobalScopeAugmentation(module: ModuleDeclaration): boolean {
@@ -354,30 +346,41 @@ namespace ts {
return false;
}
export function isBlockScope(node: Node, parentNode: Node) {
switch (node.kind) {
case SyntaxKind.SourceFile:
case SyntaxKind.CaseBlock:
case SyntaxKind.CatchClause:
case SyntaxKind.ModuleDeclaration:
case SyntaxKind.ForStatement:
case SyntaxKind.ForInStatement:
case SyntaxKind.ForOfStatement:
case SyntaxKind.Constructor:
case SyntaxKind.MethodDeclaration:
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.FunctionExpression:
case SyntaxKind.ArrowFunction:
return true;
case SyntaxKind.Block:
// function block is not considered block-scope container
// see comment in binder.ts: bind(...), case for SyntaxKind.Block
return parentNode && !isFunctionLike(parentNode);
}
return false;
}
// Gets the nearest enclosing block scope container that has the provided node
// as a descendant, that is not the provided node.
export function getEnclosingBlockScopeContainer(node: Node): Node {
let current = node.parent;
while (current) {
if (isFunctionLike(current)) {
if (isBlockScope(current, current.parent)) {
return current;
}
switch (current.kind) {
case SyntaxKind.SourceFile:
case SyntaxKind.CaseBlock:
case SyntaxKind.CatchClause:
case SyntaxKind.ModuleDeclaration:
case SyntaxKind.ForStatement:
case SyntaxKind.ForInStatement:
case SyntaxKind.ForOfStatement:
return current;
case SyntaxKind.Block:
// function block is not considered block-scope container
// see comment in binder.ts: bind(...), case for SyntaxKind.Block
if (!isFunctionLike(current.parent)) {
return current;
}
}
current = current.parent;
}
@@ -488,6 +491,19 @@ namespace ts {
return node;
}
/**
* Combines the flags of a node with the combined flags of its parent if they can be combined.
*/
export function combineNodeFlags(node: Node, parentNode: Node, previousNodeFlags: NodeFlags) {
if ((node.kind === SyntaxKind.VariableDeclarationList && parentNode.kind === SyntaxKind.VariableStatement) ||
(node.kind === SyntaxKind.VariableDeclaration && parentNode.kind === SyntaxKind.VariableDeclarationList) ||
(node.kind === SyntaxKind.BindingElement)) {
return node.flags | previousNodeFlags;
}
return node.flags;
}
// Returns the node flags for this node and all relevant parent nodes. This is done so that
// nodes like variable declarations and binding elements can returned a view of their flags
// that includes the modifiers from their container. i.e. flags like export/declare aren't
@@ -1733,7 +1749,7 @@ namespace ts {
return getOperatorPrecedence(expression.kind, operator, hasArguments);
}
function getOperator(expression: Expression) {
export function getOperator(expression: Expression) {
if (expression.kind === SyntaxKind.BinaryExpression) {
return (<BinaryExpression>expression).operatorToken.kind;
}
@@ -2318,26 +2334,33 @@ namespace ts {
}
}
export function emitComments(text: string, lineMap: number[], writer: EmitTextWriter, comments: CommentRange[], trailingSeparator: boolean, newLine: string,
export function emitComments(text: string, lineMap: number[], writer: EmitTextWriter, comments: CommentRange[], leadingSeparator: boolean, trailingSeparator: boolean, newLine: string,
writeComment: (text: string, lineMap: number[], writer: EmitTextWriter, comment: CommentRange, newLine: string) => void) {
let emitLeadingSpace = !trailingSeparator;
forEach(comments, comment => {
if (emitLeadingSpace) {
writer.write(" ");
emitLeadingSpace = false;
}
writeComment(text, lineMap, writer, comment, newLine);
if (comment.hasTrailingNewLine) {
writer.writeLine();
}
else if (trailingSeparator) {
if (comments && comments.length > 0) {
if (leadingSeparator) {
writer.write(" ");
}
else {
// Emit leading space to separate comment during next comment emit
emitLeadingSpace = true;
let emitInterveningSeperator = false;
for (const comment of comments) {
if (emitInterveningSeperator) {
writer.write(" ");
emitInterveningSeperator = false;
}
writeComment(text, lineMap, writer, comment, newLine);
if (comment.hasTrailingNewLine) {
writer.writeLine();
}
else {
emitInterveningSeperator = true;
}
}
});
if (emitInterveningSeperator && trailingSeparator) {
writer.write(" ");
}
}
}
/**
@@ -2394,7 +2417,7 @@ namespace ts {
if (nodeLine >= lastCommentLine + 2) {
// Valid detachedComments
emitNewLineBeforeLeadingComments(lineMap, writer, node, leadingComments);
emitComments(text, lineMap, writer, detachedComments, /*trailingSeparator*/ true, newLine, writeComment);
emitComments(text, lineMap, writer, detachedComments, /*leadingSeparator*/ false, /*trailingSeparator*/ true, newLine, writeComment);
currentDetachedCommentInfo = { nodePos: node.pos, detachedCommentEndPos: lastOrUndefined(detachedComments).end };
}
}
@@ -2795,6 +2818,35 @@ namespace ts {
return false;
}
export function formatSyntaxKind(kind: SyntaxKind): string {
const syntaxKindEnum = (<any>ts).SyntaxKind;
if (syntaxKindEnum) {
for (const name in syntaxKindEnum) {
if (syntaxKindEnum[name] === kind) {
return kind.toString() + " (" + name + ")";
}
}
}
else {
return kind.toString();
}
}
export const enum TextRangeCollapse {
CollapseToStart,
CollapseToEnd,
}
export function collapseTextRange(range: TextRange, collapse: TextRangeCollapse) {
if (range.pos === range.end) {
return range;
}
return collapse === TextRangeCollapse.CollapseToStart
? { pos: range.pos, end: range.end }
: { pos: range.end, end: range.end };
}
// Node tests
//
// All node tests in the following list should *not* reference parent pointers so that
@@ -2812,6 +2864,10 @@ namespace ts {
// Literals
export function isNoSubstitutionTemplateLiteral(node: Node): node is LiteralExpression {
return node.kind === SyntaxKind.NoSubstitutionTemplateLiteral;
}
export function isLiteralKind(kind: SyntaxKind): boolean {
return SyntaxKind.FirstLiteralToken <= kind && kind <= SyntaxKind.LastLiteralToken;
}
@@ -2905,6 +2961,10 @@ namespace ts {
// Type members
export function isMethodDeclaration(node: Node): node is MethodDeclaration {
return node.kind === SyntaxKind.MethodDeclaration;
}
export function isClassElement(node: Node): node is ClassElement {
const kind = node.kind;
return kind === SyntaxKind.Constructor
@@ -2991,11 +3051,16 @@ namespace ts {
|| kind === SyntaxKind.NoSubstitutionTemplateLiteral;
}
export function isSpreadElementExpression(node: Node): node is SpreadElementExpression {
return node.kind === SyntaxKind.SpreadElementExpression;
}
export function isExpressionWithTypeArguments(node: Node): node is ExpressionWithTypeArguments {
return node.kind === SyntaxKind.ExpressionWithTypeArguments;
}
function isLeftHandSideExpressionKind(kind: SyntaxKind) {
export function isLeftHandSideExpression(node: Node): node is LeftHandSideExpression {
const kind = node.kind;
return kind === SyntaxKind.PropertyAccessExpression
|| kind === SyntaxKind.ElementAccessExpression
|| kind === SyntaxKind.NewExpression
@@ -3021,11 +3086,8 @@ namespace ts {
|| kind === SyntaxKind.SuperKeyword;
}
export function isLeftHandSideExpression(node: Node): node is LeftHandSideExpression {
return isLeftHandSideExpressionKind(node.kind);
}
function isUnaryExpressionKind(kind: SyntaxKind): boolean {
export function isUnaryExpression(node: Node): node is UnaryExpression {
const kind = node.kind;
return kind === SyntaxKind.PrefixUnaryExpression
|| kind === SyntaxKind.PostfixUnaryExpression
|| kind === SyntaxKind.DeleteExpression
@@ -3033,14 +3095,11 @@ namespace ts {
|| kind === SyntaxKind.VoidExpression
|| kind === SyntaxKind.AwaitExpression
|| kind === SyntaxKind.TypeAssertionExpression
|| isLeftHandSideExpressionKind(kind);
|| isLeftHandSideExpression(node);
}
export function isUnaryExpression(node: Node): node is UnaryExpression {
return isUnaryExpressionKind(node.kind);
}
export function isExpressionKind(kind: SyntaxKind): boolean {
export function isExpression(node: Node): node is Expression {
const kind = node.kind;
return kind === SyntaxKind.ConditionalExpression
|| kind === SyntaxKind.YieldExpression
|| kind === SyntaxKind.ArrowFunction
@@ -3048,11 +3107,7 @@ namespace ts {
|| kind === SyntaxKind.SpreadElementExpression
|| kind === SyntaxKind.AsExpression
|| kind === SyntaxKind.OmittedExpression
|| isUnaryExpressionKind(kind);
}
export function isExpression(node: Node): node is Expression {
return isExpressionKind(node.kind);
|| isUnaryExpression(node);
}
// Misc
@@ -3264,9 +3319,12 @@ namespace ts {
// Property assignments
export function isShortHandPropertyAssignment(node: Node): node is ShorthandPropertyAssignment {
const kind = node.kind;
return kind === SyntaxKind.ShorthandPropertyAssignment;
export function isPropertyAssignment(node: Node): node is PropertyAssignment {
return node.kind === SyntaxKind.PropertyAssignment;
}
export function isShorthandPropertyAssignment(node: Node): node is ShorthandPropertyAssignment {
return node.kind === SyntaxKind.ShorthandPropertyAssignment;
}
// Enum
+117 -45
View File
@@ -19,6 +19,8 @@ namespace ts {
/** A callback used to lift a NodeArrayNode into a valid node. */
lift?: (nodes: NodeArray<Node>) => Node;
parenthesize?: (value: Node, parentNode: Node) => Node;
};
/**
@@ -52,7 +54,7 @@ namespace ts {
{ name: "modifiers", test: isModifier },
{ name: "name", test: isBindingName },
{ name: "type", test: isTypeNode, optional: true },
{ name: "initializer", test: isExpression, optional: true },
{ name: "initializer", test: isExpression, optional: true, parenthesize: parenthesizeExpressionForList },
],
[SyntaxKind.Decorator]: [
{ name: "expression", test: isLeftHandSideExpression },
@@ -108,34 +110,34 @@ namespace ts {
[SyntaxKind.BindingElement]: [
{ name: "propertyName", test: isPropertyName, optional: true },
{ name: "name", test: isBindingName },
{ name: "initializer", test: isExpression, optional: true },
{ name: "initializer", test: isExpression, optional: true, parenthesize: parenthesizeExpressionForList },
],
[SyntaxKind.ArrayLiteralExpression]: [
{ name: "elements", test: isExpression },
{ name: "elements", test: isExpression, parenthesize: parenthesizeExpressionForList },
],
[SyntaxKind.ObjectLiteralExpression]: [
{ name: "properties", test: isObjectLiteralElement },
],
[SyntaxKind.PropertyAccessExpression]: [
{ name: "expression", test: isLeftHandSideExpression },
{ name: "expression", test: isLeftHandSideExpression, parenthesize: parenthesizeForAccess },
{ name: "name", test: isIdentifier },
],
[SyntaxKind.ElementAccessExpression]: [
{ name: "expression", test: isLeftHandSideExpression },
{ name: "expression", test: isLeftHandSideExpression, parenthesize: parenthesizeForAccess },
{ name: "argumentExpression", test: isExpression },
],
[SyntaxKind.CallExpression]: [
{ name: "expression", test: isLeftHandSideExpression },
{ name: "expression", test: isLeftHandSideExpression, parenthesize: parenthesizeForAccess },
{ name: "typeArguments", test: isTypeNode },
{ name: "arguments", test: isExpression },
],
[SyntaxKind.NewExpression]: [
{ name: "expression", test: isLeftHandSideExpression },
{ name: "expression", test: isLeftHandSideExpression, parenthesize: parenthesizeForAccess },
{ name: "typeArguments", test: isTypeNode },
{ name: "arguments", test: isExpression },
],
[SyntaxKind.TaggedTemplateExpression]: [
{ name: "tag", test: isLeftHandSideExpression },
{ name: "tag", test: isLeftHandSideExpression, parenthesize: parenthesizeForAccess },
{ name: "template", test: isTemplate },
],
[SyntaxKind.TypeAssertionExpression]: [
@@ -163,26 +165,26 @@ namespace ts {
{ name: "body", test: isConciseBody, lift: liftToBlock },
],
[SyntaxKind.DeleteExpression]: [
{ name: "expression", test: isUnaryExpression },
{ name: "expression", test: isUnaryExpression, parenthesize: parenthesizePrefixOperand },
],
[SyntaxKind.TypeOfExpression]: [
{ name: "expression", test: isUnaryExpression },
{ name: "expression", test: isUnaryExpression, parenthesize: parenthesizePrefixOperand },
],
[SyntaxKind.VoidExpression]: [
{ name: "expression", test: isUnaryExpression },
{ name: "expression", test: isUnaryExpression, parenthesize: parenthesizePrefixOperand },
],
[SyntaxKind.AwaitExpression]: [
{ name: "expression", test: isUnaryExpression },
{ name: "expression", test: isUnaryExpression, parenthesize: parenthesizePrefixOperand },
],
[SyntaxKind.PrefixUnaryExpression]: [
{ name: "operand", test: isUnaryExpression },
{ name: "operand", test: isUnaryExpression, parenthesize: parenthesizePrefixOperand },
],
[SyntaxKind.PostfixUnaryExpression]: [
{ name: "operand", test: isLeftHandSideExpression },
{ name: "operand", test: isLeftHandSideExpression, parenthesize: parenthesizePostfixOperand },
],
[SyntaxKind.BinaryExpression]: [
{ name: "left", test: isExpression },
{ name: "right", test: isExpression },
{ name: "left", test: isExpression, parenthesize: (node: Expression, parent: BinaryExpression) => parenthesizeBinaryOperand(getOperator(parent), node, true) },
{ name: "right", test: isExpression, parenthesize: (node: Expression, parent: BinaryExpression) => parenthesizeBinaryOperand(getOperator(parent), node, false) },
],
[SyntaxKind.ConditionalExpression]: [
{ name: "condition", test: isExpression },
@@ -197,7 +199,7 @@ namespace ts {
{ name: "expression", test: isExpression, optional: true },
],
[SyntaxKind.SpreadElementExpression]: [
{ name: "expression", test: isExpression },
{ name: "expression", test: isExpression, parenthesize: parenthesizeExpressionForList },
],
[SyntaxKind.ClassExpression]: [
{ name: "decorators", test: isDecorator },
@@ -208,7 +210,7 @@ namespace ts {
{ name: "members", test: isClassElement },
],
[SyntaxKind.ExpressionWithTypeArguments]: [
{ name: "expression", test: isLeftHandSideExpression },
{ name: "expression", test: isLeftHandSideExpression, parenthesize: parenthesizeForAccess },
{ name: "typeArguments", test: isTypeNode },
],
[SyntaxKind.AsExpression]: [
@@ -228,7 +230,7 @@ namespace ts {
{ name: "declarationList", test: isVariableDeclarationList },
],
[SyntaxKind.ExpressionStatement]: [
{ name: "expression", test: isExpression },
{ name: "expression", test: isExpression, parenthesize: parenthesizeExpressionForExpressionStatement },
],
[SyntaxKind.IfStatement]: [
{ name: "expression", test: isExpression },
@@ -291,7 +293,7 @@ namespace ts {
[SyntaxKind.VariableDeclaration]: [
{ name: "name", test: isBindingName },
{ name: "type", test: isTypeNode, optional: true },
{ name: "initializer", test: isExpression, optional: true },
{ name: "initializer", test: isExpression, optional: true, parenthesize: parenthesizeExpressionForList },
],
[SyntaxKind.VariableDeclarationList]: [
{ name: "declarations", test: isVariableDeclaration },
@@ -420,7 +422,7 @@ namespace ts {
],
[SyntaxKind.PropertyAssignment]: [
{ name: "name", test: isPropertyName },
{ name: "initializer", test: isExpression },
{ name: "initializer", test: isExpression, parenthesize: parenthesizeExpressionForList },
],
[SyntaxKind.ShorthandPropertyAssignment]: [
{ name: "name", test: isIdentifier },
@@ -428,7 +430,7 @@ namespace ts {
],
[SyntaxKind.EnumMember]: [
{ name: "name", test: isPropertyName },
{ name: "initializer", test: isExpression, optional: true },
{ name: "initializer", test: isExpression, optional: true, parenthesize: parenthesizeExpressionForList },
],
[SyntaxKind.SourceFile]: [
{ name: "statements", test: isStatement },
@@ -492,7 +494,6 @@ namespace ts {
Debug.assert(test === undefined || test(visited), "Wrong node type after visit.");
aggregateTransformFlags(visited);
visited.original = node;
return <T>visited;
}
@@ -541,14 +542,14 @@ namespace ts {
aggregateTransformFlags(visited);
}
addNode(updated, visited, test);
addNodeWorker(updated, visited, /*addOnNewLine*/ undefined, test);
}
}
if (updated !== undefined) {
return <TArray>(isModifiersArray(nodes)
? createModifiersArray(updated, nodes)
: createNodeArray(updated, nodes));
: setHasTrailingComma(createNodeArray(updated, nodes), nodes.hasTrailingComma));
}
return nodes;
@@ -577,21 +578,27 @@ namespace ts {
const edgeTraversalPath = nodeEdgeTraversalMap[node.kind];
if (edgeTraversalPath) {
let modifiers: NodeFlags;
for (const edge of edgeTraversalPath) {
const value = <Node | NodeArray<Node>>node[edge.name];
if (value !== undefined) {
const visited = visitEdge(edge, value, visitor);
if (visited && isArray(visited) && isModifiersArray(visited)) {
modifiers = visited.flags;
}
if (updated !== undefined || visited !== value) {
if (updated === undefined) {
updated = cloneNode(node, /*location*/ node, node.flags & ~NodeFlags.Modifier, /*parent*/ undefined, /*original*/ node);
}
if (visited && isArray(visited) && isModifiersArray(visited)) {
updated[edge.name] = visited;
updated.flags |= visited.flags;
if (modifiers) {
updated.flags |= modifiers;
modifiers = undefined;
}
else {
updated[edge.name] = visited;
if (visited !== value) {
setEdgeValue(updated, edge, visited);
}
}
}
@@ -617,6 +624,17 @@ namespace ts {
return updated;
}
/**
* Sets the value of an edge, adjusting the value as necessary for cases such as expression precedence.
*/
function setEdgeValue(parentNode: Node & Map<any>, edge: NodeEdge, value: Node | NodeArray<Node>) {
if (value && edge.parenthesize && !isArray(value)) {
value = parenthesizeEdge(<Node>value, parentNode, edge.parenthesize, edge.test);
}
parentNode[edge.name] = value;
}
/**
* Visits a node edge.
*
@@ -627,7 +645,31 @@ namespace ts {
function visitEdge(edge: NodeEdge, value: Node | NodeArray<Node>, visitor: (node: Node) => Node) {
return isArray(value)
? visitNodes(<NodeArray<Node>>value, visitor, edge.test, /*start*/ undefined, /*count*/ undefined)
: visitNode(<Node>value, visitor, edge.test, edge.optional, edge.lift);
: visitNode(<Node>value, visitor, !edge.parenthesize ? edge.test : undefined, edge.optional, edge.lift);
}
/**
* Applies parentheses to a node to ensure the correct precedence.
*/
function parenthesizeEdge(node: Node, parentNode: Node, parenthesize: (node: Node, parentNode: Node) => Node, test: (node: Node) => boolean) {
node = parenthesize(node, parentNode);
Debug.assert(test === undefined || test(node), "Unexpected node kind after visit.");
return node;
}
/**
* Flattens an array of nodes that could contain NodeArrayNodes.
*/
export function flattenNodes<T extends Node>(nodes: OneOrMore<T>[]): T[] {
let result: T[];
if (nodes) {
result = [];
for (const node of nodes) {
addNode(result, node);
}
}
return result;
}
/**
@@ -635,18 +677,9 @@ namespace ts {
*
* @param to The destination array.
* @param from The source Node or NodeArrayNode.
* @param test The node test used to validate each node.
*/
export function addNode<T extends Node>(to: T[], from: OneOrMore<T>, test?: (node: Node) => boolean) {
if (to && from) {
if (isNodeArrayNode(from)) {
addNodes(to, from.nodes, test);
}
else {
Debug.assert(test === undefined || test(from), "Wrong node type after visit.");
to.push(from);
}
}
export function addNode<T extends Node>(to: T[], from: OneOrMore<T>, startOnNewLine?: boolean) {
addNodeWorker(to, from, startOnNewLine, /*test*/ undefined)
}
/**
@@ -654,12 +687,51 @@ namespace ts {
*
* @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) {
export function addNodes<T extends Node>(to: T[], from: OneOrMore<T>[], startOnNewLine?: boolean) {
addNodesWorker(to, from, startOnNewLine, /*test*/ undefined);
}
/**
* Appends a node to an array on a new line.
*
* @param to The destination array.
* @param from The source Node or NodeArrayNode.
*/
export function addLine<T extends Node>(to: T[], from: OneOrMore<T>) {
addNodeWorker(to, from, /*addOnNewLine*/ true, /*test*/ undefined);
}
/**
* Appends an array of nodes to an array on new lines.
*
* @param to The destination NodeArray.
* @param from The source array of Node or NodeArrayNode.
*/
export function addLines<T extends Node>(to: T[], from: OneOrMore<T>[]) {
addNodesWorker(to, from, /*addOnNewLine*/ true, /*test*/ undefined);
}
function addNodeWorker<T extends Node>(to: T[], from: OneOrMore<T>, addOnNewLine: boolean, test: (node: Node) => boolean) {
if (to && from) {
if (isNodeArrayNode(from)) {
addNodesWorker(to, from.nodes, addOnNewLine, test);
}
else {
Debug.assert(test === undefined || test(from), "Wrong node type after visit.");
if (addOnNewLine) {
startOnNewLine(from);
}
to.push(from);
}
}
}
function addNodesWorker<T extends Node>(to: T[], from: OneOrMore<T>[], addOnNewLine: boolean, test: (node: Node) => boolean) {
if (to && from) {
for (const node of from) {
addNode(to, node, test);
addNodeWorker(to, node, addOnNewLine, test);
}
}
}