mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-07-02 14:48:32 -05:00
Merge branch 'transforms-transformer-es6' into transforms-transformer-module
This commit is contained in:
@@ -239,6 +239,7 @@ function concatenateFiles(destinationFile, sourceFiles) {
|
||||
|
||||
var useDebugMode = true;
|
||||
var useTransforms = process.env.USE_TRANSFORMS || false;
|
||||
var useTransformCompat = false;
|
||||
var host = (process.env.host || process.env.TYPESCRIPT_HOST || "node");
|
||||
var compilerFilename = "tsc.js";
|
||||
var LKGCompiler = path.join(LKGDirectory, compilerFilename);
|
||||
@@ -301,6 +302,9 @@ function compileFile(outFile, sources, prereqs, prefixes, useBuiltCompiler, noOu
|
||||
if (useBuiltCompiler && useTransforms) {
|
||||
options += " --experimentalTransforms"
|
||||
}
|
||||
else if (useBuiltCompiler && useTransformCompat) {
|
||||
options += " --transformCompatibleEmit"
|
||||
}
|
||||
|
||||
var cmd = host + " " + compilerPath + " " + options + " ";
|
||||
cmd = cmd + sources.join(" ");
|
||||
@@ -429,6 +433,10 @@ task("setTransforms", function() {
|
||||
useTransforms = true;
|
||||
});
|
||||
|
||||
task("setTransformCompat", function() {
|
||||
useTransformCompat = true;
|
||||
});
|
||||
|
||||
task("configure-nightly", [configureNightlyJs], function() {
|
||||
var cmd = host + " " + configureNightlyJs + " " + packageJson + " " + programTs;
|
||||
console.log(cmd);
|
||||
|
||||
@@ -322,9 +322,18 @@ namespace ts {
|
||||
description: Diagnostics.Allow_default_imports_from_modules_with_no_default_export_This_does_not_affect_code_emit_just_typechecking
|
||||
},
|
||||
{
|
||||
// this option will be removed when this is merged with master and exists solely
|
||||
// to enable the tree transforming emitter side-by-side with the existing emitter.
|
||||
name: "experimentalTransforms",
|
||||
type: "boolean",
|
||||
experimental: true
|
||||
},
|
||||
{
|
||||
// this option will be removed when this is merged with master and exists solely
|
||||
// to enable the tree transforming emitter side-by-side with the existing emitter.
|
||||
name: "transformCompatibleEmit",
|
||||
type: "boolean",
|
||||
experimental: true
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
@@ -1915,6 +1915,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
||||
|
||||
if (multiLine) {
|
||||
decreaseIndent();
|
||||
if (!compilerOptions.transformCompatibleEmit) {
|
||||
writeLine();
|
||||
}
|
||||
}
|
||||
|
||||
write(")");
|
||||
@@ -4331,7 +4334,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
||||
writeLine();
|
||||
emitStart(restParam);
|
||||
emitNodeWithCommentsAndWithoutSourcemap(restParam.name);
|
||||
write(restIndex > 0
|
||||
write(restIndex > 0 || !compilerOptions.transformCompatibleEmit
|
||||
? `[${tempName} - ${restIndex}] = arguments[${tempName}];`
|
||||
: `[${tempName}] = arguments[${tempName}];`);
|
||||
emitEnd(restParam);
|
||||
@@ -5353,7 +5356,7 @@ const _super = (function (geti, seti) {
|
||||
const isClassExpressionWithStaticProperties = staticProperties.length > 0 && node.kind === SyntaxKind.ClassExpression;
|
||||
let tempVariable: Identifier;
|
||||
|
||||
if (isClassExpressionWithStaticProperties) {
|
||||
if (isClassExpressionWithStaticProperties && compilerOptions.transformCompatibleEmit) {
|
||||
tempVariable = createAndRecordTempVariable(TempFlags.Auto);
|
||||
write("(");
|
||||
increaseIndent();
|
||||
@@ -5390,6 +5393,11 @@ const _super = (function (geti, seti) {
|
||||
writeLine();
|
||||
emitConstructor(node, baseTypeNode);
|
||||
emitMemberFunctionsForES5AndLower(node);
|
||||
if (!compilerOptions.transformCompatibleEmit) {
|
||||
emitPropertyDeclarations(node, staticProperties);
|
||||
writeLine();
|
||||
emitDecoratorsOfClass(node, /*decoratedClassAlias*/ undefined);
|
||||
}
|
||||
writeLine();
|
||||
emitToken(SyntaxKind.CloseBraceToken, node.members.end, () => {
|
||||
write("return ");
|
||||
@@ -5416,11 +5424,13 @@ const _super = (function (geti, seti) {
|
||||
write("))");
|
||||
if (node.kind === SyntaxKind.ClassDeclaration) {
|
||||
write(";");
|
||||
emitPropertyDeclarations(node, staticProperties);
|
||||
writeLine();
|
||||
emitDecoratorsOfClass(node, /*decoratedClassAlias*/ undefined);
|
||||
if (compilerOptions.transformCompatibleEmit) {
|
||||
emitPropertyDeclarations(node, staticProperties);
|
||||
writeLine();
|
||||
emitDecoratorsOfClass(node, /*decoratedClassAlias*/ undefined);
|
||||
}
|
||||
}
|
||||
else if (isClassExpressionWithStaticProperties) {
|
||||
else if (isClassExpressionWithStaticProperties && compilerOptions.transformCompatibleEmit) {
|
||||
for (const property of staticProperties) {
|
||||
write(",");
|
||||
writeLine();
|
||||
|
||||
@@ -250,7 +250,7 @@ namespace ts {
|
||||
node.decorators = undefined;
|
||||
node.modifiers = undefined;
|
||||
node.typeParameters = undefined;
|
||||
node.parameters = createSynthesizedNodeArray(parameters);
|
||||
node.parameters = createNodeArray(parameters);
|
||||
node.type = undefined;
|
||||
node.body = body;
|
||||
return node;
|
||||
@@ -286,7 +286,7 @@ namespace ts {
|
||||
node.name = typeof name === "string" ? createIdentifier(name) : name;
|
||||
node.questionToken = undefined;
|
||||
node.type = undefined;
|
||||
node.initializer = initializer;
|
||||
node.initializer = initializer ? parenthesizeExpressionForList(initializer) : undefined;
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -294,7 +294,7 @@ namespace ts {
|
||||
|
||||
export function createArrayLiteral(elements?: Expression[]) {
|
||||
const node = <ArrayLiteralExpression>createNode(SyntaxKind.ArrayLiteralExpression);
|
||||
node.elements = createNodeArray(elements);
|
||||
node.elements = parenthesizeListElements(createNodeArray(elements));
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -322,14 +322,16 @@ namespace ts {
|
||||
export function createCall(expression: Expression, argumentsArray: Expression[], location?: TextRange) {
|
||||
const node = <CallExpression>createNode(SyntaxKind.CallExpression, location);
|
||||
node.expression = parenthesizeForAccess(expression);
|
||||
node.arguments = createNodeArray(argumentsArray);
|
||||
node.arguments = parenthesizeListElements(createNodeArray(argumentsArray));
|
||||
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;
|
||||
node.arguments = argumentsArray
|
||||
? parenthesizeListElements(createNodeArray(argumentsArray))
|
||||
: undefined;
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -358,7 +360,7 @@ namespace ts {
|
||||
node.parameters = createNodeArray(parameters);
|
||||
node.type = undefined;
|
||||
node.equalsGreaterThanToken = createNode(SyntaxKind.EqualsGreaterThanToken);
|
||||
node.body = body;
|
||||
node.body = parenthesizeConciseBody(body);
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -414,7 +416,7 @@ namespace ts {
|
||||
|
||||
export function createSpread(expression: Expression) {
|
||||
const node = <SpreadElementExpression>createNode(SyntaxKind.SpreadElementExpression);
|
||||
node.expression = expression;
|
||||
node.expression = parenthesizeExpressionForList(expression);
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -424,8 +426,8 @@ namespace ts {
|
||||
node.modifiers = undefined;
|
||||
node.name = name;
|
||||
node.typeParameters = undefined;
|
||||
node.heritageClauses = createSynthesizedNodeArray(heritageClauses);
|
||||
node.members = createSynthesizedNodeArray(members);
|
||||
node.heritageClauses = createNodeArray(heritageClauses);
|
||||
node.members = createNodeArray(members);
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -469,7 +471,7 @@ namespace ts {
|
||||
export function createVariableDeclaration(name: string | BindingPattern | Identifier, initializer?: Expression, location?: TextRange): VariableDeclaration {
|
||||
const node = <VariableDeclaration>createNode(SyntaxKind.VariableDeclaration, location);
|
||||
node.name = typeof name === "string" ? createIdentifier(name) : name;
|
||||
node.initializer = initializer;
|
||||
node.initializer = initializer !== undefined ? parenthesizeExpressionForList(initializer) : undefined;
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -479,7 +481,7 @@ namespace ts {
|
||||
|
||||
export function createStatement(expression: Expression, location?: TextRange): ExpressionStatement {
|
||||
const node = <ExpressionStatement>createNode(SyntaxKind.ExpressionStatement, location);
|
||||
node.expression = expression;
|
||||
node.expression = parenthesizeExpressionForExpressionStatement(expression);
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -562,8 +564,8 @@ namespace ts {
|
||||
setModifiers(node, modifiers);
|
||||
node.name = name;
|
||||
node.typeParameters = undefined;
|
||||
node.heritageClauses = createSynthesizedNodeArray(heritageClauses);
|
||||
node.members = createSynthesizedNodeArray(members);
|
||||
node.heritageClauses = createNodeArray(heritageClauses);
|
||||
node.members = createNodeArray(members);
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -599,7 +601,14 @@ namespace ts {
|
||||
export function createHeritageClause(token: SyntaxKind, types: ExpressionWithTypeArguments[], location?: TextRange) {
|
||||
const node = <HeritageClause>createNode(SyntaxKind.HeritageClause, location);
|
||||
node.token = token;
|
||||
node.types = createSynthesizedNodeArray(types);
|
||||
node.types = createNodeArray(types);
|
||||
return node;
|
||||
}
|
||||
|
||||
export function createCaseClause(expression: Expression, statements: Statement[], location?: TextRange) {
|
||||
const node = <CaseClause>createNode(SyntaxKind.CaseClause, location);
|
||||
node.expression = parenthesizeExpressionForList(expression);
|
||||
node.statements = createNodeArray(statements);
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -609,7 +618,7 @@ namespace ts {
|
||||
const node = <PropertyAssignment>createNode(SyntaxKind.PropertyAssignment, location);
|
||||
node.name = typeof name === "string" ? createIdentifier(name) : name;
|
||||
node.questionToken = undefined;
|
||||
node.initializer = initializer;
|
||||
node.initializer = initializer !== undefined ? parenthesizeExpressionForList(initializer) : undefined;
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -734,7 +743,7 @@ namespace ts {
|
||||
export function createJsxCreateElement(reactNamespace: string, tagName: Expression, props: Expression, children: Expression[]): LeftHandSideExpression {
|
||||
const argumentsList = [tagName];
|
||||
if (props) {
|
||||
argumentsList.push(props)
|
||||
argumentsList.push(props);
|
||||
}
|
||||
|
||||
if (children && children.length > 0) {
|
||||
@@ -834,7 +843,7 @@ namespace ts {
|
||||
addPropertyAssignment(properties, "enumerable", enumerable, preferNewLine);
|
||||
addPropertyAssignment(properties, "configurable", configurable, preferNewLine);
|
||||
addPropertyAssignment(properties, "writable", writable, preferNewLine);
|
||||
return createObjectLiteral(properties, location)
|
||||
return createObjectLiteral(properties, location);
|
||||
}
|
||||
|
||||
function addPropertyAssignment(properties: ObjectLiteralElement[], name: string, value: boolean | Expression, preferNewLine: boolean) {
|
||||
@@ -848,7 +857,7 @@ namespace ts {
|
||||
startOnNewLine(property);
|
||||
}
|
||||
|
||||
addNode(properties, property);
|
||||
properties.push(property);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1205,6 +1214,26 @@ namespace ts {
|
||||
: createParen(operand, /*location*/ operand);
|
||||
}
|
||||
|
||||
function parenthesizeListElements(elements: NodeArray<Expression>) {
|
||||
let result: Expression[];
|
||||
for (let i = 0; i < elements.length; i++) {
|
||||
const element = parenthesizeExpressionForList(elements[i]);
|
||||
if (result !== undefined || element !== elements[i]) {
|
||||
if (result === undefined) {
|
||||
result = elements.slice(0, i);
|
||||
}
|
||||
|
||||
result.push(element);
|
||||
}
|
||||
}
|
||||
|
||||
if (result !== undefined) {
|
||||
return createNodeArray(result, elements, elements.hasTrailingComma);
|
||||
}
|
||||
|
||||
return elements;
|
||||
}
|
||||
|
||||
export function parenthesizeExpressionForList(expression: Expression) {
|
||||
const expressionPrecedence = getExpressionPrecedence(expression);
|
||||
const commaPrecedence = getOperatorPrecedence(SyntaxKind.BinaryExpression, SyntaxKind.CommaToken);
|
||||
@@ -1230,6 +1259,14 @@ namespace ts {
|
||||
return expression;
|
||||
}
|
||||
|
||||
export function parenthesizeConciseBody(body: ConciseBody): ConciseBody {
|
||||
if (body.kind === SyntaxKind.ObjectLiteralExpression) {
|
||||
return createParen(<Expression>body, /*location*/ body);
|
||||
}
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
function getLeftmostExpression(node: Expression): Expression {
|
||||
while (true) {
|
||||
switch (node.kind) {
|
||||
@@ -1266,20 +1303,6 @@ namespace ts {
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Skips past any TypeAssertionExpression or AsExpression nodes to their inner expression.
|
||||
*
|
||||
* @param node The expression node.
|
||||
*/
|
||||
function skipAssertions(node: Expression) {
|
||||
while (node.kind === SyntaxKind.TypeAssertionExpression
|
||||
|| node.kind === SyntaxKind.AsExpression) {
|
||||
node = (<AssertionExpression>node).expression;
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
export function startOnNewLine<T extends Node>(node: T): T {
|
||||
node.startsOnNewLine = true;
|
||||
return node;
|
||||
|
||||
@@ -137,7 +137,6 @@ const _super = (function (geti, seti) {
|
||||
const comments = createCommentWriter(host, writer, sourceMap);
|
||||
const {
|
||||
getLeadingComments,
|
||||
getLeadingCommentsOfPosition,
|
||||
getTrailingComments,
|
||||
getTrailingCommentsOfPosition,
|
||||
emitLeadingComments,
|
||||
@@ -2421,7 +2420,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;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/// <reference path="sys.ts" />
|
||||
/// <reference path="emitter.ts" />
|
||||
/// <reference path="core.ts" />
|
||||
/// <reference path="printer.ts" />
|
||||
|
||||
namespace ts {
|
||||
/* @internal */ export let programTime = 0;
|
||||
|
||||
@@ -67,6 +67,11 @@ namespace ts {
|
||||
// Source map data
|
||||
let sourceMapData: SourceMapData;
|
||||
|
||||
// This keeps track of the number of times `disable` has been called without a
|
||||
// corresponding call to `enable`. As long as this value is non-zero, mappings will not
|
||||
// be recorded.
|
||||
// This is primarily used to provide a better experience when debugging binding
|
||||
// patterns and destructuring assignments for simple expressions.
|
||||
let disableDepth: number;
|
||||
|
||||
return {
|
||||
@@ -160,12 +165,18 @@ namespace ts {
|
||||
disableDepth = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-enables the recording of mappings.
|
||||
*/
|
||||
function enable() {
|
||||
if (disableDepth > 0) {
|
||||
disableDepth--;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables the recording of mappings.
|
||||
*/
|
||||
function disable() {
|
||||
disableDepth++;
|
||||
}
|
||||
|
||||
@@ -1,15 +1,47 @@
|
||||
/// <reference path="visitor.ts" />
|
||||
/// <reference path="transformers/ts.ts" />
|
||||
/// <reference path="transformers/jsx.ts" />
|
||||
/// <reference path="transformers/es7.ts" />
|
||||
/// <reference path="transformers/es6.ts" />
|
||||
/// <reference path="transformers/module/module.ts" />
|
||||
/// <reference path="transformers/module/system.ts" />
|
||||
/// <reference path="transformers/module/es6.ts" />
|
||||
|
||||
/* @internal */
|
||||
namespace ts {
|
||||
const moduleTransformerMap: Map<Transformer> = {
|
||||
[ModuleKind.ES6]: transformES6Module,
|
||||
[ModuleKind.System]: transformSystemModule,
|
||||
[ModuleKind.AMD]: transformModule,
|
||||
[ModuleKind.CommonJS]: transformModule,
|
||||
[ModuleKind.UMD]: transformModule,
|
||||
[ModuleKind.None]: transformModule,
|
||||
};
|
||||
|
||||
const enum SyntaxKindFeatureFlags {
|
||||
ExpressionSubstitution = 1 << 0,
|
||||
EmitNotifications = 1 << 1,
|
||||
}
|
||||
|
||||
export function getTransformers(compilerOptions: CompilerOptions) {
|
||||
const jsx = compilerOptions.jsx;
|
||||
const languageVersion = getEmitScriptTarget(compilerOptions);
|
||||
const moduleKind = getEmitModuleKind(compilerOptions);
|
||||
const transformers: Transformer[] = [];
|
||||
// TODO(rbuckton): Add transformers
|
||||
|
||||
transformers.push(transformTypeScript);
|
||||
transformers.push(moduleTransformerMap[moduleKind]);
|
||||
|
||||
if (jsx === JsxEmit.React) {
|
||||
transformers.push(transformJsx);
|
||||
}
|
||||
|
||||
transformers.push(transformES7);
|
||||
|
||||
if (languageVersion < ScriptTarget.ES6) {
|
||||
transformers.push(transformES6);
|
||||
}
|
||||
|
||||
return transformers;
|
||||
}
|
||||
|
||||
@@ -75,9 +107,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
currentSourceFile = sourceFile;
|
||||
const visited = transformation(sourceFile);
|
||||
currentSourceFile = undefined;
|
||||
return visited;
|
||||
return transformation(sourceFile);
|
||||
}
|
||||
|
||||
function enableExpressionSubstitution(kind: SyntaxKind) {
|
||||
|
||||
@@ -18,22 +18,29 @@ namespace ts {
|
||||
recordTempVariable: (node: Identifier) => void,
|
||||
visitor?: (node: Node) => Node) {
|
||||
|
||||
let location: TextRange = node;
|
||||
let value = node.right;
|
||||
if (isEmptyObjectLiteralOrArrayLiteral(node.left)) {
|
||||
return value;
|
||||
return node.right;
|
||||
}
|
||||
|
||||
let location: TextRange = node;
|
||||
let value = node.right;
|
||||
const expressions: Expression[] = [];
|
||||
if (needsValue) {
|
||||
// Temporary assignment needed to emit root should highlight whole binary expression
|
||||
value = ensureIdentifier(node.right, /*reuseIdentifierExpressions*/ true, node, emitTempVariableAssignment);
|
||||
// If the right-hand value of the destructuring assignment needs to be preserved (as
|
||||
// is the case when the destructuring assignmen) is part of a larger expression),
|
||||
// then we need to cache the right-hand value.
|
||||
//
|
||||
// The source map location for the assignment should point to the entire binary
|
||||
// expression.
|
||||
value = ensureIdentifier(node.right, /*reuseIdentifierExpressions*/ true, location, emitTempVariableAssignment);
|
||||
}
|
||||
else if (nodeIsSynthesized(node)) {
|
||||
// Source map node for root.left = root.right is root
|
||||
// but if root is synthetic, which could be in below case, use the target which is { a }
|
||||
// for ({a} of {a: string}) {
|
||||
// }
|
||||
// Generally, the source map location for a destructuring assignment is the root
|
||||
// expression.
|
||||
//
|
||||
// However, if the root expression is synthesized (as in the case
|
||||
// of the initializer when transforming a ForOfStatement), then the source map
|
||||
// location should point to the right-hand value of the expression.
|
||||
location = node.right;
|
||||
}
|
||||
|
||||
@@ -190,7 +197,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
if (isBinaryExpression(root)) {
|
||||
emitDestructuringAssignment(root.left, value, location)
|
||||
emitDestructuringAssignment(root.left, value, location);
|
||||
}
|
||||
else {
|
||||
emitBindingElement(root, value);
|
||||
@@ -255,21 +262,22 @@ namespace ts {
|
||||
|
||||
function emitArrayLiteralAssignment(target: ArrayLiteralExpression, value: Expression, location: TextRange) {
|
||||
const elements = target.elements;
|
||||
if (elements.length !== 1) {
|
||||
const numElements = elements.length;
|
||||
if (numElements !== 1) {
|
||||
// For anything but a single element destructuring we need to generate a temporary
|
||||
// to ensure value is evaluated exactly once.
|
||||
// When doing so we want to hightlight the passed in source map node since thats the one needing this temp assignment
|
||||
value = ensureIdentifier(value, /*reuseIdentifierExpressions*/ true, location, emitTempVariableAssignment);
|
||||
}
|
||||
|
||||
for (let i = 0; i < elements.length; i++) {
|
||||
for (let i = 0; i < numElements; i++) {
|
||||
const e = elements[i];
|
||||
if (e.kind !== SyntaxKind.OmittedExpression) {
|
||||
// Assignment for target = value.propName should highligh whole property, hence use e as source map node
|
||||
if (e.kind !== SyntaxKind.SpreadElementExpression) {
|
||||
emitDestructuringAssignment(e, createElementAccess(value, createLiteral(i)), e);
|
||||
}
|
||||
else if (i === elements.length - 1) {
|
||||
else if (i === numElements - 1) {
|
||||
emitDestructuringAssignment((<SpreadElementExpression>e).expression, createArraySlice(value, i), e);
|
||||
}
|
||||
}
|
||||
@@ -299,11 +307,11 @@ namespace ts {
|
||||
// so in that case, we'll intentionally create that temporary.
|
||||
value = ensureIdentifier(value, /*reuseIdentifierExpressions*/ numElements !== 0, target, emitTempVariableAssignment);
|
||||
}
|
||||
for (let i = 0; i < elements.length; i++) {
|
||||
let element = elements[i];
|
||||
for (let i = 0; i < numElements; i++) {
|
||||
const element = elements[i];
|
||||
if (name.kind === SyntaxKind.ObjectBindingPattern) {
|
||||
// Rewrite element to a declaration with an initializer that fetches property
|
||||
let propName = element.propertyName || <Identifier>element.name;
|
||||
const propName = element.propertyName || <Identifier>element.name;
|
||||
emitBindingElement(element, createDestructuringPropertyAccess(value, propName));
|
||||
}
|
||||
else if (element.kind !== SyntaxKind.OmittedExpression) {
|
||||
@@ -311,7 +319,7 @@ namespace ts {
|
||||
// Rewrite element to a declaration that accesses array element at index i
|
||||
emitBindingElement(element, createElementAccess(value, i));
|
||||
}
|
||||
else if (i === elements.length - 1) {
|
||||
else if (i === numElements - 1) {
|
||||
emitBindingElement(element, createArraySlice(value, i));
|
||||
}
|
||||
}
|
||||
@@ -332,16 +340,23 @@ namespace ts {
|
||||
);
|
||||
}
|
||||
|
||||
function createDestructuringPropertyAccess(object: Expression, propertyName: PropertyName): LeftHandSideExpression {
|
||||
/**
|
||||
* Creates either a PropertyAccessExpression or an ElementAccessExpression for the
|
||||
* right-hand side of a transformed destructuring assignment.
|
||||
*
|
||||
* @param expression The right-hand expression that is the source of the property.
|
||||
* @param propertyName The destructuring property name.
|
||||
*/
|
||||
function createDestructuringPropertyAccess(expression: Expression, propertyName: PropertyName): LeftHandSideExpression {
|
||||
if (isComputedPropertyName(propertyName)) {
|
||||
return createElementAccess(
|
||||
object,
|
||||
ensureIdentifier(propertyName.expression, /*reuseIdentifierExpressions*/ false, propertyName, emitTempVariableAssignment)
|
||||
expression,
|
||||
ensureIdentifier(propertyName.expression, /*reuseIdentifierExpressions*/ false, /*location*/ propertyName, emitTempVariableAssignment)
|
||||
);
|
||||
}
|
||||
else if (isIdentifier(propertyName)) {
|
||||
return createPropertyAccess(
|
||||
object,
|
||||
expression,
|
||||
propertyName.text
|
||||
);
|
||||
}
|
||||
@@ -349,7 +364,7 @@ namespace ts {
|
||||
// We create a synthetic copy of the identifier in order to avoid the rewriting that might
|
||||
// otherwise occur when the identifier is emitted.
|
||||
return createElementAccess(
|
||||
object,
|
||||
expression,
|
||||
cloneNode(propertyName)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -238,14 +238,14 @@ namespace ts {
|
||||
addExtendsHelperIfNeeded(statements, node, hasExtendsClause);
|
||||
addConstructor(statements, node, hasExtendsClause);
|
||||
addClassMembers(statements, node);
|
||||
addLine(statements, createReturn(getDeclarationName(node)));
|
||||
addLines(statements, endLexicalEnvironment());
|
||||
return createBlock(statements);
|
||||
addNode(statements, createReturn(getDeclarationName(node)));
|
||||
addNodes(statements, endLexicalEnvironment());
|
||||
return setMultiLine(createBlock(statements), /*multiLine*/ true);
|
||||
}
|
||||
|
||||
function addExtendsHelperIfNeeded(classStatements: Statement[], node: ClassExpression | ClassDeclaration, hasExtendsClause: boolean): void {
|
||||
if (hasExtendsClause) {
|
||||
addLine(classStatements,
|
||||
addNode(classStatements,
|
||||
createStatement(
|
||||
createExtendsHelper(getDeclarationName(node))
|
||||
)
|
||||
@@ -256,7 +256,7 @@ namespace ts {
|
||||
function addConstructor(classStatements: Statement[], node: ClassExpression | ClassDeclaration, hasExtendsClause: boolean): void {
|
||||
const constructor = getFirstConstructorWithBody(node);
|
||||
const hasSynthesizedSuper = hasSynthesizedDefaultSuperCall(constructor, hasExtendsClause);
|
||||
addLine(classStatements,
|
||||
addNode(classStatements,
|
||||
createFunctionDeclaration(
|
||||
/*modifiers*/ undefined,
|
||||
/*asteriskToken*/ undefined,
|
||||
@@ -291,13 +291,13 @@ namespace ts {
|
||||
addNodes(statements, visitNodes(constructor.body.statements, visitor, isStatement, hasSynthesizedSuper ? 1 : 0));
|
||||
}
|
||||
|
||||
addLines(statements, endLexicalEnvironment());
|
||||
return createBlock(statements, /*location*/ constructor && constructor.body);
|
||||
addNodes(statements, endLexicalEnvironment());
|
||||
return setMultiLine(createBlock(statements, /*location*/ constructor && constructor.body), /*multiLine*/ true);
|
||||
}
|
||||
|
||||
function addDefaultSuperCall(statements: Statement[], constructor: ConstructorDeclaration, hasExtendsClause: boolean, hasSynthesizedSuper: boolean) {
|
||||
if (constructor ? hasSynthesizedSuper : hasExtendsClause) {
|
||||
addLine(statements,
|
||||
addNode(statements,
|
||||
createStatement(
|
||||
createFunctionApply(
|
||||
createIdentifier("_super"),
|
||||
@@ -370,7 +370,7 @@ namespace ts {
|
||||
// we usually don't want to emit a var declaration; however, in the presence
|
||||
// of an initializer, we must emit that expression to preserve side effects.
|
||||
if (name.elements.length > 0) {
|
||||
addLine(statements,
|
||||
addNode(statements,
|
||||
createVariableStatement(
|
||||
/*modifiers*/ undefined,
|
||||
createVariableDeclarationList(
|
||||
@@ -380,7 +380,7 @@ namespace ts {
|
||||
);
|
||||
}
|
||||
else if (initializer) {
|
||||
addLine(statements,
|
||||
addNode(statements,
|
||||
createStatement(
|
||||
createAssignment(
|
||||
temp,
|
||||
@@ -396,7 +396,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function addDefaultValueAssignmentForInitializer(statements: Statement[], parameter: ParameterDeclaration, name: Identifier, initializer: Expression): void {
|
||||
addLine(statements,
|
||||
addNode(statements,
|
||||
createIf(
|
||||
createStrictEquality(
|
||||
getSynthesizedNode(name),
|
||||
@@ -436,7 +436,7 @@ namespace ts {
|
||||
const temp = createLoopVariable();
|
||||
|
||||
// var param = [];
|
||||
addLine(statements,
|
||||
addNode(statements,
|
||||
createVariableStatement(
|
||||
/*modifiers*/ undefined,
|
||||
createVariableDeclarationList([
|
||||
@@ -451,7 +451,7 @@ namespace ts {
|
||||
// for (var _i = restIndex; _i < arguments.length; _i++) {
|
||||
// param[_i - restIndex] = arguments[_i];
|
||||
// }
|
||||
addLine(statements,
|
||||
addNode(statements,
|
||||
createFor(
|
||||
createVariableDeclarationList([
|
||||
createVariableDeclaration(temp, createLiteral(restIndex))
|
||||
@@ -482,7 +482,7 @@ namespace ts {
|
||||
if (node.transformFlags & TransformFlags.ContainsCapturedLexicalThis && node.kind !== SyntaxKind.ArrowFunction) {
|
||||
enableExpressionSubstitutionForCapturedThis();
|
||||
|
||||
addLine(statements,
|
||||
addNode(statements,
|
||||
createVariableStatement(
|
||||
/*modifiers*/ undefined,
|
||||
createVariableDeclarationList([
|
||||
@@ -500,11 +500,11 @@ namespace ts {
|
||||
for (const member of node.members) {
|
||||
switch (member.kind) {
|
||||
case SyntaxKind.SemicolonClassElement:
|
||||
addLine(classStatements, transformSemicolonClassElementToStatement(<SemicolonClassElement>member));
|
||||
addNode(classStatements, transformSemicolonClassElementToStatement(<SemicolonClassElement>member));
|
||||
break;
|
||||
|
||||
case SyntaxKind.MethodDeclaration:
|
||||
addLine(classStatements, transformClassMethodDeclarationToStatement(node, <MethodDeclaration>member));
|
||||
addNode(classStatements, transformClassMethodDeclarationToStatement(node, <MethodDeclaration>member));
|
||||
break;
|
||||
|
||||
case SyntaxKind.GetAccessor:
|
||||
@@ -512,7 +512,7 @@ namespace ts {
|
||||
const accessors = getAllAccessorDeclarations(node.members, <AccessorDeclaration>member);
|
||||
if (member === accessors.firstAccessor) {
|
||||
const receiver = getClassMemberPrefix(node, member);
|
||||
addLine(classStatements, transformAccessorsToStatement(receiver, accessors));
|
||||
addNode(classStatements, transformAccessorsToStatement(receiver, accessors));
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -639,7 +639,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
addLines(statements, endLexicalEnvironment());
|
||||
addNodes(statements, endLexicalEnvironment());
|
||||
return createBlock(statements, node.body);
|
||||
}
|
||||
|
||||
@@ -804,9 +804,7 @@ namespace ts {
|
||||
// for-of bodies are always emitted as blocks.
|
||||
|
||||
const expression = visitNode(node.expression, visitor, isExpression);
|
||||
const rhsIsIdentifier = expression.kind === SyntaxKind.Identifier;
|
||||
const initializer = node.initializer;
|
||||
const loopDeclarations: VariableDeclaration[] = [];
|
||||
const loopBodyStatements: Statement[] = [];
|
||||
|
||||
// In the case where the user wrote an identifier as the RHS, like this:
|
||||
@@ -822,12 +820,11 @@ namespace ts {
|
||||
// Initialize LHS
|
||||
// var v = _a[_i];
|
||||
if (isVariableDeclarationList(initializer)) {
|
||||
const declarations: VariableDeclaration[] = [];
|
||||
const firstDeclaration = firstOrUndefined(initializer.declarations);
|
||||
if (firstDeclaration && isBindingPattern(firstDeclaration.name)) {
|
||||
// This works whether the declaration is a var, let, or const.
|
||||
// It will use rhsIterationValue _a[_i] as the initializer.
|
||||
addLine(loopBodyStatements,
|
||||
addNode(loopBodyStatements,
|
||||
createVariableStatement(
|
||||
/*modifiers*/ undefined,
|
||||
createVariableDeclarationList(
|
||||
@@ -844,7 +841,7 @@ namespace ts {
|
||||
else {
|
||||
// The following call does not include the initializer, so we have
|
||||
// to emit it separately.
|
||||
addLine(loopBodyStatements,
|
||||
addNode(loopBodyStatements,
|
||||
createVariableStatement(
|
||||
/*modifiers*/ undefined,
|
||||
createVariableDeclarationList([
|
||||
@@ -864,7 +861,7 @@ namespace ts {
|
||||
const assignment = createAssignment(initializer, createElementAccess(rhsReference, counter));
|
||||
if (isDestructuringAssignment(assignment)) {
|
||||
// This is a destructuring pattern, so we flatten the destructuring instead.
|
||||
addLine(loopBodyStatements,
|
||||
addNode(loopBodyStatements,
|
||||
createStatement(
|
||||
flattenDestructuringAssignment(
|
||||
assignment,
|
||||
@@ -876,7 +873,7 @@ namespace ts {
|
||||
);
|
||||
}
|
||||
else {
|
||||
addLine(loopBodyStatements, createStatement(assignment, /*location*/ node.initializer));
|
||||
addNode(loopBodyStatements, createStatement(assignment, /*location*/ node.initializer));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -909,10 +906,6 @@ namespace ts {
|
||||
);
|
||||
}
|
||||
|
||||
function shouldConvertLoopBody(node: IterationStatement): boolean {
|
||||
return (resolver.getNodeCheckFlags(node) & NodeCheckFlags.LoopWithCapturedBlockScopedBinding) !== 0;
|
||||
}
|
||||
|
||||
function visitObjectLiteralExpression(node: ObjectLiteralExpression): LeftHandSideExpression {
|
||||
// We are here because a ComputedPropertyName was used somewhere in the expression.
|
||||
const properties = node.properties;
|
||||
@@ -936,8 +929,6 @@ namespace ts {
|
||||
hoistVariableDeclaration(temp);
|
||||
|
||||
// Write out the first non-computed properties, then emit the rest through indexing on the temp variable.
|
||||
let initialProperties = visitNodes(properties, visitor, isObjectLiteralElement, 0, numInitialNonComputedProperties);
|
||||
|
||||
const expressions: Expression[] = [];
|
||||
addNode(expressions,
|
||||
createAssignment(
|
||||
@@ -1067,7 +1058,7 @@ namespace ts {
|
||||
target,
|
||||
thisArg,
|
||||
transformAndSpreadElements(node.arguments, /*needsUniqueCopy*/ false, /*multiLine*/ false)
|
||||
)
|
||||
);
|
||||
}
|
||||
else {
|
||||
Debug.assert(isSuperCall(node));
|
||||
@@ -1285,7 +1276,7 @@ namespace ts {
|
||||
// thus we need to remove those characters.
|
||||
// First template piece starts with "`", others with "}"
|
||||
// Last template piece ends with "`", others with "${"
|
||||
let isLast = node.kind === SyntaxKind.NoSubstitutionTemplateLiteral || node.kind === SyntaxKind.TemplateTail;
|
||||
const isLast = node.kind === SyntaxKind.NoSubstitutionTemplateLiteral || node.kind === SyntaxKind.TemplateTail;
|
||||
text = text.substring(1, text.length - (isLast ? 1 : 2));
|
||||
|
||||
// Newline normalization:
|
||||
@@ -1363,7 +1354,6 @@ namespace ts {
|
||||
}
|
||||
|
||||
function visitSuperKeyword(node: PrimaryExpression): LeftHandSideExpression {
|
||||
const expression = createIdentifier("_super");
|
||||
return containingNonArrowFunction
|
||||
&& isClassElement(containingNonArrowFunction)
|
||||
&& (containingNonArrowFunction.flags & NodeFlags.Static) === 0
|
||||
@@ -1375,7 +1365,7 @@ namespace ts {
|
||||
const clone = cloneNode(node, node, node.flags, /*parent*/ undefined, node);
|
||||
const statements: Statement[] = [];
|
||||
startLexicalEnvironment();
|
||||
let statementOffset = copyPrologueDirectives(node.statements, statements);
|
||||
const statementOffset = copyPrologueDirectives(node.statements, statements);
|
||||
addCaptureThisForNodeIfNeeded(statements, node);
|
||||
addNodes(statements, visitNodes(node.statements, visitor, isStatement, statementOffset));
|
||||
addNodes(statements, endLexicalEnvironment());
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace ts {
|
||||
function transformJsxChildToExpression(node: JsxChild): Expression {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.JsxText:
|
||||
return visitNonEmptyJsxText(<JsxText>node);
|
||||
return visitJsxText(<JsxText>node);
|
||||
|
||||
case SyntaxKind.JsxExpression:
|
||||
return visitJsxExpression(<JsxExpression>node);
|
||||
@@ -69,7 +69,7 @@ namespace ts {
|
||||
let objectProperties: Expression;
|
||||
if (node.attributes.length === 0) {
|
||||
// When there are no attributes, React wants "null"
|
||||
objectProperties = createLiteral(null);
|
||||
objectProperties = createNull();
|
||||
}
|
||||
else {
|
||||
// Either emit one big object literal (no spread attribs), or
|
||||
@@ -124,7 +124,7 @@ namespace ts {
|
||||
return createPropertyAssignment(name, expression);
|
||||
}
|
||||
|
||||
function visitNonEmptyJsxText(node: JsxText) {
|
||||
function visitJsxText(node: JsxText) {
|
||||
const text = getTextToEmit(node);
|
||||
if (text !== undefined) {
|
||||
return createLiteral(text);
|
||||
@@ -155,7 +155,7 @@ namespace ts {
|
||||
const c = text.charCodeAt(i);
|
||||
if (isLineBreak(c)) {
|
||||
if (firstNonWhitespace !== -1 && (lastNonWhitespace - firstNonWhitespace + 1 > 0)) {
|
||||
let part = text.substr(firstNonWhitespace, lastNonWhitespace - firstNonWhitespace + 1);
|
||||
const part = text.substr(firstNonWhitespace, lastNonWhitespace - firstNonWhitespace + 1);
|
||||
result = (result ? result + "\" + ' ' + \"" : "") + part;
|
||||
}
|
||||
firstNonWhitespace = -1;
|
||||
@@ -218,11 +218,6 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function visitJsxText(node: JsxText) {
|
||||
const text = trimReactWhitespaceAndApplyEntities(node);
|
||||
return createLiteral(text || "");
|
||||
}
|
||||
|
||||
function visitJsxExpression(node: JsxExpression) {
|
||||
return visitNode(node.expression, visitor, isExpression);
|
||||
}
|
||||
|
||||
@@ -6,10 +6,8 @@
|
||||
namespace ts {
|
||||
type SuperContainer = ClassDeclaration | MethodDeclaration | GetAccessorDeclaration | SetAccessorDeclaration | ConstructorDeclaration;
|
||||
|
||||
// TODO(rbuckton): TS->ES7 transformer
|
||||
export function transformTypeScript(context: TransformationContext) {
|
||||
const {
|
||||
nodeHasGeneratedName,
|
||||
getGeneratedNameForNode,
|
||||
makeUniqueName,
|
||||
setNodeEmitFlags,
|
||||
@@ -21,16 +19,18 @@ namespace ts {
|
||||
const resolver = context.getEmitResolver();
|
||||
const compilerOptions = context.getCompilerOptions();
|
||||
const languageVersion = getEmitScriptTarget(compilerOptions);
|
||||
const decoratedClassAliases: Map<Identifier> = {};
|
||||
const currentDecoratedClassAliases: Map<Identifier> = {};
|
||||
|
||||
// Save the previous transformation hooks.
|
||||
const previousExpressionSubstitution = context.expressionSubstitution;
|
||||
const previousOnBeforeEmitNode = context.onBeforeEmitNode;
|
||||
const previousOnAfterEmitNode = context.onAfterEmitNode;
|
||||
context.enableExpressionSubstitution(SyntaxKind.Identifier);
|
||||
|
||||
// Set new transformation hooks.
|
||||
context.expressionSubstitution = substituteExpression;
|
||||
context.onBeforeEmitNode = onBeforeEmitNode;
|
||||
context.onAfterEmitNode = onAfterEmitNode;
|
||||
|
||||
// These variables contain state that changes as we descend into the tree.
|
||||
let currentSourceFile: SourceFile;
|
||||
let currentNamespace: ModuleDeclaration;
|
||||
let currentNamespaceLocalName: Identifier;
|
||||
@@ -38,10 +38,28 @@ namespace ts {
|
||||
let currentParent: Node;
|
||||
let currentNode: Node;
|
||||
let combinedNodeFlags: NodeFlags;
|
||||
let isRightmostExpression: boolean;
|
||||
|
||||
// This stack is is used to support substitutions when printing nodes.
|
||||
// These variables keep track of whether expression substitution has been enabled for
|
||||
// specific edge cases. They are persisted between each SourceFile transformation and
|
||||
// should not be reset.
|
||||
let hasEnabledExpressionSubstitutionForDecoratedClasses = false;
|
||||
let hasEnabledExpressionSubstitutionForNamespaceExports = false;
|
||||
let hasEnabledExpressionSubstitutionForAsyncMethodsWithSuper = false;
|
||||
|
||||
// This map keeps track of aliases created for classes with decorators to avoid issues
|
||||
// with the double-binding behavior of classes.
|
||||
let decoratedClassAliases: Map<Identifier>;
|
||||
|
||||
// This map keeps track of currently active aliases defined in `decoratedClassAliases`
|
||||
// when just-in-time substitution occurs while printing an expression identifier.
|
||||
let currentDecoratedClassAliases: Map<Identifier>;
|
||||
|
||||
// This value keeps track of how deeply nested we are within any containing namespaces
|
||||
// when performing just-in-time substitution while printing an expression identifier.
|
||||
let namespaceNestLevel: number;
|
||||
|
||||
// This array keeps track of containers where `super` is valid, for use with
|
||||
// just-in-time substitution for `super` expressions inside of async methods.
|
||||
let superContainerStack: SuperContainer[];
|
||||
|
||||
return transformSourceFile;
|
||||
@@ -50,7 +68,6 @@ namespace ts {
|
||||
currentSourceFile = node;
|
||||
node = visitEachChild(node, visitor, context);
|
||||
setNodeEmitFlags(node, NodeEmitFlags.EmitEmitHelpers);
|
||||
currentSourceFile = undefined;
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -60,20 +77,25 @@ namespace ts {
|
||||
* @param node The node to visit.
|
||||
*/
|
||||
function visitWithStack(node: Node, visitor: (node: Node) => Node): Node {
|
||||
// Save state
|
||||
const savedCurrentNamespace = currentNamespace;
|
||||
const savedCurrentScope = currentScope;
|
||||
const savedCurrentParent = currentParent;
|
||||
const savedCurrentNode = currentNode;
|
||||
const savedCombinedNodeFlags = combinedNodeFlags;
|
||||
const savedIsRightmostExpression = isRightmostExpression;
|
||||
|
||||
// Handle state changes before visiting a node.
|
||||
onBeforeVisitNode(node);
|
||||
|
||||
node = visitor(node);
|
||||
|
||||
// Restore state
|
||||
currentNamespace = savedCurrentNamespace;
|
||||
currentScope = savedCurrentScope;
|
||||
currentParent = savedCurrentParent;
|
||||
currentNode = savedCurrentNode;
|
||||
combinedNodeFlags = savedCombinedNodeFlags;
|
||||
isRightmostExpression = savedIsRightmostExpression;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -156,6 +178,11 @@ namespace ts {
|
||||
return visitorWorker(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Branching visitor, visits a TypeScript syntax node.
|
||||
*
|
||||
* @param node The node to visit.
|
||||
*/
|
||||
function visitTypeScript(node: Node): Node {
|
||||
// TypeScript ambient declarations are elided.
|
||||
if (node.flags & NodeFlags.Ambient) {
|
||||
@@ -212,7 +239,7 @@ namespace ts {
|
||||
|
||||
case SyntaxKind.Constructor:
|
||||
// TypeScript constructors are elided. The constructor of a class will be
|
||||
// reordered to the start of the member list in `transformClassDeclaration`.
|
||||
// transformed as part of `transformClassDeclaration`.
|
||||
return undefined;
|
||||
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
@@ -342,11 +369,6 @@ namespace ts {
|
||||
currentScope = <SourceFile | CaseBlock | ModuleBlock | Block>node;
|
||||
break;
|
||||
}
|
||||
|
||||
// Keep track of whether this is the right-most expression of an expression tree.
|
||||
// This is used to determine whether to parenthesize an `await` expression transformed
|
||||
// into a `yield` expression.
|
||||
isRightmostExpression = currentParent && isRightmost(currentParent, currentNode, isRightmostExpression);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -479,11 +501,13 @@ namespace ts {
|
||||
|
||||
// Record an alias to avoid class double-binding.
|
||||
if (resolver.getNodeCheckFlags(getOriginalNode(node)) & NodeCheckFlags.ClassWithBodyScopedClassBinding) {
|
||||
enableExpressionSubstitutionForDecoratedClasses();
|
||||
decoratedClassAlias = makeUniqueName(node.name ? node.name.text : "default");
|
||||
decoratedClassAliases[getOriginalNodeId(node)] = decoratedClassAlias;
|
||||
|
||||
// We emit the class alias as a `let` declaration here so that it has the same
|
||||
// TDZ as the class.
|
||||
|
||||
// let ${decoratedClassAlias};
|
||||
addNode(statements,
|
||||
createVariableStatement(
|
||||
@@ -546,7 +570,7 @@ namespace ts {
|
||||
// Write any decorators of the node.
|
||||
addNodes(statements, generateClassElementDecorationStatements(node, /*isStatic*/ false));
|
||||
addNodes(statements, generateClassElementDecorationStatements(node, /*isStatic*/ true));
|
||||
addNode(statements, generateConstructorDecorationStatement(node, decoratedClassAlias))
|
||||
addNode(statements, generateConstructorDecorationStatement(node, decoratedClassAlias));
|
||||
|
||||
// If the class is exported as part of a TypeScript namespace, emit the namespace export.
|
||||
// Otherwise, if the class was exported at the top level and was decorated, emit an export
|
||||
@@ -575,7 +599,7 @@ namespace ts {
|
||||
*
|
||||
* @param node The node to transform.
|
||||
*/
|
||||
function visitClassExpression(node: ClassExpression): LeftHandSideExpression {
|
||||
function visitClassExpression(node: ClassExpression): Expression {
|
||||
const staticProperties = getInitializedProperties(node, /*isStatic*/ true);
|
||||
const heritageClauses = visitNodes(node.heritageClauses, visitor, isHeritageClause);
|
||||
const members = transformClassMembers(node, heritageClauses !== undefined);
|
||||
@@ -606,7 +630,7 @@ namespace ts {
|
||||
addNode(expressions, createAssignment(temp, classExpression));
|
||||
addNodes(expressions, generateInitializedPropertyExpressions(node, staticProperties, temp));
|
||||
addNode(expressions, temp);
|
||||
return createParen(inlineExpressions(expressions));
|
||||
return inlineExpressions(expressions);
|
||||
}
|
||||
|
||||
return classExpression;
|
||||
@@ -1093,7 +1117,7 @@ namespace ts {
|
||||
* Transforms all of the decorators for a declaration into an array of expressions.
|
||||
*
|
||||
* @param node The declaration node.
|
||||
* @param allDecorators The AllDecorators object for the node.
|
||||
* @param allDecorators An object containing all of the decorators for the declaration.
|
||||
*/
|
||||
function transformAllDecoratorsOfDeclaration(node: Declaration, allDecorators: AllDecorators) {
|
||||
if (!allDecorators) {
|
||||
@@ -1290,13 +1314,13 @@ namespace ts {
|
||||
*/
|
||||
function addTypeMetadata(node: Declaration, decoratorExpressions: Expression[]) {
|
||||
if (compilerOptions.emitDecoratorMetadata) {
|
||||
if (shouldAppendTypeMetadata(node)) {
|
||||
if (shouldAddTypeMetadata(node)) {
|
||||
decoratorExpressions.push(createMetadataHelper("design:type", serializeTypeOfNode(node), /*defer*/ true));
|
||||
}
|
||||
if (shouldAppendParamTypesMetadata(node)) {
|
||||
if (shouldAddParamTypesMetadata(node)) {
|
||||
decoratorExpressions.push(createMetadataHelper("design:paramtypes", serializeParameterTypesOfNode(node), /*defer*/ true));
|
||||
}
|
||||
if (shouldAppendReturnTypeMetadata(node)) {
|
||||
if (shouldAddReturnTypeMetadata(node)) {
|
||||
decoratorExpressions.push(createMetadataHelper("design:returntype", serializeReturnTypeOfNode(node), /*defer*/ true));
|
||||
}
|
||||
}
|
||||
@@ -1304,12 +1328,12 @@ namespace ts {
|
||||
|
||||
/**
|
||||
* Determines whether to emit the "design:type" metadata based on the node's kind.
|
||||
* The caller should have already tested whether the node has decorators and whether the emitDecoratorMetadata
|
||||
* compiler option is set.
|
||||
* The caller should have already tested whether the node has decorators and whether the
|
||||
* emitDecoratorMetadata compiler option is set.
|
||||
*
|
||||
* @param node The node to test.
|
||||
*/
|
||||
function shouldAppendTypeMetadata(node: Declaration): boolean {
|
||||
function shouldAddTypeMetadata(node: Declaration): boolean {
|
||||
const kind = node.kind;
|
||||
return kind === SyntaxKind.MethodDeclaration
|
||||
|| kind === SyntaxKind.GetAccessor
|
||||
@@ -1319,23 +1343,23 @@ namespace ts {
|
||||
|
||||
/**
|
||||
* Determines whether to emit the "design:returntype" metadata based on the node's kind.
|
||||
* The caller should have already tested whether the node has decorators and whether the emitDecoratorMetadata
|
||||
* compiler option is set.
|
||||
* The caller should have already tested whether the node has decorators and whether the
|
||||
* emitDecoratorMetadata compiler option is set.
|
||||
*
|
||||
* @param node The node to test.
|
||||
*/
|
||||
function shouldAppendReturnTypeMetadata(node: Declaration): boolean {
|
||||
function shouldAddReturnTypeMetadata(node: Declaration): boolean {
|
||||
return node.kind === SyntaxKind.MethodDeclaration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether to emit the "design:paramtypes" metadata based on the node's kind.
|
||||
* The caller should have already tested whether the node has decorators and whether the emitDecoratorMetadata
|
||||
* compiler option is set.
|
||||
* The caller should have already tested whether the node has decorators and whether the
|
||||
* emitDecoratorMetadata compiler option is set.
|
||||
*
|
||||
* @param node The node to test.
|
||||
*/
|
||||
function shouldAppendParamTypesMetadata(node: Declaration): boolean {
|
||||
function shouldAddParamTypesMetadata(node: Declaration): boolean {
|
||||
const kind = node.kind;
|
||||
return kind === SyntaxKind.ClassDeclaration
|
||||
|| kind === SyntaxKind.ClassExpression
|
||||
@@ -1465,7 +1489,7 @@ namespace ts {
|
||||
|
||||
case SyntaxKind.TypePredicate:
|
||||
case SyntaxKind.BooleanKeyword:
|
||||
return createIdentifier("Boolean")
|
||||
return createIdentifier("Boolean");
|
||||
|
||||
case SyntaxKind.StringKeyword:
|
||||
case SyntaxKind.StringLiteral:
|
||||
@@ -1591,7 +1615,7 @@ namespace ts {
|
||||
* qualified name at runtime.
|
||||
*/
|
||||
function serializeQualifiedNameAsExpression(node: QualifiedName, useFallback: boolean): Expression {
|
||||
let left: Expression
|
||||
let left: Expression;
|
||||
if (node.left.kind === SyntaxKind.Identifier) {
|
||||
left = serializeEntityNameAsExpression(node.left, useFallback);
|
||||
}
|
||||
@@ -1997,7 +2021,7 @@ namespace ts {
|
||||
)
|
||||
);
|
||||
|
||||
const block = createBlock(statements);
|
||||
const block = createBlock(statements, /*location*/ node.body);
|
||||
|
||||
// Minor optimization, emit `_super` helper to capture `super` access in an arrow.
|
||||
// This step isn't needed if we eventually transform this to ES5.
|
||||
@@ -2023,25 +2047,6 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function enableExpressionSubstitutionForAsyncMethodsWithSuper() {
|
||||
if (!hasEnabledExpressionSubstitutionForAsyncMethodsWithSuper) {
|
||||
hasEnabledExpressionSubstitutionForAsyncMethodsWithSuper = true;
|
||||
|
||||
// We need to enable substitutions for call, property access, and element access
|
||||
// if we need to rewrite super calls.
|
||||
context.enableExpressionSubstitution(SyntaxKind.CallExpression);
|
||||
context.enableExpressionSubstitution(SyntaxKind.PropertyAccessExpression);
|
||||
context.enableExpressionSubstitution(SyntaxKind.ElementAccessExpression);
|
||||
|
||||
// We need to be notified when entering and exiting declarations that bind super.
|
||||
context.enableEmitNotification(SyntaxKind.ClassDeclaration);
|
||||
context.enableEmitNotification(SyntaxKind.MethodDeclaration);
|
||||
context.enableEmitNotification(SyntaxKind.GetAccessor);
|
||||
context.enableEmitNotification(SyntaxKind.SetAccessor);
|
||||
context.enableEmitNotification(SyntaxKind.Constructor);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits a parameter declaration node.
|
||||
*
|
||||
@@ -2217,7 +2222,7 @@ namespace ts {
|
||||
* @param member The enum member node.
|
||||
*/
|
||||
function transformEnumMemberDeclarationValue(member: EnumMember): Expression {
|
||||
let value = resolver.getConstantValue(member);
|
||||
const value = resolver.getConstantValue(member);
|
||||
if (value !== undefined) {
|
||||
return createLiteral(value);
|
||||
}
|
||||
@@ -2248,20 +2253,13 @@ namespace ts {
|
||||
* @param node The await expression node.
|
||||
*/
|
||||
function visitAwaitExpression(node: AwaitExpression): Expression {
|
||||
const expression = setOriginalNode(
|
||||
return setOriginalNode(
|
||||
createYield(
|
||||
visitNode(node.expression, visitor, isExpression),
|
||||
node
|
||||
/*location*/ node
|
||||
),
|
||||
node
|
||||
);
|
||||
|
||||
return isRightmostExpression
|
||||
? expression
|
||||
: setOriginalNode(
|
||||
createParen(expression, /*location*/ node),
|
||||
node
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2331,6 +2329,8 @@ namespace ts {
|
||||
|
||||
Debug.assert(isIdentifier(node.name));
|
||||
|
||||
enableExpressionSubstitutionForNamespaceExports();
|
||||
|
||||
const savedCurrentNamespaceLocalName = currentNamespaceLocalName;
|
||||
const modifiers = visitNodes(node.modifiers, visitor, isModifier);
|
||||
const statements: Statement[] = [];
|
||||
@@ -2532,19 +2532,6 @@ namespace ts {
|
||||
return createStatement(expression, /*location*/ undefined);
|
||||
}
|
||||
|
||||
function createExportStatement(node: ClassExpression | ClassDeclaration | FunctionDeclaration): Statement {
|
||||
const name = getDeclarationName(node);
|
||||
if (currentNamespace) {
|
||||
return createNamespaceExport(name, name);
|
||||
}
|
||||
else if (node.flags & NodeFlags.Default) {
|
||||
return createExportDefault(name);
|
||||
}
|
||||
else {
|
||||
return createModuleExport(name);
|
||||
}
|
||||
}
|
||||
|
||||
function createNamespaceExport(exportName: Identifier, exportValue: Expression, location?: TextRange) {
|
||||
return createStatement(
|
||||
createAssignment(
|
||||
@@ -2581,8 +2568,65 @@ namespace ts {
|
||||
: getClassPrototype(node);
|
||||
}
|
||||
|
||||
function onBeforeEmitNode(node: Node): void {
|
||||
previousOnBeforeEmitNode(node);
|
||||
|
||||
const kind = node.kind;
|
||||
if (hasEnabledExpressionSubstitutionForDecoratedClasses
|
||||
&& kind === SyntaxKind.ClassDeclaration && node.decorators) {
|
||||
currentDecoratedClassAliases[getOriginalNodeId(node)] = decoratedClassAliases[getOriginalNodeId(node)];
|
||||
}
|
||||
|
||||
if (hasEnabledExpressionSubstitutionForAsyncMethodsWithSuper
|
||||
&& (kind === SyntaxKind.ClassDeclaration
|
||||
|| kind === SyntaxKind.Constructor
|
||||
|| kind === SyntaxKind.MethodDeclaration
|
||||
|| kind === SyntaxKind.GetAccessor
|
||||
|| kind === SyntaxKind.SetAccessor)) {
|
||||
|
||||
if (!superContainerStack) {
|
||||
superContainerStack = [];
|
||||
}
|
||||
|
||||
superContainerStack.push(<SuperContainer>node);
|
||||
}
|
||||
|
||||
if (hasEnabledExpressionSubstitutionForNamespaceExports
|
||||
&& kind === SyntaxKind.ModuleDeclaration) {
|
||||
namespaceNestLevel++;
|
||||
}
|
||||
}
|
||||
|
||||
function onAfterEmitNode(node: Node): void {
|
||||
previousOnAfterEmitNode(node);
|
||||
|
||||
const kind = node.kind;
|
||||
if (hasEnabledExpressionSubstitutionForDecoratedClasses
|
||||
&& kind === SyntaxKind.ClassDeclaration && node.decorators) {
|
||||
currentDecoratedClassAliases[getOriginalNodeId(node)] = undefined;
|
||||
}
|
||||
|
||||
if (hasEnabledExpressionSubstitutionForAsyncMethodsWithSuper
|
||||
&& (kind === SyntaxKind.ClassDeclaration
|
||||
|| kind === SyntaxKind.Constructor
|
||||
|| kind === SyntaxKind.MethodDeclaration
|
||||
|| kind === SyntaxKind.GetAccessor
|
||||
|| kind === SyntaxKind.SetAccessor)) {
|
||||
|
||||
if (superContainerStack) {
|
||||
superContainerStack.pop();
|
||||
}
|
||||
}
|
||||
|
||||
if (hasEnabledExpressionSubstitutionForNamespaceExports
|
||||
&& kind === SyntaxKind.ModuleDeclaration) {
|
||||
namespaceNestLevel--;
|
||||
}
|
||||
}
|
||||
|
||||
function substituteExpression(node: Expression): Expression {
|
||||
node = previousExpressionSubstitution(node);
|
||||
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.Identifier:
|
||||
return substituteExpressionIdentifier(<Identifier>node);
|
||||
@@ -2603,35 +2647,41 @@ namespace ts {
|
||||
}
|
||||
|
||||
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);
|
||||
if (hasEnabledExpressionSubstitutionForDecoratedClasses) {
|
||||
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
|
||||
);
|
||||
if (hasEnabledExpressionSubstitutionForNamespaceExports
|
||||
&& namespaceNestLevel > 0) {
|
||||
// If we are nested within a namespace declaration, we may need to qualifiy
|
||||
// an identifier that is exported from a merged namespace.
|
||||
const original = getOriginalNode(node);
|
||||
if (isIdentifier(original) && original.parent) {
|
||||
const container = resolver.getReferencedExportContainer(original);
|
||||
if (container && container.kind === SyntaxKind.ModuleDeclaration) {
|
||||
return createPropertyAccess(getGeneratedNameForNode(container), node, /*location*/ node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
function substituteCallExpression(node: CallExpression) {
|
||||
function substituteCallExpression(node: CallExpression): Expression {
|
||||
const expression = node.expression;
|
||||
if (isSuperPropertyOrElementAccess(expression)) {
|
||||
const flags = getSuperContainerAsyncMethodFlags();
|
||||
@@ -2681,6 +2731,54 @@ namespace ts {
|
||||
return node;
|
||||
}
|
||||
|
||||
function enableExpressionSubstitutionForAsyncMethodsWithSuper() {
|
||||
if (!hasEnabledExpressionSubstitutionForAsyncMethodsWithSuper) {
|
||||
hasEnabledExpressionSubstitutionForAsyncMethodsWithSuper = true;
|
||||
|
||||
// We need to enable substitutions for call, property access, and element access
|
||||
// if we need to rewrite super calls.
|
||||
context.enableExpressionSubstitution(SyntaxKind.CallExpression);
|
||||
context.enableExpressionSubstitution(SyntaxKind.PropertyAccessExpression);
|
||||
context.enableExpressionSubstitution(SyntaxKind.ElementAccessExpression);
|
||||
|
||||
// We need to be notified when entering and exiting declarations that bind super.
|
||||
context.enableEmitNotification(SyntaxKind.ClassDeclaration);
|
||||
context.enableEmitNotification(SyntaxKind.MethodDeclaration);
|
||||
context.enableEmitNotification(SyntaxKind.GetAccessor);
|
||||
context.enableEmitNotification(SyntaxKind.SetAccessor);
|
||||
context.enableEmitNotification(SyntaxKind.Constructor);
|
||||
}
|
||||
}
|
||||
|
||||
function enableExpressionSubstitutionForDecoratedClasses() {
|
||||
if (!hasEnabledExpressionSubstitutionForDecoratedClasses) {
|
||||
hasEnabledExpressionSubstitutionForDecoratedClasses = true;
|
||||
|
||||
// We need to enable substitutions for identifiers. This allows us to
|
||||
// substitute class names inside of a class declaration.
|
||||
context.enableExpressionSubstitution(SyntaxKind.Identifier);
|
||||
|
||||
// Keep track of class aliases.
|
||||
decoratedClassAliases = {};
|
||||
currentDecoratedClassAliases = {};
|
||||
}
|
||||
}
|
||||
|
||||
function enableExpressionSubstitutionForNamespaceExports() {
|
||||
if (!hasEnabledExpressionSubstitutionForNamespaceExports) {
|
||||
hasEnabledExpressionSubstitutionForNamespaceExports = true;
|
||||
|
||||
// We need to enable substitutions for identifiers. This allows us to
|
||||
// substitute the names of exported members of a namespace.
|
||||
context.enableExpressionSubstitution(SyntaxKind.Identifier);
|
||||
|
||||
// We need to be notified when entering and exiting namespaces.
|
||||
context.enableEmitNotification(SyntaxKind.ModuleDeclaration);
|
||||
|
||||
// Keep track of namespace nesting depth
|
||||
namespaceNestLevel = 0;
|
||||
}
|
||||
}
|
||||
|
||||
function createSuperAccessInAsyncMethod(argumentExpression: Expression, flags: NodeCheckFlags, location: TextRange): LeftHandSideExpression {
|
||||
if (flags & NodeCheckFlags.AsyncMethodWithSuperBinding) {
|
||||
@@ -2707,92 +2805,5 @@ namespace ts {
|
||||
return container !== undefined
|
||||
&& resolver.getNodeCheckFlags(getOriginalNode(container)) & (NodeCheckFlags.AsyncMethodWithSuper | NodeCheckFlags.AsyncMethodWithSuperBinding);
|
||||
}
|
||||
|
||||
function onBeforeEmitNode(node: Node): void {
|
||||
previousOnAfterEmitNode(node);
|
||||
|
||||
const kind = node.kind;
|
||||
if (kind === SyntaxKind.ClassDeclaration && node.decorators) {
|
||||
currentDecoratedClassAliases[getOriginalNodeId(node)] = decoratedClassAliases[getOriginalNodeId(node)];
|
||||
}
|
||||
|
||||
if (hasEnabledExpressionSubstitutionForAsyncMethodsWithSuper
|
||||
&& (kind === SyntaxKind.ClassDeclaration
|
||||
|| kind === SyntaxKind.Constructor
|
||||
|| kind === SyntaxKind.MethodDeclaration
|
||||
|| kind === SyntaxKind.GetAccessor
|
||||
|| kind === SyntaxKind.SetAccessor)) {
|
||||
|
||||
if (!superContainerStack) {
|
||||
superContainerStack = [];
|
||||
}
|
||||
|
||||
superContainerStack.push(<SuperContainer>node);
|
||||
}
|
||||
}
|
||||
|
||||
function onAfterEmitNode(node: Node): void {
|
||||
previousOnAfterEmitNode(node);
|
||||
|
||||
const kind = node.kind;
|
||||
if (kind === SyntaxKind.ClassDeclaration && node.decorators) {
|
||||
currentDecoratedClassAliases[getOriginalNodeId(node)] = undefined;
|
||||
}
|
||||
|
||||
if (hasEnabledExpressionSubstitutionForAsyncMethodsWithSuper
|
||||
&& (kind === SyntaxKind.ClassDeclaration
|
||||
|| kind === SyntaxKind.Constructor
|
||||
|| kind === SyntaxKind.MethodDeclaration
|
||||
|| kind === SyntaxKind.GetAccessor
|
||||
|| kind === SyntaxKind.SetAccessor)) {
|
||||
|
||||
if (superContainerStack) {
|
||||
superContainerStack.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function isRightmost(parentNode: Node, node: Node, wasRightmost: boolean) {
|
||||
switch (parentNode.kind) {
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
case SyntaxKind.Parameter:
|
||||
case SyntaxKind.BindingElement:
|
||||
case SyntaxKind.PropertyDeclaration:
|
||||
case SyntaxKind.PropertyAssignment:
|
||||
case SyntaxKind.ShorthandPropertyAssignment:
|
||||
case SyntaxKind.ExpressionStatement:
|
||||
case SyntaxKind.ArrayLiteralExpression:
|
||||
case SyntaxKind.ThrowStatement:
|
||||
case SyntaxKind.ReturnStatement:
|
||||
case SyntaxKind.ForStatement:
|
||||
case SyntaxKind.ForOfStatement:
|
||||
case SyntaxKind.ForInStatement:
|
||||
case SyntaxKind.DoStatement:
|
||||
case SyntaxKind.WhileStatement:
|
||||
case SyntaxKind.SwitchStatement:
|
||||
case SyntaxKind.CaseClause:
|
||||
case SyntaxKind.WithStatement:
|
||||
case SyntaxKind.Decorator:
|
||||
case SyntaxKind.ExpressionWithTypeArguments:
|
||||
case SyntaxKind.SpreadElementExpression:
|
||||
case SyntaxKind.AsExpression:
|
||||
case SyntaxKind.TypeAssertionExpression:
|
||||
case SyntaxKind.EnumMember:
|
||||
case SyntaxKind.JsxAttribute:
|
||||
case SyntaxKind.JsxSpreadAttribute:
|
||||
case SyntaxKind.JsxExpression:
|
||||
return true;
|
||||
case SyntaxKind.TemplateSpan:
|
||||
case SyntaxKind.CallExpression:
|
||||
case SyntaxKind.NewExpression:
|
||||
return node !== (<CallExpression | NewExpression>parentNode).expression;
|
||||
case SyntaxKind.BinaryExpression:
|
||||
return wasRightmost && node === (<BinaryExpression>parentNode).right;
|
||||
case SyntaxKind.ConditionalExpression:
|
||||
return wasRightmost && node === (<ConditionalExpression>parentNode).whenTrue;
|
||||
default:
|
||||
return wasRightmost;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2470,6 +2470,7 @@ namespace ts {
|
||||
allowJs?: boolean;
|
||||
/* @internal */ stripInternal?: boolean;
|
||||
/* @internal */ experimentalTransforms?: boolean;
|
||||
/* @internal */ transformCompatibleEmit?: boolean;
|
||||
|
||||
// Skip checking lib.d.ts to help speed up tests.
|
||||
/* @internal */ skipDefaultLibCheck?: boolean;
|
||||
|
||||
@@ -2817,7 +2817,7 @@ namespace ts {
|
||||
else if (kind === SyntaxKind.ConditionalExpression) {
|
||||
return isSimpleExpressionWorker((<ConditionalExpression>node).condition, depth + 1)
|
||||
&& isSimpleExpressionWorker((<ConditionalExpression>node).whenTrue, depth + 1)
|
||||
&& isSimpleExpressionWorker((<ConditionalExpression>node).whenFalse, depth + 1)
|
||||
&& isSimpleExpressionWorker((<ConditionalExpression>node).whenFalse, depth + 1);
|
||||
}
|
||||
else if (kind === SyntaxKind.VoidExpression
|
||||
|| kind === SyntaxKind.TypeOfExpression
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/// <reference path="checker.ts" />
|
||||
/// <reference path="factory.ts" />
|
||||
|
||||
/* @internal */
|
||||
namespace ts {
|
||||
@@ -163,7 +164,7 @@ namespace ts {
|
||||
{ name: "typeParameters", test: isTypeParameter },
|
||||
{ name: "parameters", test: isParameter },
|
||||
{ name: "type", test: isTypeNode, optional: true },
|
||||
{ name: "body", test: isConciseBody, lift: liftToBlock },
|
||||
{ name: "body", test: isConciseBody, lift: liftToBlock, parenthesize: parenthesizeConciseBody },
|
||||
],
|
||||
[SyntaxKind.DeleteExpression]: [
|
||||
{ name: "expression", test: isUnaryExpression, parenthesize: parenthesizePrefixOperand },
|
||||
@@ -408,7 +409,7 @@ namespace ts {
|
||||
{ name: "expression", test: isExpression, optional: true },
|
||||
],
|
||||
[SyntaxKind.CaseClause]: [
|
||||
{ name: "expression", test: isExpression },
|
||||
{ name: "expression", test: isExpression, parenthesize: parenthesizeExpressionForList },
|
||||
{ name: "statements", test: isStatement },
|
||||
],
|
||||
[SyntaxKind.DefaultClause]: [
|
||||
@@ -478,24 +479,46 @@ namespace ts {
|
||||
* @param lift An optional callback to execute to lift a NodeArrayNode into a valid Node.
|
||||
*/
|
||||
export function visitNode<T extends Node>(node: T, visitor: (node: Node) => Node, test: (node: Node) => boolean, optional?: boolean, lift?: (node: NodeArray<Node>) => T): T {
|
||||
return <T>visitNodeWorker(node, visitor, test, optional, lift, /*parenthesize*/ undefined, /*parentNode*/ undefined);
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits a Node using the supplied visitor, possibly returning a new Node in its place.
|
||||
*
|
||||
* @param node The Node to visit.
|
||||
* @param visitor The callback used to visit the Node.
|
||||
* @param test A callback to execute to verify the Node is valid.
|
||||
* @param optional A value indicating whether the Node is itself optional.
|
||||
* @param lift A callback to execute to lift a NodeArrayNode into a valid Node.
|
||||
* @param parenthesize A callback used to parenthesize the node if needed.
|
||||
* @param parentNode A parentNode for the node.
|
||||
*/
|
||||
function visitNodeWorker(node: Node, visitor: (node: Node) => Node, test: (node: Node) => boolean, optional: boolean, lift: (node: NodeArray<Node>) => Node, parenthesize: (node: Node, parentNode: Node) => Node, parentNode: Node): Node {
|
||||
if (node === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const visited = visitor(node);
|
||||
let visited = visitor(node);
|
||||
if (visited === node) {
|
||||
return node;
|
||||
}
|
||||
|
||||
const lifted = liftNode(visited, lift);
|
||||
if (lifted === undefined) {
|
||||
if (visited !== undefined && isNodeArrayNode(visited)) {
|
||||
visited = (lift || extractSingleNode)((<NodeArrayNode<Node>>visited).nodes);
|
||||
}
|
||||
|
||||
if (parenthesize !== undefined && visited !== undefined) {
|
||||
visited = parenthesize(visited, parentNode);
|
||||
}
|
||||
|
||||
if (visited === undefined) {
|
||||
Debug.assert(optional, "Node not optional.");
|
||||
return undefined;
|
||||
}
|
||||
|
||||
Debug.assert(test === undefined || test(visited), "Wrong node type after visit.");
|
||||
aggregateTransformFlags(visited);
|
||||
return <T>visited;
|
||||
return visited;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -508,11 +531,24 @@ namespace ts {
|
||||
* @param count An optional value indicating the maximum number of nodes to visit.
|
||||
*/
|
||||
export function visitNodes<T extends Node, TArray extends NodeArray<T>>(nodes: TArray, visitor: (node: Node) => Node, test: (node: Node) => boolean, start?: number, count?: number): TArray {
|
||||
return <TArray>visitNodesWorker(nodes, visitor, test, /*parenthesize*/ undefined, /*parentNode*/ undefined, start, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits a NodeArray using the supplied visitor, possibly returning a new NodeArray in its place.
|
||||
*
|
||||
* @param nodes The NodeArray to visit.
|
||||
* @param visitor The callback used to visit a Node.
|
||||
* @param test A node test to execute for each node.
|
||||
* @param start An optional value indicating the starting offset at which to start visiting.
|
||||
* @param count An optional value indicating the maximum number of nodes to visit.
|
||||
*/
|
||||
function visitNodesWorker(nodes: NodeArray<Node>, visitor: (node: Node) => Node, test: (node: Node) => boolean, parenthesize: (node: Node, parentNode: Node) => Node, parentNode: Node, start: number, count: number): NodeArray<Node> {
|
||||
if (nodes === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
let updated: T[];
|
||||
let updated: Node[];
|
||||
|
||||
// Ensure start and count have valid values
|
||||
const length = nodes.length;
|
||||
@@ -532,25 +568,21 @@ namespace ts {
|
||||
// Visit each original node.
|
||||
for (let i = 0; i < count; i++) {
|
||||
const node = nodes[i + start];
|
||||
const visited = node && <OneOrMany<T>>visitor(node);
|
||||
const visited = node !== undefined ? visitor(node) : undefined;
|
||||
if (updated !== undefined || visited === undefined || visited !== node) {
|
||||
if (updated === undefined) {
|
||||
// Ensure we have a copy of `nodes`, up to the current index.
|
||||
updated = nodes.slice(0, i);
|
||||
}
|
||||
|
||||
if (visited !== node) {
|
||||
aggregateTransformFlags(visited);
|
||||
}
|
||||
|
||||
addNodeWorker(updated, visited, /*addOnNewLine*/ undefined, test);
|
||||
addNodeWorker(updated, visited, /*addOnNewLine*/ undefined, test, parenthesize, parentNode, /*isVisiting*/ visited !== node);
|
||||
}
|
||||
}
|
||||
|
||||
if (updated !== undefined) {
|
||||
return <TArray>(isModifiersArray(nodes)
|
||||
return isModifiersArray(nodes)
|
||||
? createModifiersArray(updated, nodes)
|
||||
: createNodeArray(updated, nodes, nodes.hasTrailingComma));
|
||||
: createNodeArray(updated, nodes, nodes.hasTrailingComma);
|
||||
}
|
||||
|
||||
return nodes;
|
||||
@@ -583,9 +615,17 @@ namespace ts {
|
||||
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;
|
||||
let visited: Node | NodeArray<Node>;
|
||||
if (isArray(value)) {
|
||||
const visitedArray = visitNodesWorker(value, visitor, edge.test, edge.parenthesize, node, 0, value.length);
|
||||
if (isModifiersArray(visitedArray)) {
|
||||
modifiers = visitedArray.flags;
|
||||
}
|
||||
|
||||
visited = visitedArray;
|
||||
}
|
||||
else {
|
||||
visited = visitNodeWorker(<Node>value, visitor, edge.test, edge.optional, edge.lift, edge.parenthesize, node);
|
||||
}
|
||||
|
||||
if (updated !== undefined || visited !== value) {
|
||||
@@ -600,7 +640,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
if (visited !== value) {
|
||||
setEdgeValue(updated, edge, visited);
|
||||
updated[edge.name] = visited;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -626,39 +666,6 @@ namespace ts {
|
||||
return updated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits a node edge.
|
||||
*
|
||||
* @param edge The edge of the Node.
|
||||
* @param value The Node or NodeArray value for the edge.
|
||||
* @param visitor A callback used to visit the node.
|
||||
*/
|
||||
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.parenthesize ? edge.test : undefined, edge.optional, edge.lift);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of an edge, adjusting the value as necessary for cases such as expression precedence.
|
||||
*/
|
||||
function setEdgeValue(parentNode: Node & Map<any>, edge: NodeEdge, value: Node | NodeArray<Node>) {
|
||||
if (value && edge.parenthesize && !isArray(value)) {
|
||||
value = parenthesizeEdge(<Node>value, parentNode, edge.parenthesize, edge.test);
|
||||
}
|
||||
|
||||
parentNode[edge.name] = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies parentheses to a node to ensure the correct precedence.
|
||||
*/
|
||||
function parenthesizeEdge(node: Node, parentNode: Node, parenthesize: (node: Node, parentNode: Node) => Node, test: (node: Node) => boolean) {
|
||||
node = parenthesize(node, parentNode);
|
||||
Debug.assert(test === undefined || test(node), "Unexpected node kind after visit.");
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flattens an array of nodes that could contain NodeArrayNodes.
|
||||
*/
|
||||
@@ -686,7 +693,7 @@ namespace ts {
|
||||
* @param from The source Node or NodeArrayNode.
|
||||
*/
|
||||
export function addNode<T extends Node>(to: T[], from: OneOrMany<T>, startOnNewLine?: boolean) {
|
||||
addNodeWorker(to, from, startOnNewLine, /*test*/ undefined)
|
||||
addNodeWorker(to, from, startOnNewLine, /*test*/ undefined, /*parenthesize*/ undefined, /*parentNode*/ undefined, /*isVisiting*/ false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -696,49 +703,38 @@ namespace ts {
|
||||
* @param from The source array of Node or NodeArrayNode.
|
||||
*/
|
||||
export function addNodes<T extends Node>(to: T[], from: OneOrMany<T>[], startOnNewLine?: boolean) {
|
||||
addNodesWorker(to, from, startOnNewLine, /*test*/ undefined);
|
||||
addNodesWorker(to, from, startOnNewLine, /*test*/ undefined, /*parenthesize*/ undefined, /*parentNode*/ undefined, /*isVisiting*/ false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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: OneOrMany<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: OneOrMany<T>[]) {
|
||||
addNodesWorker(to, from, /*addOnNewLine*/ true, /*test*/ undefined);
|
||||
}
|
||||
|
||||
function addNodeWorker<T extends Node>(to: T[], from: OneOrMany<T>, addOnNewLine: boolean, test: (node: Node) => boolean) {
|
||||
function addNodeWorker(to: Node[], from: OneOrMany<Node>, startOnNewLine: boolean, test: (node: Node) => boolean, parenthesize: (node: Node, parentNode: Node) => Node, parentNode: Node, isVisiting: boolean) {
|
||||
if (to && from) {
|
||||
if (isNodeArrayNode(from)) {
|
||||
addNodesWorker(to, from.nodes, addOnNewLine, test);
|
||||
addNodesWorker(to, from.nodes, startOnNewLine, test, parenthesize, parentNode, isVisiting);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
Debug.assert(test === undefined || test(from), "Wrong node type after visit.");
|
||||
if (addOnNewLine) {
|
||||
startOnNewLine(from);
|
||||
}
|
||||
|
||||
to.push(from);
|
||||
if (parenthesize !== undefined) {
|
||||
from = parenthesize(from, parentNode);
|
||||
}
|
||||
|
||||
Debug.assert(test === undefined || test(from), "Wrong node type after visit.");
|
||||
|
||||
if (startOnNewLine) {
|
||||
from.startsOnNewLine = true;
|
||||
}
|
||||
|
||||
if (isVisiting) {
|
||||
aggregateTransformFlags(from);
|
||||
}
|
||||
|
||||
to.push(from);
|
||||
}
|
||||
}
|
||||
|
||||
function addNodesWorker<T extends Node>(to: T[], from: OneOrMany<T>[], addOnNewLine: boolean, test: (node: Node) => boolean) {
|
||||
function addNodesWorker(to: Node[], from: OneOrMany<Node>[], startOnNewLine: boolean, test: (node: Node) => boolean, parenthesize: (node: Node, parentNode: Node) => Node, parentNode: Node, isVisiting: boolean) {
|
||||
if (to && from) {
|
||||
for (const node of from) {
|
||||
addNodeWorker(to, node, addOnNewLine, test);
|
||||
addNodeWorker(to, node, startOnNewLine, test, parenthesize, parentNode, isVisiting);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -878,26 +874,6 @@ namespace ts {
|
||||
return createNodeArray(concatenate(statements, declarations), /*location*/ statements);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to lift a NodeArrayNode to a Node. This is primarily used to
|
||||
* lift multiple statements into a single Block.
|
||||
*
|
||||
* @param node The visited Node.
|
||||
* @param options Options used to control lift behavior.
|
||||
*/
|
||||
function liftNode(node: Node, lifter: (nodes: NodeArray<Node>) => Node): Node {
|
||||
if (node === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
else if (isNodeArrayNode(node)) {
|
||||
const lift = lifter || extractSingleNode;
|
||||
return lift(node.nodes);
|
||||
}
|
||||
else {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lifts a NodeArray containing only Statement nodes to a block.
|
||||
*
|
||||
|
||||
@@ -204,7 +204,7 @@ namespace ts.formatting {
|
||||
// - parent is SourceFile - by default immediate children of SourceFile are not indented except when user indents them manually
|
||||
// - parent and child are not on the same line
|
||||
let useActualIndentation =
|
||||
(isDeclaration(current) || isStatement(current)) &&
|
||||
(isDeclaration(current) || isStatementButNotDeclaration(current)) &&
|
||||
(parent.kind === SyntaxKind.SourceFile || !parentAndChildShareLine);
|
||||
|
||||
if (!useActualIndentation) {
|
||||
|
||||
Reference in New Issue
Block a user