mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Adds destructuring logic and placeholders for each transformer.
This commit is contained in:
+25
-8
@@ -135,9 +135,18 @@ namespace ts {
|
||||
return node;
|
||||
}
|
||||
|
||||
export function createTempVariable(tempKind: TempVariableKind): Identifier {
|
||||
export function createTempVariable(): Identifier {
|
||||
const name = <Identifier>createNode(SyntaxKind.Identifier);
|
||||
name.tempKind = tempKind;
|
||||
name.text = undefined;
|
||||
name.tempKind = TempVariableKind.Auto;
|
||||
getNodeId(name);
|
||||
return name;
|
||||
}
|
||||
|
||||
export function createLoopVariable(): Identifier {
|
||||
const name = <Identifier>createNode(SyntaxKind.Identifier);
|
||||
name.text = undefined;
|
||||
name.tempKind = TempVariableKind.Loop;
|
||||
getNodeId(name);
|
||||
return name;
|
||||
}
|
||||
@@ -171,16 +180,16 @@ namespace ts {
|
||||
return createVoid(createLiteral(0));
|
||||
}
|
||||
|
||||
export function createPropertyAccess(expression: Expression, name: string | Identifier) {
|
||||
const node = <PropertyAccessExpression>createNode(SyntaxKind.PropertyAccessExpression);
|
||||
export function createPropertyAccess(expression: Expression, name: string | Identifier, location?: TextRange) {
|
||||
const node = <PropertyAccessExpression>createNode(SyntaxKind.PropertyAccessExpression, location);
|
||||
node.expression = parenthesizeForAccess(expression);
|
||||
node.dotToken = createSynthesizedNode(SyntaxKind.DotToken);
|
||||
node.name = coerceIdentifier(name);
|
||||
return node;
|
||||
}
|
||||
|
||||
export function createElementAccess(expression: Expression, index: string | number | Expression) {
|
||||
const node = <ElementAccessExpression>createNode(SyntaxKind.ElementAccessExpression);
|
||||
export function createElementAccess(expression: Expression, index: string | number | Expression, location?: TextRange) {
|
||||
const node = <ElementAccessExpression>createNode(SyntaxKind.ElementAccessExpression, location);
|
||||
node.expression = parenthesizeForAccess(expression);
|
||||
node.argumentExpression = coerceExpression(index);
|
||||
return node;
|
||||
@@ -216,8 +225,8 @@ namespace ts {
|
||||
return <Expression>createBinary(left, SyntaxKind.CommaToken, right);
|
||||
}
|
||||
|
||||
export function createCall(expression: Expression, argumentsArray: Expression[]) {
|
||||
const node = <CallExpression>createNode(SyntaxKind.CallExpression);
|
||||
export function createCall(expression: Expression, argumentsArray: Expression[], location?: TextRange) {
|
||||
const node = <CallExpression>createNode(SyntaxKind.CallExpression, location);
|
||||
node.expression = parenthesizeForAccess(expression);
|
||||
node.arguments = createNodeArray(argumentsArray);
|
||||
return node;
|
||||
@@ -228,6 +237,14 @@ namespace ts {
|
||||
return createCall(createPropertyAccess(array, "slice"), argumentsList);
|
||||
}
|
||||
|
||||
export function createMathPow(left: Expression, right: Expression, location?: TextRange) {
|
||||
return createCall(
|
||||
createPropertyAccess(createIdentifier("Math"), "pow"),
|
||||
[left, right],
|
||||
location
|
||||
);
|
||||
}
|
||||
|
||||
export function parenthesizeExpression(expression: Expression) {
|
||||
const node = <ParenthesizedExpression>createNode(SyntaxKind.ParenthesizedExpression);
|
||||
node.expression = expression;
|
||||
|
||||
@@ -7,12 +7,15 @@ namespace ts {
|
||||
setSourceFile(sourceFile: SourceFile): void;
|
||||
emitPos(pos: number): void;
|
||||
emitStart(range: TextRange): void;
|
||||
emitEnd(range: TextRange, stopOverridingSpan?: boolean): void;
|
||||
changeEmitSourcePos(): void;
|
||||
emitEnd(range: TextRange): void;
|
||||
/*@deprecated*/ emitEnd(range: TextRange, stopOverridingSpan: boolean): void;
|
||||
/*@deprecated*/ changeEmitSourcePos(): void;
|
||||
getText(): string;
|
||||
getSourceMappingURL(): string;
|
||||
initialize(filePath: string, sourceMapFilePath: string, sourceFiles: SourceFile[], isBundledEmit: boolean): void;
|
||||
reset(): void;
|
||||
enable(): void;
|
||||
disable(): void;
|
||||
}
|
||||
|
||||
let nullSourceMapWriter: SourceMapWriter;
|
||||
@@ -38,6 +41,8 @@ namespace ts {
|
||||
getSourceMappingURL(): string { return undefined; },
|
||||
initialize(filePath: string, sourceMapFilePath: string, sourceFiles: SourceFile[], isBundledEmit: boolean): void { },
|
||||
reset(): void { },
|
||||
enable(): void { },
|
||||
disable(): void { }
|
||||
};
|
||||
}
|
||||
|
||||
@@ -62,6 +67,8 @@ namespace ts {
|
||||
// Source map data
|
||||
let sourceMapData: SourceMapData;
|
||||
|
||||
let disableDepth: number;
|
||||
|
||||
return {
|
||||
getSourceMapData: () => sourceMapData,
|
||||
setSourceFile,
|
||||
@@ -73,6 +80,8 @@ namespace ts {
|
||||
getSourceMappingURL,
|
||||
initialize,
|
||||
reset,
|
||||
enable,
|
||||
disable,
|
||||
};
|
||||
|
||||
function initialize(filePath: string, sourceMapFilePath: string, sourceFiles: SourceFile[], isBundledEmit: boolean) {
|
||||
@@ -81,6 +90,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
currentSourceFile = undefined;
|
||||
disableDepth = 0;
|
||||
|
||||
// Current source map file and its index in the sources list
|
||||
sourceMapSourceIndex = -1;
|
||||
@@ -147,6 +157,17 @@ namespace ts {
|
||||
lastEncodedSourceMapSpan = undefined;
|
||||
lastEncodedNameIndex = undefined;
|
||||
sourceMapData = undefined;
|
||||
disableDepth = 0;
|
||||
}
|
||||
|
||||
function enable() {
|
||||
if (disableDepth > 0) {
|
||||
disableDepth--;
|
||||
}
|
||||
}
|
||||
|
||||
function disable() {
|
||||
disableDepth++;
|
||||
}
|
||||
|
||||
function updateLastEncodedAndRecordedSpans() {
|
||||
@@ -168,7 +189,7 @@ namespace ts {
|
||||
sourceMapData.sourceMapDecodedMappings[sourceMapData.sourceMapDecodedMappings.length - 1] :
|
||||
defaultLastEncodedSourceMapSpan;
|
||||
|
||||
// TODO: Update lastEncodedNameIndex
|
||||
// TODO: Update lastEncodedNameIndex
|
||||
// Since we dont support this any more, lets not worry about it right now.
|
||||
// When we start supporting nameIndex, we will get back to this
|
||||
|
||||
@@ -236,7 +257,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function emitPos(pos: number) {
|
||||
if (pos === -1) {
|
||||
if (positionIsSynthesized(pos) || disableDepth > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -288,9 +309,17 @@ namespace ts {
|
||||
|
||||
function emitStart(range: TextRange) {
|
||||
emitPos(getStartPos(range));
|
||||
|
||||
if ((<SynthesizedNode>range).disableSourceMap) {
|
||||
disable();
|
||||
}
|
||||
}
|
||||
|
||||
function emitEnd(range: TextRange, stopOverridingEnd?: boolean) {
|
||||
if ((<SynthesizedNode>range).disableSourceMap) {
|
||||
enable();
|
||||
}
|
||||
|
||||
emitPos(range.end);
|
||||
stopOverridingSpan = stopOverridingEnd;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,44 @@
|
||||
/// <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
|
||||
};
|
||||
|
||||
export function getTransformers(compilerOptions: CompilerOptions) {
|
||||
const jsx = compilerOptions.jsx;
|
||||
const languageVersion = getLanguageVersion(compilerOptions);
|
||||
const moduleKind = getModuleKind(compilerOptions);
|
||||
const transformers: Transformer[] = [];
|
||||
// TODO(rbuckton): Add transformers
|
||||
|
||||
transformers.push(transformTypeScript);
|
||||
transformers.push(moduleTransformerMap[moduleKind]);
|
||||
if (jsx === JsxEmit.React) {
|
||||
transformers.push(transformJsx);
|
||||
}
|
||||
|
||||
if (languageVersion < ScriptTarget.ES7) {
|
||||
transformers.push(transformES7);
|
||||
}
|
||||
|
||||
if (languageVersion < ScriptTarget.ES6) {
|
||||
transformers.push(transformES6);
|
||||
}
|
||||
|
||||
return transformers;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,347 @@
|
||||
/// <reference path="../factory.ts" />
|
||||
/// <reference path="../visitor.ts" />
|
||||
|
||||
/*@internal*/
|
||||
namespace ts {
|
||||
/**
|
||||
* Flattens a destructuring assignment expression.
|
||||
*
|
||||
* @param root The destructuring assignment expression.
|
||||
* @param needsValue Indicates whether the value from the right-hand-side of the
|
||||
* destructuring assignment is needed as part of a larger expression.
|
||||
* @param recordTempVariable A callback used to record new temporary variables.
|
||||
*/
|
||||
export function flattenDestructuringAssignment(node: BinaryExpression, needsValue: boolean, recordTempVariable: (node: Identifier) => void) {
|
||||
let location: TextRange = node;
|
||||
let value = node.right;
|
||||
if (isEmptyObjectLiteralOrArrayLiteral(node.left)) {
|
||||
return value;
|
||||
}
|
||||
|
||||
const expressions: Expression[] = [];
|
||||
if (needsValue) {
|
||||
// Temporary assignment needed to emit root should highlight whole binary expression
|
||||
value = ensureIdentifier(node.right, /*reuseIdentifierExpressions*/ true, node, 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}) {
|
||||
// }
|
||||
location = node.right;
|
||||
}
|
||||
|
||||
flattenDestructuring(node, value, location, emitAssignment, emitTempVariableAssignment);
|
||||
|
||||
if (needsValue) {
|
||||
expressions.push(value);
|
||||
}
|
||||
|
||||
const expression = inlineExpressions(expressions);
|
||||
aggregateTransformFlags(expression);
|
||||
return expression;
|
||||
|
||||
function emitAssignment(name: Identifier, value: Expression, location: TextRange) {
|
||||
const expression = createAssignment(name, value, location);
|
||||
if (isSimpleExpression(value)) {
|
||||
(<SynthesizedNode>expression).disableSourceMap = true;
|
||||
}
|
||||
|
||||
aggregateTransformFlags(expression);
|
||||
expressions.push(expression);
|
||||
}
|
||||
|
||||
function emitTempVariableAssignment(value: Expression, location: TextRange) {
|
||||
const name = createTempVariable();
|
||||
recordTempVariable(name);
|
||||
emitAssignment(name, value, location);
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Flattens binding patterns in a parameter declaration.
|
||||
*
|
||||
* @param node The ParameterDeclaration to flatten.
|
||||
* @param value The rhs value for the binding pattern.
|
||||
*/
|
||||
export function flattenParameterDestructuring(node: ParameterDeclaration, value: Expression) {
|
||||
const declarations: VariableDeclaration[] = [];
|
||||
|
||||
flattenDestructuring(node, value, node, emitAssignment, emitTempVariableAssignment);
|
||||
|
||||
return declarations;
|
||||
|
||||
function emitAssignment(name: Identifier, value: Expression, location: TextRange) {
|
||||
const declaration = createVariableDeclaration(name, value, location);
|
||||
if (isSimpleExpression(value)) {
|
||||
(<SynthesizedNode>declaration).disableSourceMap = true;
|
||||
}
|
||||
|
||||
aggregateTransformFlags(declaration);
|
||||
declarations.push(declaration);
|
||||
}
|
||||
|
||||
function emitTempVariableAssignment(value: Expression, location: TextRange) {
|
||||
const name = createTempVariable();
|
||||
emitAssignment(name, value, location);
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Flattens binding patterns in a variable declaration.
|
||||
*
|
||||
* @param node The VariableDeclaration to flatten.
|
||||
* @param value An optional rhs value for the binding pattern.
|
||||
*/
|
||||
export function flattenVariableDestructuring(node: VariableDeclaration, value?: Expression) {
|
||||
const declarations: VariableDeclaration[] = [];
|
||||
|
||||
flattenDestructuring(node, value, node, emitAssignment, emitTempVariableAssignment);
|
||||
|
||||
return declarations;
|
||||
|
||||
function emitAssignment(name: Identifier, value: Expression, location: TextRange, original: Node) {
|
||||
const declaration = createVariableDeclaration(name, value, location);
|
||||
if (declarations.length === 0) {
|
||||
declaration.pos = -1;
|
||||
}
|
||||
|
||||
if (isSimpleExpression(value)) {
|
||||
(<SynthesizedNode>declaration).disableSourceMap = true;
|
||||
}
|
||||
|
||||
declaration.original = original;
|
||||
declarations.push(declaration);
|
||||
aggregateTransformFlags(declaration);
|
||||
}
|
||||
|
||||
function emitTempVariableAssignment(value: Expression, location: TextRange) {
|
||||
const name = createTempVariable();
|
||||
emitAssignment(name, value, location, /*original*/ undefined);
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Flattens binding patterns in a variable declaration and transforms them into an expression.
|
||||
*
|
||||
* @param node The VariableDeclaration to flatten.
|
||||
* @param recordTempVariable A callback used to record new temporary variables.
|
||||
*/
|
||||
export function flattenVariableDestructuringToExpression(node: VariableDeclaration, recordTempVariable: (name: Identifier) => void) {
|
||||
const pendingAssignments: Expression[] = [];
|
||||
|
||||
flattenDestructuring(node, /*value*/ undefined, node, emitAssignment, emitTempVariableAssignment);
|
||||
|
||||
const expression = inlineExpressions(pendingAssignments);
|
||||
aggregateTransformFlags(expression);
|
||||
return expression;
|
||||
|
||||
function emitAssignment(name: Identifier, value: Expression, location: TextRange, original: Node) {
|
||||
const expression = createAssignment(name, value, location);
|
||||
if (isSimpleExpression(value)) {
|
||||
(<SynthesizedNode>expression).disableSourceMap = true;
|
||||
}
|
||||
|
||||
expression.original = original;
|
||||
pendingAssignments.push(expression);
|
||||
}
|
||||
|
||||
function emitTempVariableAssignment(value: Expression, location: TextRange) {
|
||||
const name = createTempVariable();
|
||||
recordTempVariable(name);
|
||||
emitAssignment(name, value, location, /*original*/ undefined);
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
function flattenDestructuring(
|
||||
root: BindingElement | BinaryExpression,
|
||||
value: Expression,
|
||||
location: TextRange,
|
||||
emitAssignment: (name: Identifier, value: Expression, location: TextRange, original: Node) => void,
|
||||
emitTempVariableAssignment: (value: Expression, location: TextRange) => Identifier) {
|
||||
if (isBinaryExpression(root)) {
|
||||
emitDestructuringAssignment(root.left, value, location)
|
||||
}
|
||||
else {
|
||||
emitBindingElement(root, value);
|
||||
}
|
||||
|
||||
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 (bindingTarget.objectAssignmentInitializer) {
|
||||
value = createDefaultValueCheck(value, bindingTarget.objectAssignmentInitializer, location);
|
||||
}
|
||||
|
||||
target = bindingTarget.name;
|
||||
}
|
||||
else if (isBinaryExpression(bindingTarget) && bindingTarget.operatorToken.kind === SyntaxKind.EqualsToken) {
|
||||
value = createDefaultValueCheck(value, bindingTarget.right, location);
|
||||
target = bindingTarget.left;
|
||||
}
|
||||
else {
|
||||
target = bindingTarget;
|
||||
}
|
||||
|
||||
if (target.kind === SyntaxKind.ObjectLiteralExpression) {
|
||||
emitObjectLiteralAssignment(<ObjectLiteralExpression>target, value, location);
|
||||
}
|
||||
else if (target.kind === SyntaxKind.ArrayLiteralExpression) {
|
||||
emitArrayLiteralAssignment(<ArrayLiteralExpression>target, value, location);
|
||||
}
|
||||
else {
|
||||
const name = cloneNode(<Identifier>target, /*location*/ target, /*flags*/ undefined, /*parent*/ undefined, /*original*/ target);
|
||||
emitAssignment(name, value, location, /*original*/ undefined);
|
||||
}
|
||||
}
|
||||
|
||||
function emitObjectLiteralAssignment(target: ObjectLiteralExpression, value: Expression, location: TextRange) {
|
||||
const properties = target.properties;
|
||||
if (properties.length !== 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 (const p of properties) {
|
||||
if (p.kind === SyntaxKind.PropertyAssignment || p.kind === SyntaxKind.ShorthandPropertyAssignment) {
|
||||
const propName = <Identifier | LiteralExpression>(<PropertyAssignment>p).name;
|
||||
const target = p.kind === SyntaxKind.ShorthandPropertyAssignment ? <ShorthandPropertyAssignment>p : (<PropertyAssignment>p).initializer || propName;
|
||||
// Assignment for target = value.propName should highligh whole property, hence use p as source map node
|
||||
emitDestructuringAssignment(target, createDestructuringPropertyAccess(value, propName), p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function emitArrayLiteralAssignment(target: ArrayLiteralExpression, value: Expression, location: TextRange) {
|
||||
const elements = target.elements;
|
||||
if (elements.length !== 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++) {
|
||||
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) {
|
||||
emitDestructuringAssignment((<SpreadElementExpression>e).expression, createArraySlice(value, i), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function emitBindingElement(target: BindingElement, value: Expression) {
|
||||
// Any temporary assignments needed to emit target = value should point to target
|
||||
if (target.initializer) {
|
||||
// Combine value and initializer
|
||||
value = value ? createDefaultValueCheck(value, target.initializer, target) : target.initializer;
|
||||
}
|
||||
else if (!value) {
|
||||
// Use 'void 0' in absence of value and initializer
|
||||
value = createVoidZero();
|
||||
}
|
||||
|
||||
const name = target.name;
|
||||
if (isBindingPattern(name)) {
|
||||
const elements = name.elements;
|
||||
const numElements = elements.length;
|
||||
if (numElements !== 1) {
|
||||
// For anything other than a single-element destructuring we need to generate a temporary
|
||||
// to ensure value is evaluated exactly once. Additionally, if we have zero elements
|
||||
// we need to emit *something* to ensure that in case a 'var' keyword was already emitted,
|
||||
// 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];
|
||||
if (name.kind === SyntaxKind.ObjectBindingPattern) {
|
||||
// Rewrite element to a declaration with an initializer that fetches property
|
||||
let propName = element.propertyName || <Identifier>element.name;
|
||||
emitBindingElement(element, createDestructuringPropertyAccess(value, propName));
|
||||
}
|
||||
else if (element.kind !== SyntaxKind.OmittedExpression) {
|
||||
if (!element.dotDotDotToken) {
|
||||
// Rewrite element to a declaration that accesses array element at index i
|
||||
emitBindingElement(element, createElementAccess(value, i));
|
||||
}
|
||||
else if (i === elements.length - 1) {
|
||||
emitBindingElement(element, createArraySlice(value, i));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
const clonedName = cloneNode(name, /*location*/ undefined, /*flags*/ undefined, /*parent*/ undefined, /*original*/ name);
|
||||
emitAssignment(clonedName, value, target, target);
|
||||
}
|
||||
}
|
||||
|
||||
function createDefaultValueCheck(value: Expression, defaultValue: Expression, location: TextRange): Expression {
|
||||
value = ensureIdentifier(value, /*reuseIdentifierExpressions*/ true, location, emitTempVariableAssignment);
|
||||
return createConditional(
|
||||
createStrictEquality(value, createVoidZero()),
|
||||
defaultValue,
|
||||
value
|
||||
);
|
||||
}
|
||||
|
||||
function createDestructuringPropertyAccess(object: Expression, propertyName: PropertyName): LeftHandSideExpression {
|
||||
if (isComputedPropertyName(propertyName)) {
|
||||
return createElementAccess(
|
||||
object,
|
||||
ensureIdentifier(propertyName.expression, /*reuseIdentifierExpressions*/ false, propertyName, emitTempVariableAssignment)
|
||||
);
|
||||
}
|
||||
else if (isIdentifier(propertyName)) {
|
||||
return createPropertyAccess(
|
||||
object,
|
||||
propertyName.text
|
||||
);
|
||||
}
|
||||
else {
|
||||
// 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,
|
||||
cloneNode(propertyName)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that there exists a declared identifier whose value holds the given expression.
|
||||
* This function is useful to ensure that the expression's value can be read from in subsequent expressions.
|
||||
* Unless 'reuseIdentifierExpressions' is false, 'value' will be returned if it is just an identifier.
|
||||
*
|
||||
* @param value the expression whose value needs to be bound.
|
||||
* @param reuseIdentifierExpressions true if identifier expressions can simply be returned;
|
||||
* false if it is necessary to always emit an identifier.
|
||||
* @param location The location to use for source maps and comments.
|
||||
* @param emitTempVariableAssignment A callback used to emit a temporary variable.
|
||||
*/
|
||||
function ensureIdentifier(
|
||||
value: Expression,
|
||||
reuseIdentifierExpressions: boolean,
|
||||
location: TextRange,
|
||||
emitTempVariableAssignment: (value: Expression, location: TextRange) => Identifier) {
|
||||
if (isIdentifier(value) && reuseIdentifierExpressions) {
|
||||
return value;
|
||||
}
|
||||
else {
|
||||
return emitTempVariableAssignment(value, location);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/// <reference path="../factory.ts" />
|
||||
/// <reference path="../visitor.ts" />
|
||||
|
||||
/*@internal*/
|
||||
namespace ts {
|
||||
// TODO(rbuckton): ES6->ES5 transformer
|
||||
export function transformES6(context: TransformationContext) {
|
||||
return transformSourceFile;
|
||||
|
||||
function transformSourceFile(node: SourceFile) {
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
|
||||
function visitor(node: Node): Node {
|
||||
if (node.transformFlags & TransformFlags.ES6) {
|
||||
return visitorWorker(node);
|
||||
}
|
||||
else if (node.transformFlags & TransformFlags.ContainsES6) {
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
else {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
function visitorWorker(node: Node): Node {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/// <reference path="../factory.ts" />
|
||||
/// <reference path="../visitor.ts" />
|
||||
|
||||
/*@internal*/
|
||||
namespace ts {
|
||||
// TODO(rbuckton): ES7->ES6 transformer
|
||||
export function transformES7(context: TransformationContext) {
|
||||
const { hoistVariableDeclaration } = context;
|
||||
|
||||
return transformSourceFile;
|
||||
|
||||
function transformSourceFile(node: SourceFile) {
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
|
||||
function visitor(node: Node): Node {
|
||||
if (node.transformFlags & TransformFlags.ES7) {
|
||||
return visitorWorker(node);
|
||||
}
|
||||
else if (node.transformFlags & TransformFlags.ContainsES7) {
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
else {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
function visitorWorker(node: Node) {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/// <reference path="../factory.ts" />
|
||||
/// <reference path="../visitor.ts" />
|
||||
|
||||
/*@internal*/
|
||||
namespace ts {
|
||||
// TODO(rbuckton): JSX->React transformer
|
||||
export function transformJsx(context: TransformationContext) {
|
||||
return transformSourceFile;
|
||||
|
||||
function transformSourceFile(node: SourceFile) {
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
|
||||
function visitor(node: Node): Node {
|
||||
if (node.transformFlags & TransformFlags.Jsx) {
|
||||
return visitorWorker(node);
|
||||
}
|
||||
else if (node.transformFlags & TransformFlags.ContainsJsx) {
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
else {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
function visitorWorker(node: Node): Node {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
/// <reference path="../../factory.ts" />
|
||||
/// <reference path="../../visitor.ts" />
|
||||
|
||||
/*@internal*/
|
||||
namespace ts {
|
||||
export function transformES6Module(context: TransformationContext) {
|
||||
return transformSourceFile;
|
||||
|
||||
function transformSourceFile(node: SourceFile) {
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
|
||||
function visitor(node: Node): Node {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
/// <reference path="../../factory.ts" />
|
||||
/// <reference path="../../visitor.ts" />
|
||||
|
||||
/*@internal*/
|
||||
namespace ts {
|
||||
// TODO(rbuckton): CommonJS/AMD/UMD transformer
|
||||
export function transformModule(context: TransformationContext) {
|
||||
return transformSourceFile;
|
||||
|
||||
function transformSourceFile(node: SourceFile) {
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
|
||||
function visitor(node: Node): Node {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
/// <reference path="../../factory.ts" />
|
||||
/// <reference path="../../visitor.ts" />
|
||||
|
||||
/*@internal*/
|
||||
namespace ts {
|
||||
// TODO(rbuckton): System module transformer
|
||||
export function transformSystemModule(context: TransformationContext) {
|
||||
return transformSourceFile;
|
||||
|
||||
function transformSourceFile(node: SourceFile) {
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
|
||||
function visitor(node: Node): Node {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/// <reference path="../factory.ts" />
|
||||
/// <reference path="../visitor.ts" />
|
||||
|
||||
/*@internal*/
|
||||
namespace ts {
|
||||
// TODO(rbuckton): TS->ES7 transformer
|
||||
export function transformTypeScript(context: TransformationContext) {
|
||||
return transformSourceFile;
|
||||
|
||||
function transformSourceFile(node: SourceFile) {
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
|
||||
function visitor(node: Node) {
|
||||
if (node.transformFlags & TransformFlags.TypeScript) {
|
||||
return visitorWorker(node);
|
||||
}
|
||||
else if (node.transformFlags & TransformFlags.ContainsTypeScript) {
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
else {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
function visitorWorker(node: Node): Node {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2508,8 +2508,10 @@ namespace ts {
|
||||
ES3 = 0,
|
||||
ES5 = 1,
|
||||
ES6 = 2,
|
||||
ES7 = 3,
|
||||
ES2015 = ES6,
|
||||
Latest = ES6,
|
||||
ES2016 = ES7,
|
||||
Latest = ES7,
|
||||
}
|
||||
|
||||
export const enum LanguageVariant {
|
||||
|
||||
@@ -11,7 +11,8 @@ namespace ts {
|
||||
export interface SynthesizedNode extends Node {
|
||||
leadingCommentRanges?: CommentRange[];
|
||||
trailingCommentRanges?: CommentRange[];
|
||||
startsOnNewLine: boolean;
|
||||
startsOnNewLine?: boolean;
|
||||
disableSourceMap?: boolean;
|
||||
}
|
||||
|
||||
export function getDeclarationOfKind(symbol: Symbol, kind: SyntaxKind): Declaration {
|
||||
@@ -2724,6 +2725,68 @@ namespace ts {
|
||||
return carriageReturnLineFeed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether a node and its subtree is simple enough to have its position
|
||||
* information ignored when emitting source maps in a destructuring assignment.
|
||||
*
|
||||
* @param node The expression to test.
|
||||
*/
|
||||
export function isSimpleExpression(node: Expression): boolean {
|
||||
return isSimpleExpressionWorker(node, 0);
|
||||
}
|
||||
|
||||
function isSimpleExpressionWorker(node: Expression, depth: number): boolean {
|
||||
if (depth <= 5) {
|
||||
const kind = node.kind;
|
||||
if (kind === SyntaxKind.StringLiteral
|
||||
|| kind === SyntaxKind.NumericLiteral
|
||||
|| kind === SyntaxKind.RegularExpressionLiteral
|
||||
|| kind === SyntaxKind.NoSubstitutionTemplateLiteral
|
||||
|| kind === SyntaxKind.Identifier
|
||||
|| kind === SyntaxKind.ThisKeyword
|
||||
|| kind === SyntaxKind.SuperKeyword
|
||||
|| kind === SyntaxKind.TrueKeyword
|
||||
|| kind === SyntaxKind.FalseKeyword
|
||||
|| kind === SyntaxKind.NullKeyword) {
|
||||
return true;
|
||||
}
|
||||
else if (kind === SyntaxKind.PropertyAccessExpression) {
|
||||
return isSimpleExpressionWorker((<PropertyAccessExpression>node).expression, depth + 1);
|
||||
}
|
||||
else if (kind === SyntaxKind.ElementAccessExpression) {
|
||||
return isSimpleExpressionWorker((<ElementAccessExpression>node).expression, depth + 1)
|
||||
&& isSimpleExpressionWorker((<ElementAccessExpression>node).argumentExpression, depth + 1);
|
||||
}
|
||||
else if (kind === SyntaxKind.PrefixUnaryExpression
|
||||
|| kind === SyntaxKind.PostfixUnaryExpression) {
|
||||
return isSimpleExpressionWorker((<PrefixUnaryExpression | PostfixUnaryExpression>node).operand, depth + 1);
|
||||
}
|
||||
else if (kind === SyntaxKind.BinaryExpression) {
|
||||
return (<BinaryExpression>node).operatorToken.kind !== SyntaxKind.AsteriskAsteriskToken
|
||||
&& isSimpleExpressionWorker((<BinaryExpression>node).left, depth + 1)
|
||||
&& isSimpleExpressionWorker((<BinaryExpression>node).right, depth + 1);
|
||||
}
|
||||
else if (kind === SyntaxKind.ConditionalExpression) {
|
||||
return isSimpleExpressionWorker((<ConditionalExpression>node).condition, depth + 1)
|
||||
&& isSimpleExpressionWorker((<ConditionalExpression>node).whenTrue, depth + 1)
|
||||
&& isSimpleExpressionWorker((<ConditionalExpression>node).whenFalse, depth + 1)
|
||||
}
|
||||
else if (kind === SyntaxKind.VoidExpression
|
||||
|| kind === SyntaxKind.TypeOfExpression
|
||||
|| kind === SyntaxKind.DeleteExpression) {
|
||||
return isSimpleExpressionWorker((<VoidExpression | TypeOfExpression | DeleteExpression>node).expression, depth + 1);
|
||||
}
|
||||
else if (kind === SyntaxKind.ArrayLiteralExpression) {
|
||||
return (<ArrayLiteralExpression>node).elements.length === 0;
|
||||
}
|
||||
else if (kind === SyntaxKind.ObjectLiteralExpression) {
|
||||
return (<ObjectLiteralExpression>node).properties.length === 0;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Node tests
|
||||
//
|
||||
// All node tests in the following list should *not* reference parent pointers so that
|
||||
|
||||
Reference in New Issue
Block a user