mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-15 03:23:08 -06:00
WIP Clean up destructuring
This commit is contained in:
parent
d537b79c61
commit
8babde0b98
@ -811,6 +811,13 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
export function appendProperty<T>(map: Map<T>, key: string | number, value: T): Map<T> {
|
||||
if (key === undefined || value === undefined) return map;
|
||||
if (map === undefined) map = createMap<T>();
|
||||
map[key] = value;
|
||||
return map;
|
||||
}
|
||||
|
||||
export function assign<T1 extends MapLike<{}>, T2, T3>(t: T1, arg1: T2, arg2: T3): T1 & T2 & T3;
|
||||
export function assign<T1 extends MapLike<{}>, T2>(t: T1, arg1: T2): T1 & T2;
|
||||
export function assign<T1 extends MapLike<{}>>(t: T1, ...args: any[]): any;
|
||||
|
||||
@ -238,9 +238,9 @@ namespace ts {
|
||||
return node;
|
||||
}
|
||||
|
||||
export function updateParameter(node: ParameterDeclaration, decorators: Decorator[], modifiers: Modifier[], name: BindingName, type: TypeNode, initializer: Expression) {
|
||||
if (node.decorators !== decorators || node.modifiers !== modifiers || node.name !== name || node.type !== type || node.initializer !== initializer) {
|
||||
return updateNode(createParameter(decorators, modifiers, node.dotDotDotToken, name, node.questionToken, type, initializer, /*location*/ node, /*flags*/ node.flags), node);
|
||||
export function updateParameter(node: ParameterDeclaration, decorators: Decorator[], modifiers: Modifier[], dotDotDotToken: DotDotDotToken, name: BindingName, type: TypeNode, initializer: Expression) {
|
||||
if (node.decorators !== decorators || node.modifiers !== modifiers || node.dotDotDotToken !== dotDotDotToken || node.name !== name || node.type !== type || node.initializer !== initializer) {
|
||||
return updateNode(createParameter(decorators, modifiers, dotDotDotToken, name, node.questionToken, type, initializer, /*location*/ node, /*flags*/ node.flags), node);
|
||||
}
|
||||
|
||||
return node;
|
||||
@ -378,9 +378,9 @@ namespace ts {
|
||||
return node;
|
||||
}
|
||||
|
||||
export function updateBindingElement(node: BindingElement, propertyName: PropertyName, name: BindingName, initializer: Expression) {
|
||||
if (node.propertyName !== propertyName || node.name !== name || node.initializer !== initializer) {
|
||||
return updateNode(createBindingElement(propertyName, node.dotDotDotToken, name, initializer, node), node);
|
||||
export function updateBindingElement(node: BindingElement, dotDotDotToken: DotDotDotToken, propertyName: PropertyName, name: BindingName, initializer: Expression) {
|
||||
if (node.propertyName !== propertyName || node.dotDotDotToken !== dotDotDotToken || node.name !== name || node.initializer !== initializer) {
|
||||
return updateNode(createBindingElement(propertyName, dotDotDotToken, name, initializer, node), node);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
@ -1635,7 +1635,7 @@ namespace ts {
|
||||
// flag and setting a parent node.
|
||||
const react = createIdentifier(reactNamespace || "React");
|
||||
react.flags &= ~NodeFlags.Synthesized;
|
||||
// Set the parent that is in parse tree
|
||||
// Set the parent that is in parse tree
|
||||
// this makes sure that parent chain is intact for checker to traverse complete scope tree
|
||||
react.parent = getParseTreeNode(parent);
|
||||
return react;
|
||||
|
||||
@ -3,6 +3,18 @@
|
||||
|
||||
/*@internal*/
|
||||
namespace ts {
|
||||
type EffectiveBindingElement = VariableDeclaration | ParameterDeclaration | BindingElement | ObjectLiteralElementLike | Expression;
|
||||
type EffectiveObjectBindingPattern = ObjectBindingPattern | ObjectLiteralExpression;
|
||||
type EffectiveArrayBindingPattern = ArrayBindingPattern | ArrayLiteralExpression;
|
||||
type EffectiveBindingPattern = EffectiveObjectBindingPattern | EffectiveArrayBindingPattern;
|
||||
type EffectiveBindingTarget = EffectiveBindingPattern | Expression;
|
||||
type EffectiveRestIndicator = DotDotDotToken | SpreadElement | SpreadAssignment;
|
||||
|
||||
export const enum FlattenLevel {
|
||||
All,
|
||||
ObjectRestDestructuringOnly,
|
||||
}
|
||||
|
||||
/**
|
||||
* Flattens a destructuring assignment expression.
|
||||
*
|
||||
@ -40,7 +52,7 @@ namespace ts {
|
||||
//
|
||||
// The source map location for the assignment should point to the entire binary
|
||||
// expression.
|
||||
value = ensureIdentifier(value, /*reuseIdentifierExpressions*/ true, location, emitTempVariableAssignment, visitor);
|
||||
value = ensureIdentifierOld(value, /*reuseIdentifierExpressions*/ true, location, emitTempVariableAssignment, visitor);
|
||||
}
|
||||
else if (nodeIsSynthesized(node)) {
|
||||
// Generally, the source map location for a destructuring assignment is the root
|
||||
@ -52,7 +64,7 @@ namespace ts {
|
||||
location = value;
|
||||
}
|
||||
|
||||
flattenDestructuring(node, value, location, emitAssignment, emitTempVariableAssignment, recordTempVariable, emitRestAssignment, transformRest, visitor);
|
||||
flattenDestructuringOld(node, value, location, emitAssignment, emitTempVariableAssignment, recordTempVariable, emitRestAssignment, transformRest, visitor);
|
||||
|
||||
if (needsValue) {
|
||||
expressions.push(value);
|
||||
@ -98,7 +110,7 @@ namespace ts {
|
||||
transformRest?: boolean) {
|
||||
const declarations: VariableDeclaration[] = [];
|
||||
|
||||
flattenDestructuring(node, value, node, emitAssignment, emitTempVariableAssignment, noop, emitRestAssignment, transformRest, visitor);
|
||||
flattenDestructuringOld(node, value, node, emitAssignment, emitTempVariableAssignment, noop, emitRestAssignment, transformRest, visitor);
|
||||
|
||||
return declarations;
|
||||
|
||||
@ -140,7 +152,7 @@ namespace ts {
|
||||
const declarations: VariableDeclaration[] = [];
|
||||
|
||||
let pendingAssignments: Expression[];
|
||||
flattenDestructuring(node, value, node, emitAssignment, emitTempVariableAssignment, recordTempVariable, emitRestAssignment, transformRest, visitor);
|
||||
flattenDestructuringOld(node, value, node, emitAssignment, emitTempVariableAssignment, recordTempVariable, emitRestAssignment, transformRest, visitor);
|
||||
|
||||
return declarations;
|
||||
|
||||
@ -201,7 +213,7 @@ namespace ts {
|
||||
|
||||
const pendingAssignments: Expression[] = [];
|
||||
|
||||
flattenDestructuring(node, /*value*/ undefined, node, emitAssignment, emitTempVariableAssignment, noop, emitRestAssignment, /*transformRest*/ false, visitor);
|
||||
flattenDestructuringOld(node, /*value*/ undefined, node, emitAssignment, emitTempVariableAssignment, noop, emitRestAssignment, /*transformRest*/ false, visitor);
|
||||
|
||||
const expression = inlineExpressions(pendingAssignments);
|
||||
aggregateTransformFlags(expression);
|
||||
@ -238,7 +250,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function flattenDestructuring(
|
||||
function flattenDestructuringOld(
|
||||
root: VariableDeclaration | ParameterDeclaration | BindingElement | BinaryExpression,
|
||||
value: Expression,
|
||||
location: TextRange,
|
||||
@ -305,7 +317,7 @@ namespace ts {
|
||||
// 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);
|
||||
value = ensureIdentifierOld(value, /*reuseIdentifierExpressions*/ true, location, emitTempVariableAssignment);
|
||||
}
|
||||
|
||||
let bindingElements: ObjectLiteralElementLike[] = [];
|
||||
@ -361,7 +373,7 @@ namespace ts {
|
||||
// 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 highlight the passed-in source map node since thats the one needing this temp assignment
|
||||
value = ensureIdentifier(value, /*reuseIdentifierExpressions*/ true, location, emitTempVariableAssignment);
|
||||
value = ensureIdentifierOld(value, /*reuseIdentifierExpressions*/ true, location, emitTempVariableAssignment);
|
||||
}
|
||||
|
||||
const expressions: Expression[] = [];
|
||||
@ -393,7 +405,7 @@ namespace ts {
|
||||
// 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 highlight the passed-in source map node since thats the one needing this temp assignment
|
||||
value = ensureIdentifier(value, /*reuseIdentifierExpressions*/ true, location, emitTempVariableAssignment);
|
||||
value = ensureIdentifierOld(value, /*reuseIdentifierExpressions*/ true, location, emitTempVariableAssignment);
|
||||
}
|
||||
|
||||
for (let i = 0; i < numElements; i++) {
|
||||
@ -454,7 +466,7 @@ namespace ts {
|
||||
// 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);
|
||||
value = ensureIdentifierOld(value, /*reuseIdentifierExpressions*/ numElements !== 0, target, emitTempVariableAssignment);
|
||||
}
|
||||
if (name.kind === SyntaxKind.ArrayBindingPattern) {
|
||||
emitArrayBindingElement(name as ArrayBindingPattern, value);
|
||||
@ -558,7 +570,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function createDefaultValueCheck(value: Expression, defaultValue: Expression, location: TextRange): Expression {
|
||||
value = ensureIdentifier(value, /*reuseIdentifierExpressions*/ true, location, emitTempVariableAssignment);
|
||||
value = ensureIdentifierOld(value, /*reuseIdentifierExpressions*/ true, location, emitTempVariableAssignment);
|
||||
return createConditional(
|
||||
createStrictEquality(value, createVoidZero()),
|
||||
createToken(SyntaxKind.QuestionToken),
|
||||
@ -579,7 +591,7 @@ namespace ts {
|
||||
if (isComputedPropertyName(propertyName)) {
|
||||
return createElementAccess(
|
||||
expression,
|
||||
ensureIdentifier(propertyName.expression, /*reuseIdentifierExpressions*/ false, /*location*/ propertyName, emitTempVariableAssignment)
|
||||
ensureIdentifierOld(propertyName.expression, /*reuseIdentifierExpressions*/ false, /*location*/ propertyName, emitTempVariableAssignment)
|
||||
);
|
||||
}
|
||||
else if (isLiteralExpression(propertyName)) {
|
||||
@ -612,7 +624,7 @@ namespace ts {
|
||||
* @param emitTempVariableAssignment A callback used to emit a temporary variable.
|
||||
* @param visitor An optional callback used to visit the value.
|
||||
*/
|
||||
function ensureIdentifier(
|
||||
function ensureIdentifierOld(
|
||||
value: Expression,
|
||||
reuseIdentifierExpressions: boolean,
|
||||
location: TextRange,
|
||||
@ -630,4 +642,724 @@ namespace ts {
|
||||
return emitTempVariableAssignment(value, location);
|
||||
}
|
||||
}
|
||||
|
||||
interface FlattenHost {
|
||||
context: TransformationContext;
|
||||
level: FlattenLevel;
|
||||
recordTempVariablesInLine: boolean;
|
||||
emitAssignment: (target: EffectiveBindingTarget, value: Expression, location: TextRange, original: Node) => void;
|
||||
emitArrayAssignment: (elements: EffectiveBindingElement[], value: Expression, location: TextRange, original: Node) => void;
|
||||
emitObjectAssignment: (elements: EffectiveBindingElement[], value: Expression, location: TextRange, original: Node) => void;
|
||||
emitExpression: (value: Expression) => void;
|
||||
}
|
||||
|
||||
export function flattenDestructuringToDeclarations(
|
||||
context: TransformationContext,
|
||||
node: VariableDeclaration | ParameterDeclaration,
|
||||
boundValue: Expression | undefined,
|
||||
recordTempVariablesInLine: boolean,
|
||||
level: FlattenLevel): VisitResult<VariableDeclaration> {
|
||||
|
||||
const pendingDeclarations: { pendingExpressions?: Expression[], name: BindingName, value: Expression, location?: TextRange, original?: Node; }[] = [];
|
||||
let pendingExpressions: Expression[];
|
||||
let declaration: VariableDeclaration;
|
||||
let declarations: VariableDeclaration[];
|
||||
const host: FlattenHost = {
|
||||
context,
|
||||
level,
|
||||
recordTempVariablesInLine,
|
||||
emitExpression,
|
||||
emitAssignment,
|
||||
emitArrayAssignment,
|
||||
emitObjectAssignment
|
||||
};
|
||||
|
||||
flattenEffectiveBindingElement(host, node, boundValue, node);
|
||||
|
||||
if (pendingExpressions) {
|
||||
const temp = createTempVariable(/*recordTempVariable*/ undefined);
|
||||
if (recordTempVariablesInLine) {
|
||||
const value = inlineExpressions(pendingExpressions);
|
||||
pendingExpressions = undefined;
|
||||
emitAssignment(temp, value, /*location*/ undefined, /*original*/ undefined);
|
||||
}
|
||||
else {
|
||||
context.hoistVariableDeclaration(temp);
|
||||
const pendingDeclaration = lastOrUndefined(pendingDeclarations);
|
||||
pendingDeclaration.pendingExpressions = append(
|
||||
pendingDeclaration.pendingExpressions,
|
||||
createAssignment(temp, pendingDeclaration.value)
|
||||
);
|
||||
addRange(pendingDeclaration.pendingExpressions, pendingExpressions);
|
||||
pendingDeclaration.value = temp;
|
||||
}
|
||||
}
|
||||
|
||||
for (const { pendingExpressions, name, value, location, original } of pendingDeclarations) {
|
||||
const variable = createVariableDeclaration(
|
||||
name,
|
||||
/*type*/ undefined,
|
||||
pendingExpressions ? inlineExpressions(append(pendingExpressions, value)) : value,
|
||||
location);
|
||||
variable.original = original;
|
||||
if (isIdentifier(name)) {
|
||||
setEmitFlags(variable, EmitFlags.NoNestedSourceMaps);
|
||||
}
|
||||
aggregateTransformFlags(variable);
|
||||
if (!declaration) {
|
||||
declaration = variable;
|
||||
}
|
||||
else if (!declarations) {
|
||||
declarations = [declaration, variable];
|
||||
}
|
||||
else {
|
||||
declarations.push(variable);
|
||||
}
|
||||
}
|
||||
|
||||
return declarations || declaration;
|
||||
|
||||
function emitExpression(value: Expression) {
|
||||
pendingExpressions = append(pendingExpressions, value);
|
||||
}
|
||||
|
||||
function emitAssignment(target: EffectiveBindingTarget, value: Expression, location: TextRange, original: Node) {
|
||||
Debug.assertNode(target, isBindingName);
|
||||
pendingDeclarations.push({ pendingExpressions, name: <BindingName>target, value, location, original });
|
||||
if (pendingExpressions) {
|
||||
value = inlineExpressions(append(pendingExpressions, value));
|
||||
pendingExpressions = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
function emitArrayAssignment(elements: EffectiveBindingElement[], value: Expression, location: TextRange, original: Node) {
|
||||
Debug.assertEachNode(elements, isArrayBindingElement);
|
||||
emitAssignment(createArrayBindingPattern(<ArrayBindingElement[]>elements), value, location, original);
|
||||
}
|
||||
|
||||
function emitObjectAssignment(elements: EffectiveBindingElement[], value: Expression, location: TextRange, original: Node) {
|
||||
Debug.assertEachNode(elements, isBindingElement);
|
||||
emitAssignment(createObjectBindingPattern(<BindingElement[]>elements), value, location, original);
|
||||
}
|
||||
}
|
||||
|
||||
function flattenEffectiveBindingElement(
|
||||
host: FlattenHost,
|
||||
bindingElement: EffectiveBindingElement,
|
||||
boundValue: Expression | undefined,
|
||||
location: TextRange,
|
||||
skipInitializer?: boolean) {
|
||||
if (!skipInitializer) {
|
||||
const initializer = getInitializerOfEffectiveBindingElement(bindingElement);
|
||||
if (initializer) {
|
||||
// Combine value and initializer
|
||||
boundValue = boundValue ? createDefaultValueCheck(host, boundValue, initializer, location) : initializer;
|
||||
}
|
||||
else if (!boundValue) {
|
||||
// Use 'void 0' in absence of value and initializer
|
||||
boundValue = createVoidZero();
|
||||
}
|
||||
}
|
||||
const bindingTarget = getTargetOfEffectiveBindingElement(bindingElement);
|
||||
if (!isEffectiveBindingPattern(bindingTarget)) {
|
||||
host.emitAssignment(bindingTarget, boundValue, location, /*original*/ bindingElement);
|
||||
}
|
||||
else {
|
||||
const elements = getElementsOfEffectiveBindingPattern(bindingTarget);
|
||||
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.
|
||||
const reuseIdentifierExpressions = !isDeclarationBindingElement(bindingElement) || numElements !== 0;
|
||||
boundValue = ensureIdentifier(host, boundValue, reuseIdentifierExpressions, location);
|
||||
}
|
||||
if (isEffectiveObjectBindingPattern(bindingTarget)) {
|
||||
flattenEffectiveObjectBindingElements(host, bindingTarget, elements, boundValue, location);
|
||||
}
|
||||
else {
|
||||
flattenEffectiveArrayBindingElements(host, bindingTarget, elements, boundValue, location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function flattenEffectiveObjectBindingElements(host: FlattenHost, bindingTarget: EffectiveObjectBindingPattern, elements: EffectiveBindingElement[], boundValue: Expression, location: TextRange) {
|
||||
let bindingElements: EffectiveBindingElement[];
|
||||
const numElements = elements.length;
|
||||
for (let i = 0; i < numElements; i++) {
|
||||
const element = elements[i];
|
||||
if (!getEffectiveRestIndicator(element)) {
|
||||
if (host.level >= FlattenLevel.ObjectRestDestructuringOnly && !(element.transformFlags & TransformFlags.ContainsSpreadExpression)) {
|
||||
bindingElements = append(bindingElements, element);
|
||||
}
|
||||
else {
|
||||
if (bindingElements) {
|
||||
host.emitObjectAssignment(bindingElements, boundValue, location, bindingTarget);
|
||||
bindingElements = undefined;
|
||||
}
|
||||
const propertyName = getEffectivePropertyNameOfEffectiveBindingElement(element);
|
||||
const value = createDestructuringPropertyAccess(host, boundValue, propertyName);
|
||||
flattenEffectiveBindingElement(host, element, value, /*location*/ element);
|
||||
}
|
||||
}
|
||||
else if (i === numElements - 1) {
|
||||
if (bindingElements) {
|
||||
host.emitObjectAssignment(bindingElements, boundValue, location, bindingTarget);
|
||||
bindingElements = undefined;
|
||||
}
|
||||
const value = createRestCall(boundValue, elements, bindingTarget);
|
||||
flattenEffectiveBindingElement(host, element, value, element);
|
||||
}
|
||||
}
|
||||
if (bindingElements) {
|
||||
host.emitObjectAssignment(bindingElements, boundValue, location, bindingTarget);
|
||||
}
|
||||
}
|
||||
|
||||
function flattenEffectiveArrayBindingElements(host: FlattenHost, bindingTarget: EffectiveArrayBindingPattern, elements: EffectiveBindingElement[], boundValue: Expression, location: TextRange) {
|
||||
let bindingElements: EffectiveBindingElement[];
|
||||
let spreadContainingElements: EffectiveBindingElement[];
|
||||
let tempNames: Map<Identifier>;
|
||||
const numElements = elements.length;
|
||||
for (let i = 0; i < numElements; i++) {
|
||||
const element = elements[i];
|
||||
if (isOmittedExpression(element)) {
|
||||
continue;
|
||||
}
|
||||
else if (host.level >= FlattenLevel.ObjectRestDestructuringOnly) {
|
||||
if (element.transformFlags & TransformFlags.ContainsSpreadExpression) {
|
||||
const temp = createTempVariable(/*recordTempVariable*/ undefined);
|
||||
tempNames = appendProperty(tempNames, getNodeId(element), temp);
|
||||
spreadContainingElements = append(spreadContainingElements, element);
|
||||
bindingElements = append(bindingElements, temp);
|
||||
}
|
||||
else {
|
||||
bindingElements = append(bindingElements, element);
|
||||
}
|
||||
}
|
||||
else if (!getEffectiveRestIndicator(element)) {
|
||||
const value = createElementAccess(boundValue, i);
|
||||
flattenEffectiveBindingElement(host, element, value, /*location*/ element);
|
||||
}
|
||||
else if (i === numElements - 1) {
|
||||
const value = createArraySlice(boundValue, i);
|
||||
flattenEffectiveBindingElement(host, element, value, /*location*/ element);
|
||||
}
|
||||
}
|
||||
if (bindingElements) {
|
||||
host.emitArrayAssignment(bindingElements, boundValue, location, bindingTarget);
|
||||
}
|
||||
if (spreadContainingElements) {
|
||||
for (const element of spreadContainingElements) {
|
||||
flattenEffectiveBindingElement(host, element, tempNames[getNodeId(element)], element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an expression used to provide a default value if a value is `undefined` at runtime.
|
||||
*/
|
||||
function createDefaultValueCheck(host: FlattenHost, value: Expression, defaultValue: Expression, location: TextRange): Expression {
|
||||
value = ensureIdentifier(host, value, /*reuseIdentifierExpressions*/ true, location);
|
||||
return createConditional(
|
||||
createStrictEquality(value, createVoidZero()),
|
||||
createToken(SyntaxKind.QuestionToken),
|
||||
defaultValue,
|
||||
createToken(SyntaxKind.ColonToken),
|
||||
value
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @param emitTempVariableAssignment A callback used to emit a temporary variable.
|
||||
*/
|
||||
function createDestructuringPropertyAccess(host: FlattenHost, expression: Expression, propertyName: PropertyName): LeftHandSideExpression {
|
||||
if (isComputedPropertyName(propertyName)) {
|
||||
const argumentExpression = ensureIdentifier(host, propertyName.expression, /*reuseIdentifierExpressions*/ false, /*location*/ propertyName);
|
||||
return createElementAccess(expression, argumentExpression);
|
||||
}
|
||||
else if (isLiteralExpression(propertyName)) {
|
||||
const argumentExpression = getSynthesizedClone(propertyName);
|
||||
argumentExpression.text = unescapeIdentifier(argumentExpression.text);
|
||||
return createElementAccess(expression, argumentExpression);
|
||||
}
|
||||
else if (isGeneratedIdentifier(propertyName)) {
|
||||
const name = getSynthesizedClone(propertyName);
|
||||
name.text = unescapeIdentifier(name.text);
|
||||
return createPropertyAccess(expression, name);
|
||||
}
|
||||
else {
|
||||
const name = createIdentifier(unescapeIdentifier(propertyName.text));
|
||||
return createPropertyAccess(expression, name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 emitTempVariableAssignment A callback used to emit a temporary variable.
|
||||
* @param location The location to use for source maps and comments.
|
||||
*/
|
||||
function ensureIdentifier(
|
||||
host: FlattenHost,
|
||||
value: Expression,
|
||||
reuseIdentifierExpressions: boolean,
|
||||
location: TextRange) {
|
||||
|
||||
if (isIdentifier(value) && reuseIdentifierExpressions) {
|
||||
return value;
|
||||
}
|
||||
else {
|
||||
const temp = createTempVariable(/*recordTempVariable*/ undefined);
|
||||
if (host.recordTempVariablesInLine) {
|
||||
host.emitAssignment(temp, value, location, /*original*/ undefined);
|
||||
}
|
||||
else {
|
||||
host.context.hoistVariableDeclaration(temp);
|
||||
host.emitExpression(createAssignment(temp, value, location));
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the EffectiveBindingElement is a declaration
|
||||
*/
|
||||
function isDeclarationBindingElement(bindingElement: EffectiveBindingElement): bindingElement is VariableDeclaration | ParameterDeclaration | BindingElement {
|
||||
switch (bindingElement.kind) {
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
case SyntaxKind.Parameter:
|
||||
case SyntaxKind.BindingElement:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the initializer of an EffectiveBindingElement.
|
||||
*/
|
||||
function getInitializerOfEffectiveBindingElement(bindingElement: EffectiveBindingElement): Expression | undefined {
|
||||
if (isDeclarationBindingElement(bindingElement)) {
|
||||
// `1` in `let { a = 1 } = ...`
|
||||
// `1` in `let { a: b = 1 } = ...`
|
||||
// `1` in `let { a: {b} = 1 } = ...`
|
||||
// `1` in `let { a: [b] = 1 } = ...`
|
||||
// `1` in `let [a = 1] = ...`
|
||||
// `1` in `let [{a} = 1] = ...`
|
||||
// `1` in `let [[a] = 1] = ...`
|
||||
return bindingElement.initializer;
|
||||
}
|
||||
|
||||
if (isPropertyAssignment(bindingElement)) {
|
||||
// `1` in `({ a: b = 1 } = ...)`
|
||||
// `1` in `({ a: {b} = 1 } = ...)`
|
||||
// `1` in `({ a: [b] = 1 } = ...)`
|
||||
return isAssignmentExpression(bindingElement.initializer, /*excludeCompoundAssignment*/ true)
|
||||
? bindingElement.initializer.right
|
||||
: undefined;
|
||||
}
|
||||
|
||||
if (isShorthandPropertyAssignment(bindingElement)) {
|
||||
// `1` in `({ a = 1 } = ...)`
|
||||
return bindingElement.objectAssignmentInitializer;
|
||||
}
|
||||
|
||||
if (isAssignmentExpression(bindingElement, /*excludeCompoundAssignment*/ true)) {
|
||||
// `1` in `[a = 1] = ...`
|
||||
// `1` in `[{a} = 1] = ...`
|
||||
// `1` in `[[a] = 1] = ...`
|
||||
return bindingElement.right;
|
||||
}
|
||||
|
||||
if (isSpreadExpression(bindingElement) || isPartiallyEmittedExpression(bindingElement)) {
|
||||
// Recovery consistent with existing emit.
|
||||
return getInitializerOfEffectiveBindingElement(bindingElement.expression);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of an EffectiveBindingElement.
|
||||
*/
|
||||
function getTargetOfEffectiveBindingElement(bindingElement: EffectiveBindingElement): EffectiveBindingTarget {
|
||||
if (isDeclarationBindingElement(bindingElement)) {
|
||||
// `a` in `let { a } = ...`
|
||||
// `a` in `let { a = 1 } = ...`
|
||||
// `b` in `let { a: b } = ...`
|
||||
// `b` in `let { a: b = 1 } = ...`
|
||||
// `a` in `let { ...a } = ...`
|
||||
// `{b}` in `let { a: {b} } = ...`
|
||||
// `{b}` in `let { a: {b} = 1 } = ...`
|
||||
// `[b]` in `let { a: [b] } = ...`
|
||||
// `[b]` in `let { a: [b] = 1 } = ...`
|
||||
// `a` in `let [a] = ...`
|
||||
// `a` in `let [a = 1] = ...`
|
||||
// `a` in `let [...a] = ...`
|
||||
// `{a}` in `let [{a}] = ...`
|
||||
// `{a}` in `let [{a} = 1] = ...`
|
||||
// `[a]` in `let [[a]] = ...`
|
||||
// `[a]` in `let [[a] = 1] = ...`
|
||||
return <ObjectBindingPattern | ArrayBindingPattern | Identifier>bindingElement.name;
|
||||
}
|
||||
|
||||
if (isObjectLiteralElementLike(bindingElement)) {
|
||||
switch (bindingElement.kind) {
|
||||
case SyntaxKind.PropertyAssignment:
|
||||
// `b` in `({ a: b } = ...)`
|
||||
// `b` in `({ a: b = 1 } = ...)`
|
||||
// `{b}` in `({ a: {b} } = ...)`
|
||||
// `{b}` in `({ a: {b} = 1 } = ...)`
|
||||
// `[b]` in `({ a: [b] } = ...)`
|
||||
// `[b]` in `({ a: [b] = 1 } = ...)`
|
||||
// `b.c` in `({ a: b.c } = ...)`
|
||||
// `b.c` in `({ a: b.c = 1 } = ...)`
|
||||
// `b[0]` in `({ a: b[0] } = ...)`
|
||||
// `b[0]` in `({ a: b[0] = 1 } = ...)`
|
||||
return getTargetOfEffectiveBindingElement(bindingElement.initializer);
|
||||
|
||||
case SyntaxKind.ShorthandPropertyAssignment:
|
||||
// `a` in `({ a } = ...)`
|
||||
// `a` in `({ a = 1 } = ...)`
|
||||
return bindingElement.name;
|
||||
|
||||
case SyntaxKind.SpreadAssignment:
|
||||
// `a` in `({ ...a } = ...)`
|
||||
return getTargetOfEffectiveBindingElement(bindingElement.expression);
|
||||
}
|
||||
|
||||
// no target
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (isAssignmentExpression(bindingElement, /*excludeCompoundAssignment*/ true)) {
|
||||
// `a` in `[a = 1] = ...`
|
||||
// `{a}` in `[{a} = 1] = ...`
|
||||
// `[a]` in `[[a] = 1] = ...`
|
||||
// `a.b` in `[a.b = 1] = ...`
|
||||
// `a[0]` in `[a[0] = 1] = ...`
|
||||
return getTargetOfEffectiveBindingElement(bindingElement.left);
|
||||
}
|
||||
|
||||
if (isSpreadExpression(bindingElement) || isPartiallyEmittedExpression(bindingElement)) {
|
||||
// `a` in `[...a] = ...`
|
||||
return getTargetOfEffectiveBindingElement(bindingElement.expression);
|
||||
}
|
||||
|
||||
// `a` in `[a] = ...`
|
||||
// `{a}` in `[{a}] = ...`
|
||||
// `[a]` in `[[a]] = ...`
|
||||
// `a.b` in `[a.b] = ...`
|
||||
// `a[0]` in `[a[0]] = ...`
|
||||
return bindingElement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether an EffectiveBindingElement is a rest element.
|
||||
*/
|
||||
function getEffectiveRestIndicator(bindingElement: EffectiveBindingElement): EffectiveRestIndicator {
|
||||
switch (bindingElement.kind) {
|
||||
case SyntaxKind.Parameter:
|
||||
case SyntaxKind.BindingElement:
|
||||
// `...` in `let [...a] = ...`
|
||||
return (<ParameterDeclaration | BindingElement>bindingElement).dotDotDotToken;
|
||||
|
||||
case SyntaxKind.SpreadElement:
|
||||
case SyntaxKind.SpreadAssignment:
|
||||
// `...` in `[...a] = ...`
|
||||
return <SpreadElement | SpreadAssignment>bindingElement;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the property name of a BindingElement-like element
|
||||
*/
|
||||
function getEffectivePropertyNameOfEffectiveBindingElement(bindingElement: EffectiveBindingElement) {
|
||||
switch (bindingElement.kind) {
|
||||
case SyntaxKind.BindingElement:
|
||||
// `a` in `let { a: b } = ...`
|
||||
// `[a]` in `let { [a]: b } = ...`
|
||||
// `"a"` in `let { "a": b } = ...`
|
||||
// `1` in `let { 1: b } = ...`
|
||||
if ((<BindingElement>bindingElement).propertyName) {
|
||||
return (<BindingElement>bindingElement).propertyName;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case SyntaxKind.PropertyAssignment:
|
||||
// `a` in `({ a: b } = ...)`
|
||||
// `[a]` in `({ [a]: b } = ...)`
|
||||
// `"a"` in `({ "a": b } = ...)`
|
||||
// `1` in `({ 1: b } = ...)`
|
||||
if ((<PropertyAssignment>bindingElement).name) {
|
||||
return (<PropertyAssignment>bindingElement).name;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case SyntaxKind.SpreadAssignment:
|
||||
// `a` in `({ ...a } = ...)`
|
||||
return (<SpreadAssignment>bindingElement).name;
|
||||
}
|
||||
|
||||
const target = getTargetOfEffectiveBindingElement(bindingElement);
|
||||
if (target && isPropertyName(target)) {
|
||||
return target;
|
||||
}
|
||||
|
||||
Debug.fail("Invalid property name for binding element.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a node is BindingPattern-like
|
||||
*/
|
||||
function isEffectiveBindingPattern(node: EffectiveBindingTarget): node is EffectiveBindingPattern {
|
||||
return isEffectiveObjectBindingPattern(node)
|
||||
|| isEffectiveArrayBindingPattern(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a node is ObjectBindingPattern-like
|
||||
*/
|
||||
function isEffectiveObjectBindingPattern(node: EffectiveBindingTarget): node is EffectiveObjectBindingPattern {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.ObjectBindingPattern:
|
||||
case SyntaxKind.ObjectLiteralExpression:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a node is ArrayBindingPattern-like
|
||||
*/
|
||||
function isEffectiveArrayBindingPattern(node: EffectiveBindingTarget): node is EffectiveArrayBindingPattern {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.ArrayBindingPattern:
|
||||
case SyntaxKind.ArrayLiteralExpression:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the elements of a BindingPattern-like name
|
||||
*/
|
||||
function getElementsOfEffectiveBindingPattern(name: EffectiveBindingPattern): EffectiveBindingElement[] {
|
||||
switch (name.kind) {
|
||||
case SyntaxKind.ObjectBindingPattern:
|
||||
case SyntaxKind.ArrayBindingPattern:
|
||||
case SyntaxKind.ArrayLiteralExpression:
|
||||
// `a` in `{a}`
|
||||
// `a` in `[a]`
|
||||
return name.elements;
|
||||
|
||||
case SyntaxKind.ObjectLiteralExpression:
|
||||
// `a` in `{a}`
|
||||
return name.properties;
|
||||
}
|
||||
}
|
||||
|
||||
// function updateEffectiveBindingElement(bindingElement: EffectiveBindingElement, restIndicator: EffectiveRestIndicator, propertyName: PropertyName, target: EffectiveBindingTarget, initializer: Expression) {
|
||||
// switch (bindingElement.kind) {
|
||||
// case SyntaxKind.VariableDeclaration:
|
||||
// Debug.assertNode(target, isBindingName);
|
||||
// Debug.assertMissingNode(propertyName);
|
||||
// return updateVariableDeclaration(
|
||||
// <VariableDeclaration>bindingElement,
|
||||
// <BindingName>target,
|
||||
// /*type*/ undefined,
|
||||
// initializer
|
||||
// );
|
||||
|
||||
// case SyntaxKind.Parameter:
|
||||
// Debug.assertOptionalToken(restIndicator, SyntaxKind.DotDotDotToken);
|
||||
// Debug.assertMissingNode(propertyName);
|
||||
// Debug.assertNode(target, isBindingName);
|
||||
// return updateParameter(
|
||||
// <ParameterDeclaration>bindingElement,
|
||||
// /*decorators*/ undefined,
|
||||
// /*modifiers*/ undefined,
|
||||
// <DotDotDotToken>restIndicator,
|
||||
// <BindingName>target,
|
||||
// /*type*/ undefined,
|
||||
// initializer
|
||||
// );
|
||||
|
||||
// case SyntaxKind.BindingElement:
|
||||
// Debug.assertOptionalToken(restIndicator, SyntaxKind.DotDotDotToken);
|
||||
// Debug.assertNode(target, isBindingName);
|
||||
// return updateBindingElement(
|
||||
// <BindingElement>bindingElement,
|
||||
// <DotDotDotToken>restIndicator,
|
||||
// propertyName,
|
||||
// <BindingName>target,
|
||||
// initializer
|
||||
// );
|
||||
|
||||
// case SyntaxKind.PropertyAssignment:
|
||||
// case SyntaxKind.ShorthandPropertyAssignment:
|
||||
// case SyntaxKind.SpreadAssignment:
|
||||
// if (restIndicator) {
|
||||
// return convertToSpreadAssignment(<PropertyAssignment | ShorthandPropertyAssignment | SpreadAssignment>bindingElement, propertyName, target, initializer);
|
||||
// }
|
||||
// else if (propertyName) {
|
||||
// return convertToPropertyAssignment(<PropertyAssignment | ShorthandPropertyAssignment | SpreadAssignment>bindingElement, propertyName, target, initializer);
|
||||
// }
|
||||
// else {
|
||||
// return convertToShorthandPropertyAssignment(<PropertyAssignment | ShorthandPropertyAssignment | SpreadAssignment>bindingElement, target, initializer);
|
||||
// }
|
||||
|
||||
// case SyntaxKind.ArrayLiteralExpression:
|
||||
// case SyntaxKind.BinaryExpression:
|
||||
// case SyntaxKind.SpreadElement:
|
||||
// case SyntaxKind.PropertyAccessExpression:
|
||||
// case SyntaxKind.ElementAccessExpression:
|
||||
// Debug.assertMissingNode(propertyName);
|
||||
// if (restIndicator) {
|
||||
// return convertToSpreadElement(<Expression>bindingElement, target, initializer);
|
||||
// }
|
||||
// else {
|
||||
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// function convertToSpreadAssignment(node: PropertyAssignment | ShorthandPropertyAssignment | SpreadAssignment, propertyName: PropertyName, target: EffectiveBindingTarget, initializer: Expression) {
|
||||
// Debug.assertMissingNode(propertyName);
|
||||
// Debug.assertNode(target, isIdentifier);
|
||||
// Debug.assertMissingNode(initializer);
|
||||
// if (node.kind === SyntaxKind.SpreadAssignment) {
|
||||
// return updateSpreadAssignment(node, <Identifier>target);
|
||||
// }
|
||||
// return setOriginalNode(
|
||||
// createSpreadAssignment(
|
||||
// <Identifier>target,
|
||||
// node
|
||||
// ),
|
||||
// node
|
||||
// );
|
||||
// }
|
||||
|
||||
// function convertToPropertyAssignment(node: PropertyAssignment | ShorthandPropertyAssignment | SpreadAssignment, propertyName: PropertyName, target: EffectiveBindingTarget, initializer: Expression) {
|
||||
// Debug.assertNode(target, isExpression);
|
||||
// if (node.kind === SyntaxKind.PropertyAssignment) {
|
||||
// return updatePropertyAssignment(
|
||||
// node,
|
||||
// propertyName,
|
||||
// initializer ?
|
||||
// isAssignmentExpression(node.initializer, /*excludeCompoundAssignment*/ true)
|
||||
// ? updateBinary(node.initializer, <Expression>target, initializer)
|
||||
// : createAssignment(<Expression>target, initializer)
|
||||
// : <Expression>target
|
||||
// );
|
||||
// }
|
||||
// return setOriginalNode(
|
||||
// createPropertyAssignment(
|
||||
// propertyName,
|
||||
// initializer ?
|
||||
// createAssignment(<Expression>target, initializer)
|
||||
// : <Expression>target,
|
||||
// node
|
||||
// ),
|
||||
// node
|
||||
// );
|
||||
// }
|
||||
|
||||
// function convertToShorthandPropertyAssignment(node: PropertyAssignment | ShorthandPropertyAssignment | SpreadAssignment, target: EffectiveBindingTarget, initializer: Expression) {
|
||||
// Debug.assertNode(target, isIdentifier);
|
||||
// if (node.kind === SyntaxKind.ShorthandPropertyAssignment) {
|
||||
// return updateShorthandPropertyAssignment(
|
||||
// node,
|
||||
// <Identifier>target,
|
||||
// initializer
|
||||
// );
|
||||
// }
|
||||
// return setOriginalNode(
|
||||
// createShorthandPropertyAssignment(
|
||||
// <Identifier>target,
|
||||
// initializer,
|
||||
// node
|
||||
// ),
|
||||
// node
|
||||
// );
|
||||
// }
|
||||
|
||||
// function convertToSpreadElement(node: Expression, target: EffectiveBindingTarget, initializer: Expression) {
|
||||
// Debug.assertNode(target, isExpression);
|
||||
// Debug.assertMissingNode(initializer);
|
||||
// if (node.kind === SyntaxKind.SpreadElement) {
|
||||
// return updateSpread(
|
||||
// <SpreadElement>node,
|
||||
// <Expression>target);
|
||||
// }
|
||||
// return setOriginalNode(
|
||||
// createSpread(
|
||||
// <Expression>target,
|
||||
// node
|
||||
// ),
|
||||
// node
|
||||
// );
|
||||
// }
|
||||
|
||||
// function convertToElement(node: Expression, target: EffectiveBindingTarget, initializer: Expression) {
|
||||
|
||||
// }
|
||||
|
||||
function createOrUpdateVariableDeclaration(node: Node, name: BindingName, initializer: Expression, location: TextRange) {
|
||||
if (node && node.kind === SyntaxKind.VariableDeclaration) {
|
||||
return updateVariableDeclaration(<VariableDeclaration>node, name, /*type*/ undefined, initializer);
|
||||
}
|
||||
const variable = createVariableDeclaration(name, /*type*/ undefined, initializer, location);
|
||||
return node ? setOriginalNode(variable, node) : variable;
|
||||
}
|
||||
|
||||
function createOrUpdateArrayBindingPattern(node: Node, elements: ArrayBindingElement[], location: TextRange) {
|
||||
if (node && node.kind === SyntaxKind.ArrayBindingPattern) {
|
||||
return updateArrayBindingPattern(<ArrayBindingPattern>node, elements);
|
||||
}
|
||||
const pattern = createArrayBindingPattern(elements, location);
|
||||
return node ? setOriginalNode(pattern, node) : pattern;
|
||||
}
|
||||
|
||||
function createOrUpdateObjectBindingPattern(node: Node, elements: BindingElement[], location: TextRange) {
|
||||
if (node && node.kind === SyntaxKind.ArrayBindingPattern) {
|
||||
return updateObjectBindingPattern(<ObjectBindingPattern>node, elements);
|
||||
}
|
||||
const pattern = createObjectBindingPattern(elements, location);
|
||||
return node ? setOriginalNode(pattern, node) : pattern;
|
||||
}
|
||||
|
||||
/** Given value: o, propName: p, pattern: { a, b, ...p } from the original statement
|
||||
* `{ a, b, ...p } = o`, create `p = __rest(o, ["a", "b"]);`*/
|
||||
function createRestCall(value: Expression, elements: EffectiveBindingElement[], location: TextRange): Expression {
|
||||
const propertyNames: LiteralExpression[] = [];
|
||||
for (let i = 0; i < elements.length - 1; i++) {
|
||||
if (isOmittedExpression(elements[i])) {
|
||||
continue;
|
||||
}
|
||||
const str = <StringLiteral>createSynthesizedNode(SyntaxKind.StringLiteral);
|
||||
str.pos = location.pos;
|
||||
str.end = location.end;
|
||||
str.text = getTextOfPropertyName(getEffectivePropertyNameOfEffectiveBindingElement(elements[i]));
|
||||
propertyNames.push(str);
|
||||
}
|
||||
const args = createSynthesizedNodeArray([value, createArrayLiteral(propertyNames, location)]);
|
||||
return createCall(createIdentifier("__rest"), undefined, args);
|
||||
}
|
||||
}
|
||||
|
||||
@ -105,7 +105,7 @@ namespace ts {
|
||||
* @param node A BinaryExpression node.
|
||||
*/
|
||||
function visitBinaryExpression(node: BinaryExpression): Expression {
|
||||
if (isDestructuringAssignment(node) && node.left.transformFlags & TransformFlags.AssertESNext) {
|
||||
if (isDestructuringAssignment(node) && node.left.transformFlags & TransformFlags.ContainsESNext) {
|
||||
return flattenDestructuringAssignment(context, node, /*needsDestructuringValue*/ true, hoistVariableDeclaration, visitor, /*transformRest*/ true);
|
||||
}
|
||||
|
||||
|
||||
@ -1175,16 +1175,18 @@ namespace ts {
|
||||
right: Expression;
|
||||
}
|
||||
|
||||
export interface AssignmentExpression extends BinaryExpression {
|
||||
export type AssignmentOperatorToken = Token<AssignmentOperator>;
|
||||
|
||||
export interface AssignmentExpression<TOperator extends AssignmentOperatorToken> extends BinaryExpression {
|
||||
left: LeftHandSideExpression;
|
||||
operatorToken: Token<SyntaxKind.EqualsToken>;
|
||||
operatorToken: TOperator;
|
||||
}
|
||||
|
||||
export interface ObjectDestructuringAssignment extends AssignmentExpression {
|
||||
export interface ObjectDestructuringAssignment extends AssignmentExpression<EqualsToken> {
|
||||
left: ObjectLiteralExpression;
|
||||
}
|
||||
|
||||
export interface ArrayDestructuringAssignment extends AssignmentExpression {
|
||||
export interface ArrayDestructuringAssignment extends AssignmentExpression<EqualsToken> {
|
||||
left: ArrayLiteralExpression;
|
||||
}
|
||||
|
||||
|
||||
@ -3125,19 +3125,21 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
export function isAssignmentExpression(node: Node): node is AssignmentExpression {
|
||||
export function isAssignmentExpression(node: Node, excludeCompoundAssignment: true): node is AssignmentExpression<EqualsToken>;
|
||||
export function isAssignmentExpression(node: Node, excludeCompoundAssignment?: false): node is AssignmentExpression<AssignmentOperatorToken>;
|
||||
export function isAssignmentExpression(node: Node, excludeCompoundAssignment?: boolean): node is AssignmentExpression<AssignmentOperatorToken> {
|
||||
return isBinaryExpression(node)
|
||||
&& isAssignmentOperator(node.operatorToken.kind)
|
||||
&& (excludeCompoundAssignment
|
||||
? node.operatorToken.kind === SyntaxKind.EqualsToken
|
||||
: isAssignmentOperator(node.operatorToken.kind))
|
||||
&& isLeftHandSideExpression(node.left);
|
||||
}
|
||||
|
||||
export function isDestructuringAssignment(node: Node): node is DestructuringAssignment {
|
||||
if (isBinaryExpression(node)) {
|
||||
if (node.operatorToken.kind === SyntaxKind.EqualsToken) {
|
||||
const kind = node.left.kind;
|
||||
return kind === SyntaxKind.ObjectLiteralExpression
|
||||
|| kind === SyntaxKind.ArrayLiteralExpression;
|
||||
}
|
||||
if (isAssignmentExpression(node, /*excludeCompoundAssignment*/ true)) {
|
||||
const kind = node.left.kind;
|
||||
return kind === SyntaxKind.ObjectLiteralExpression
|
||||
|| kind === SyntaxKind.ArrayLiteralExpression;
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -3918,6 +3920,14 @@ namespace ts {
|
||||
|
||||
// Binding patterns
|
||||
|
||||
export function isArrayBindingPattern(node: Node): node is ArrayBindingPattern {
|
||||
return node.kind === SyntaxKind.ArrayBindingPattern;
|
||||
}
|
||||
|
||||
export function isObjectBindingPattern(node: Node): node is ObjectBindingPattern {
|
||||
return node.kind === SyntaxKind.ObjectBindingPattern;
|
||||
}
|
||||
|
||||
export function isBindingPattern(node: Node): node is BindingPattern {
|
||||
if (node) {
|
||||
const kind = node.kind;
|
||||
|
||||
@ -701,6 +701,7 @@ namespace ts {
|
||||
return updateParameter(<ParameterDeclaration>node,
|
||||
visitNodes((<ParameterDeclaration>node).decorators, visitor, isDecorator),
|
||||
visitNodes((<ParameterDeclaration>node).modifiers, visitor, isModifier),
|
||||
(<ParameterDeclaration>node).dotDotDotToken,
|
||||
visitNode((<ParameterDeclaration>node).name, visitor, isBindingName),
|
||||
visitNode((<ParameterDeclaration>node).type, visitor, isTypeNode, /*optional*/ true),
|
||||
visitNode((<ParameterDeclaration>node).initializer, visitor, isExpression, /*optional*/ true));
|
||||
@ -767,6 +768,7 @@ namespace ts {
|
||||
|
||||
case SyntaxKind.BindingElement:
|
||||
return updateBindingElement(<BindingElement>node,
|
||||
(<BindingElement>node).dotDotDotToken,
|
||||
visitNode((<BindingElement>node).propertyName, visitor, isPropertyName, /*optional*/ true),
|
||||
visitNode((<BindingElement>node).name, visitor, isBindingName),
|
||||
visitNode((<BindingElement>node).initializer, visitor, isExpression, /*optional*/ true));
|
||||
@ -1287,6 +1289,13 @@ namespace ts {
|
||||
? (node: Node, message?: string) => assert(false, message || "Unexpected node.", () => `Node ${formatSyntaxKind(node.kind)} was unexpected.`)
|
||||
: noop;
|
||||
|
||||
export const assertEachNode = shouldAssert(AssertionLevel.Normal)
|
||||
? (nodes: Node[], test: (node: Node) => boolean, message?: string) => assert(
|
||||
test === undefined || every(nodes, test),
|
||||
message || "Unexpected node.",
|
||||
() => `Node array did not pass test '${getFunctionName(test)}'.`)
|
||||
: noop;
|
||||
|
||||
export const assertNode = shouldAssert(AssertionLevel.Normal)
|
||||
? (node: Node, test: (node: Node) => boolean, message?: string) => assert(
|
||||
test === undefined || test(node),
|
||||
@ -1294,6 +1303,27 @@ namespace ts {
|
||||
() => `Node ${formatSyntaxKind(node.kind)} did not pass test '${getFunctionName(test)}'.`)
|
||||
: noop;
|
||||
|
||||
export const assertOptionalNode = shouldAssert(AssertionLevel.Normal)
|
||||
? (node: Node, test: (node: Node) => boolean, message?: string) => assert(
|
||||
test === undefined || node === undefined || test(node),
|
||||
message || "Unexpected node.",
|
||||
() => `Node ${formatSyntaxKind(node.kind)} did not pass test '${getFunctionName(test)}'.`)
|
||||
: noop;
|
||||
|
||||
export const assertOptionalToken = shouldAssert(AssertionLevel.Normal)
|
||||
? (node: Node, kind: SyntaxKind, message?: string) => assert(
|
||||
kind === undefined || node === undefined || node.kind === kind,
|
||||
message || "Unexpected node.",
|
||||
() => `Node ${formatSyntaxKind(node.kind)} was not a '${formatSyntaxKind(kind)}' token.`)
|
||||
: noop;
|
||||
|
||||
export const assertMissingNode = shouldAssert(AssertionLevel.Normal)
|
||||
? (node: Node, message?: string) => assert(
|
||||
node === undefined,
|
||||
message || "Unexpected node.",
|
||||
() => `Node ${formatSyntaxKind(node.kind)} was unexpected'.`)
|
||||
: noop;
|
||||
|
||||
function getFunctionName(func: Function) {
|
||||
if (typeof func !== "function") {
|
||||
return "";
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user