1/*@internal*/ 2namespace ts { 3 interface FlattenContext { 4 context: TransformationContext; 5 level: FlattenLevel; 6 downlevelIteration: boolean; 7 hoistTempVariables: boolean; 8 hasTransformedPriorElement?: boolean; // indicates whether we've transformed a prior declaration 9 emitExpression: (value: Expression) => void; 10 emitBindingOrAssignment: (target: BindingOrAssignmentElementTarget, value: Expression, location: TextRange, original: Node | undefined) => void; 11 createArrayBindingOrAssignmentPattern: (elements: BindingOrAssignmentElement[]) => ArrayBindingOrAssignmentPattern; 12 createObjectBindingOrAssignmentPattern: (elements: BindingOrAssignmentElement[]) => ObjectBindingOrAssignmentPattern; 13 createArrayBindingOrAssignmentElement: (node: Identifier) => BindingOrAssignmentElement; 14 visitor?: (node: Node) => VisitResult<Node>; 15 } 16 17 export const enum FlattenLevel { 18 All, 19 ObjectRest, 20 } 21 22 /** 23 * Flattens a DestructuringAssignment or a VariableDeclaration to an expression. 24 * 25 * @param node The node to flatten. 26 * @param visitor An optional visitor used to visit initializers. 27 * @param context The transformation context. 28 * @param level Indicates the extent to which flattening should occur. 29 * @param needsValue An optional value indicating whether the value from the right-hand-side of 30 * the destructuring assignment is needed as part of a larger expression. 31 * @param createAssignmentCallback An optional callback used to create the assignment expression. 32 */ 33 export function flattenDestructuringAssignment( 34 node: VariableDeclaration | DestructuringAssignment, 35 visitor: ((node: Node) => VisitResult<Node>) | undefined, 36 context: TransformationContext, 37 level: FlattenLevel, 38 needsValue?: boolean, 39 createAssignmentCallback?: (name: Identifier, value: Expression, location?: TextRange) => Expression): Expression { 40 let location: TextRange = node; 41 let value: Expression | undefined; 42 if (isDestructuringAssignment(node)) { 43 value = node.right; 44 while (isEmptyArrayLiteral(node.left) || isEmptyObjectLiteral(node.left)) { 45 if (isDestructuringAssignment(value)) { 46 location = node = value; 47 value = node.right; 48 } 49 else { 50 return visitNode(value, visitor, isExpression); 51 } 52 } 53 } 54 55 let expressions: Expression[] | undefined; 56 const flattenContext: FlattenContext = { 57 context, 58 level, 59 downlevelIteration: !!context.getCompilerOptions().downlevelIteration, 60 hoistTempVariables: true, 61 emitExpression, 62 emitBindingOrAssignment, 63 createArrayBindingOrAssignmentPattern: elements => makeArrayAssignmentPattern(context.factory, elements), 64 createObjectBindingOrAssignmentPattern: elements => makeObjectAssignmentPattern(context.factory, elements), 65 createArrayBindingOrAssignmentElement: makeAssignmentElement, 66 visitor 67 }; 68 69 if (value) { 70 value = visitNode(value, visitor, isExpression); 71 72 if (isIdentifier(value) && bindingOrAssignmentElementAssignsToName(node, value.escapedText) || 73 bindingOrAssignmentElementContainsNonLiteralComputedName(node)) { 74 // If the right-hand value of the assignment is also an assignment target then 75 // we need to cache the right-hand value. 76 value = ensureIdentifier(flattenContext, value, /*reuseIdentifierExpressions*/ false, location); 77 } 78 else if (needsValue) { 79 // If the right-hand value of the destructuring assignment needs to be preserved (as 80 // is the case when the destructuring assignment is part of a larger expression), 81 // then we need to cache the right-hand value. 82 // 83 // The source map location for the assignment should point to the entire binary 84 // expression. 85 value = ensureIdentifier(flattenContext, value, /*reuseIdentifierExpressions*/ true, location); 86 } 87 else if (nodeIsSynthesized(node)) { 88 // Generally, the source map location for a destructuring assignment is the root 89 // expression. 90 // 91 // However, if the root expression is synthesized (as in the case 92 // of the initializer when transforming a ForOfStatement), then the source map 93 // location should point to the right-hand value of the expression. 94 location = value; 95 } 96 } 97 98 flattenBindingOrAssignmentElement(flattenContext, node, value, location, /*skipInitializer*/ isDestructuringAssignment(node)); 99 100 if (value && needsValue) { 101 if (!some(expressions)) { 102 return value; 103 } 104 105 expressions.push(value); 106 } 107 108 return context.factory.inlineExpressions(expressions!) || context.factory.createOmittedExpression(); 109 110 function emitExpression(expression: Expression) { 111 expressions = append(expressions, expression); 112 } 113 114 function emitBindingOrAssignment(target: BindingOrAssignmentElementTarget, value: Expression, location: TextRange, original: Node) { 115 Debug.assertNode(target, createAssignmentCallback ? isIdentifier : isExpression); 116 const expression = createAssignmentCallback 117 ? createAssignmentCallback(<Identifier>target, value, location) 118 : setTextRange( 119 context.factory.createAssignment(visitNode(<Expression>target, visitor, isExpression), value), 120 location 121 ); 122 expression.original = original; 123 emitExpression(expression); 124 } 125 } 126 127 function bindingOrAssignmentElementAssignsToName(element: BindingOrAssignmentElement, escapedName: __String): boolean { 128 const target = getTargetOfBindingOrAssignmentElement(element)!; // TODO: GH#18217 129 if (isBindingOrAssignmentPattern(target)) { 130 return bindingOrAssignmentPatternAssignsToName(target, escapedName); 131 } 132 else if (isIdentifier(target)) { 133 return target.escapedText === escapedName; 134 } 135 return false; 136 } 137 138 function bindingOrAssignmentPatternAssignsToName(pattern: BindingOrAssignmentPattern, escapedName: __String): boolean { 139 const elements = getElementsOfBindingOrAssignmentPattern(pattern); 140 for (const element of elements) { 141 if (bindingOrAssignmentElementAssignsToName(element, escapedName)) { 142 return true; 143 } 144 } 145 return false; 146 } 147 148 function bindingOrAssignmentElementContainsNonLiteralComputedName(element: BindingOrAssignmentElement): boolean { 149 const propertyName = tryGetPropertyNameOfBindingOrAssignmentElement(element); 150 if (propertyName && isComputedPropertyName(propertyName) && !isLiteralExpression(propertyName.expression)) { 151 return true; 152 } 153 const target = getTargetOfBindingOrAssignmentElement(element); 154 return !!target && isBindingOrAssignmentPattern(target) && bindingOrAssignmentPatternContainsNonLiteralComputedName(target); 155 } 156 157 function bindingOrAssignmentPatternContainsNonLiteralComputedName(pattern: BindingOrAssignmentPattern): boolean { 158 return !!forEach(getElementsOfBindingOrAssignmentPattern(pattern), bindingOrAssignmentElementContainsNonLiteralComputedName); 159 } 160 161 /** 162 * Flattens a VariableDeclaration or ParameterDeclaration to one or more variable declarations. 163 * 164 * @param node The node to flatten. 165 * @param visitor An optional visitor used to visit initializers. 166 * @param context The transformation context. 167 * @param boundValue The value bound to the declaration. 168 * @param skipInitializer A value indicating whether to ignore the initializer of `node`. 169 * @param hoistTempVariables Indicates whether temporary variables should not be recorded in-line. 170 * @param level Indicates the extent to which flattening should occur. 171 */ 172 export function flattenDestructuringBinding( 173 node: VariableDeclaration | ParameterDeclaration, 174 visitor: (node: Node) => VisitResult<Node>, 175 context: TransformationContext, 176 level: FlattenLevel, 177 rval?: Expression, 178 hoistTempVariables = false, 179 skipInitializer?: boolean): VariableDeclaration[] { 180 let pendingExpressions: Expression[] | undefined; 181 const pendingDeclarations: { pendingExpressions?: Expression[], name: BindingName, value: Expression, location?: TextRange, original?: Node; }[] = []; 182 const declarations: VariableDeclaration[] = []; 183 const flattenContext: FlattenContext = { 184 context, 185 level, 186 downlevelIteration: !!context.getCompilerOptions().downlevelIteration, 187 hoistTempVariables, 188 emitExpression, 189 emitBindingOrAssignment, 190 createArrayBindingOrAssignmentPattern: elements => makeArrayBindingPattern(context.factory, elements), 191 createObjectBindingOrAssignmentPattern: elements => makeObjectBindingPattern(context.factory, elements), 192 createArrayBindingOrAssignmentElement: name => makeBindingElement(context.factory, name), 193 visitor 194 }; 195 196 if (isVariableDeclaration(node)) { 197 let initializer = getInitializerOfBindingOrAssignmentElement(node); 198 if (initializer && (isIdentifier(initializer) && bindingOrAssignmentElementAssignsToName(node, initializer.escapedText) || 199 bindingOrAssignmentElementContainsNonLiteralComputedName(node))) { 200 // If the right-hand value of the assignment is also an assignment target then 201 // we need to cache the right-hand value. 202 initializer = ensureIdentifier(flattenContext, visitNode(initializer, flattenContext.visitor), /*reuseIdentifierExpressions*/ false, initializer); 203 node = context.factory.updateVariableDeclaration(node, node.name, /*exclamationToken*/ undefined, /*type*/ undefined, initializer); 204 } 205 } 206 207 flattenBindingOrAssignmentElement(flattenContext, node, rval, node, skipInitializer); 208 if (pendingExpressions) { 209 const temp = context.factory.createTempVariable(/*recordTempVariable*/ undefined); 210 if (hoistTempVariables) { 211 const value = context.factory.inlineExpressions(pendingExpressions); 212 pendingExpressions = undefined; 213 emitBindingOrAssignment(temp, value, /*location*/ undefined, /*original*/ undefined); 214 } 215 else { 216 context.hoistVariableDeclaration(temp); 217 const pendingDeclaration = last(pendingDeclarations); 218 pendingDeclaration.pendingExpressions = append( 219 pendingDeclaration.pendingExpressions, 220 context.factory.createAssignment(temp, pendingDeclaration.value) 221 ); 222 addRange(pendingDeclaration.pendingExpressions, pendingExpressions); 223 pendingDeclaration.value = temp; 224 } 225 } 226 for (const { pendingExpressions, name, value, location, original } of pendingDeclarations) { 227 const variable = context.factory.createVariableDeclaration( 228 name, 229 /*exclamationToken*/ undefined, 230 /*type*/ undefined, 231 pendingExpressions ? context.factory.inlineExpressions(append(pendingExpressions, value)) : value 232 ); 233 variable.original = original; 234 setTextRange(variable, location); 235 declarations.push(variable); 236 } 237 return declarations; 238 239 function emitExpression(value: Expression) { 240 pendingExpressions = append(pendingExpressions, value); 241 } 242 243 function emitBindingOrAssignment(target: BindingOrAssignmentElementTarget, value: Expression, location: TextRange | undefined, original: Node | undefined) { 244 Debug.assertNode(target, isBindingName); 245 if (pendingExpressions) { 246 value = context.factory.inlineExpressions(append(pendingExpressions, value)); 247 pendingExpressions = undefined; 248 } 249 pendingDeclarations.push({ pendingExpressions, name: target, value, location, original }); 250 } 251 } 252 253 /** 254 * Flattens a BindingOrAssignmentElement into zero or more bindings or assignments. 255 * 256 * @param flattenContext Options used to control flattening. 257 * @param element The element to flatten. 258 * @param value The current RHS value to assign to the element. 259 * @param location The location to use for source maps and comments. 260 * @param skipInitializer An optional value indicating whether to include the initializer 261 * for the element. 262 */ 263 function flattenBindingOrAssignmentElement( 264 flattenContext: FlattenContext, 265 element: BindingOrAssignmentElement, 266 value: Expression | undefined, 267 location: TextRange, 268 skipInitializer?: boolean) { 269 const bindingTarget = getTargetOfBindingOrAssignmentElement(element)!; // TODO: GH#18217 270 if (!skipInitializer) { 271 const initializer = visitNode(getInitializerOfBindingOrAssignmentElement(element), flattenContext.visitor, isExpression); 272 if (initializer) { 273 // Combine value and initializer 274 if (value) { 275 value = createDefaultValueCheck(flattenContext, value, initializer, location); 276 // If 'value' is not a simple expression, it could contain side-effecting code that should evaluate before an object or array binding pattern. 277 if (!isSimpleInlineableExpression(initializer) && isBindingOrAssignmentPattern(bindingTarget)) { 278 value = ensureIdentifier(flattenContext, value, /*reuseIdentifierExpressions*/ true, location); 279 } 280 } 281 else { 282 value = initializer; 283 } 284 } 285 else if (!value) { 286 // Use 'void 0' in absence of value and initializer 287 value = flattenContext.context.factory.createVoidZero(); 288 } 289 } 290 if (isObjectBindingOrAssignmentPattern(bindingTarget)) { 291 flattenObjectBindingOrAssignmentPattern(flattenContext, element, bindingTarget, value!, location); 292 } 293 else if (isArrayBindingOrAssignmentPattern(bindingTarget)) { 294 flattenArrayBindingOrAssignmentPattern(flattenContext, element, bindingTarget, value!, location); 295 } 296 else { 297 flattenContext.emitBindingOrAssignment(bindingTarget, value!, location, /*original*/ element); // TODO: GH#18217 298 } 299 } 300 301 /** 302 * Flattens an ObjectBindingOrAssignmentPattern into zero or more bindings or assignments. 303 * 304 * @param flattenContext Options used to control flattening. 305 * @param parent The parent element of the pattern. 306 * @param pattern The ObjectBindingOrAssignmentPattern to flatten. 307 * @param value The current RHS value to assign to the element. 308 * @param location The location to use for source maps and comments. 309 */ 310 function flattenObjectBindingOrAssignmentPattern(flattenContext: FlattenContext, parent: BindingOrAssignmentElement, pattern: ObjectBindingOrAssignmentPattern, value: Expression, location: TextRange) { 311 const elements = getElementsOfBindingOrAssignmentPattern(pattern); 312 const numElements = elements.length; 313 if (numElements !== 1) { 314 // For anything other than a single-element destructuring we need to generate a temporary 315 // to ensure value is evaluated exactly once. Additionally, if we have zero elements 316 // we need to emit *something* to ensure that in case a 'var' keyword was already emitted, 317 // so in that case, we'll intentionally create that temporary. 318 const reuseIdentifierExpressions = !isDeclarationBindingElement(parent) || numElements !== 0; 319 value = ensureIdentifier(flattenContext, value, reuseIdentifierExpressions, location); 320 } 321 let bindingElements: BindingOrAssignmentElement[] | undefined; 322 let computedTempVariables: Expression[] | undefined; 323 for (let i = 0; i < numElements; i++) { 324 const element = elements[i]; 325 if (!getRestIndicatorOfBindingOrAssignmentElement(element)) { 326 const propertyName = getPropertyNameOfBindingOrAssignmentElement(element)!; 327 if (flattenContext.level >= FlattenLevel.ObjectRest 328 && !(element.transformFlags & (TransformFlags.ContainsRestOrSpread | TransformFlags.ContainsObjectRestOrSpread)) 329 && !(getTargetOfBindingOrAssignmentElement(element)!.transformFlags & (TransformFlags.ContainsRestOrSpread | TransformFlags.ContainsObjectRestOrSpread)) 330 && !isComputedPropertyName(propertyName)) { 331 bindingElements = append(bindingElements, visitNode(element, flattenContext.visitor)); 332 } 333 else { 334 if (bindingElements) { 335 flattenContext.emitBindingOrAssignment(flattenContext.createObjectBindingOrAssignmentPattern(bindingElements), value, location, pattern); 336 bindingElements = undefined; 337 } 338 const rhsValue = createDestructuringPropertyAccess(flattenContext, value, propertyName); 339 if (isComputedPropertyName(propertyName)) { 340 computedTempVariables = append<Expression>(computedTempVariables, (rhsValue as ElementAccessExpression).argumentExpression); 341 } 342 flattenBindingOrAssignmentElement(flattenContext, element, rhsValue, /*location*/ element); 343 } 344 } 345 else if (i === numElements - 1) { 346 if (bindingElements) { 347 flattenContext.emitBindingOrAssignment(flattenContext.createObjectBindingOrAssignmentPattern(bindingElements), value, location, pattern); 348 bindingElements = undefined; 349 } 350 const rhsValue = flattenContext.context.getEmitHelperFactory().createRestHelper(value, elements, computedTempVariables, pattern); 351 flattenBindingOrAssignmentElement(flattenContext, element, rhsValue, element); 352 } 353 } 354 if (bindingElements) { 355 flattenContext.emitBindingOrAssignment(flattenContext.createObjectBindingOrAssignmentPattern(bindingElements), value, location, pattern); 356 } 357 } 358 359 /** 360 * Flattens an ArrayBindingOrAssignmentPattern into zero or more bindings or assignments. 361 * 362 * @param flattenContext Options used to control flattening. 363 * @param parent The parent element of the pattern. 364 * @param pattern The ArrayBindingOrAssignmentPattern to flatten. 365 * @param value The current RHS value to assign to the element. 366 * @param location The location to use for source maps and comments. 367 */ 368 function flattenArrayBindingOrAssignmentPattern(flattenContext: FlattenContext, parent: BindingOrAssignmentElement, pattern: ArrayBindingOrAssignmentPattern, value: Expression, location: TextRange) { 369 const elements = getElementsOfBindingOrAssignmentPattern(pattern); 370 const numElements = elements.length; 371 if (flattenContext.level < FlattenLevel.ObjectRest && flattenContext.downlevelIteration) { 372 // Read the elements of the iterable into an array 373 value = ensureIdentifier( 374 flattenContext, 375 setTextRange( 376 flattenContext.context.getEmitHelperFactory().createReadHelper( 377 value, 378 numElements > 0 && getRestIndicatorOfBindingOrAssignmentElement(elements[numElements - 1]) 379 ? undefined 380 : numElements 381 ), 382 location 383 ), 384 /*reuseIdentifierExpressions*/ false, 385 location 386 ); 387 } 388 else if (numElements !== 1 && (flattenContext.level < FlattenLevel.ObjectRest || numElements === 0) 389 || every(elements, isOmittedExpression)) { 390 // For anything other than a single-element destructuring we need to generate a temporary 391 // to ensure value is evaluated exactly once. Additionally, if we have zero elements 392 // we need to emit *something* to ensure that in case a 'var' keyword was already emitted, 393 // so in that case, we'll intentionally create that temporary. 394 // Or all the elements of the binding pattern are omitted expression such as "var [,] = [1,2]", 395 // then we will create temporary variable. 396 const reuseIdentifierExpressions = !isDeclarationBindingElement(parent) || numElements !== 0; 397 value = ensureIdentifier(flattenContext, value, reuseIdentifierExpressions, location); 398 } 399 let bindingElements: BindingOrAssignmentElement[] | undefined; 400 let restContainingElements: [Identifier, BindingOrAssignmentElement][] | undefined; 401 for (let i = 0; i < numElements; i++) { 402 const element = elements[i]; 403 if (flattenContext.level >= FlattenLevel.ObjectRest) { 404 // If an array pattern contains an ObjectRest, we must cache the result so that we 405 // can perform the ObjectRest destructuring in a different declaration 406 if (element.transformFlags & TransformFlags.ContainsObjectRestOrSpread || flattenContext.hasTransformedPriorElement && !isSimpleBindingOrAssignmentElement(element)) { 407 flattenContext.hasTransformedPriorElement = true; 408 const temp = flattenContext.context.factory.createTempVariable(/*recordTempVariable*/ undefined); 409 if (flattenContext.hoistTempVariables) { 410 flattenContext.context.hoistVariableDeclaration(temp); 411 } 412 413 restContainingElements = append(restContainingElements, <[Identifier, BindingOrAssignmentElement]>[temp, element]); 414 bindingElements = append(bindingElements, flattenContext.createArrayBindingOrAssignmentElement(temp)); 415 } 416 else { 417 bindingElements = append(bindingElements, element); 418 } 419 } 420 else if (isOmittedExpression(element)) { 421 continue; 422 } 423 else if (!getRestIndicatorOfBindingOrAssignmentElement(element)) { 424 const rhsValue = flattenContext.context.factory.createElementAccessExpression(value, i); 425 flattenBindingOrAssignmentElement(flattenContext, element, rhsValue, /*location*/ element); 426 } 427 else if (i === numElements - 1) { 428 const rhsValue = flattenContext.context.factory.createArraySliceCall(value, i); 429 flattenBindingOrAssignmentElement(flattenContext, element, rhsValue, /*location*/ element); 430 } 431 } 432 if (bindingElements) { 433 flattenContext.emitBindingOrAssignment(flattenContext.createArrayBindingOrAssignmentPattern(bindingElements), value, location, pattern); 434 } 435 if (restContainingElements) { 436 for (const [id, element] of restContainingElements) { 437 flattenBindingOrAssignmentElement(flattenContext, element, id, element); 438 } 439 } 440 } 441 442 function isSimpleBindingOrAssignmentElement(element: BindingOrAssignmentElement): boolean { 443 const target = getTargetOfBindingOrAssignmentElement(element); 444 if (!target || isOmittedExpression(target)) return true; 445 const propertyName = tryGetPropertyNameOfBindingOrAssignmentElement(element); 446 if (propertyName && !isPropertyNameLiteral(propertyName)) return false; 447 const initializer = getInitializerOfBindingOrAssignmentElement(element); 448 if (initializer && !isSimpleInlineableExpression(initializer)) return false; 449 if (isBindingOrAssignmentPattern(target)) return every(getElementsOfBindingOrAssignmentPattern(target), isSimpleBindingOrAssignmentElement); 450 return isIdentifier(target); 451 } 452 453 /** 454 * Creates an expression used to provide a default value if a value is `undefined` at runtime. 455 * 456 * @param flattenContext Options used to control flattening. 457 * @param value The RHS value to test. 458 * @param defaultValue The default value to use if `value` is `undefined` at runtime. 459 * @param location The location to use for source maps and comments. 460 */ 461 function createDefaultValueCheck(flattenContext: FlattenContext, value: Expression, defaultValue: Expression, location: TextRange): Expression { 462 value = ensureIdentifier(flattenContext, value, /*reuseIdentifierExpressions*/ true, location); 463 return flattenContext.context.factory.createConditionalExpression(flattenContext.context.factory.createTypeCheck(value, "undefined"), /*questionToken*/ undefined, defaultValue, /*colonToken*/ undefined, value); 464 } 465 466 /** 467 * Creates either a PropertyAccessExpression or an ElementAccessExpression for the 468 * right-hand side of a transformed destructuring assignment. 469 * 470 * @link https://tc39.github.io/ecma262/#sec-runtime-semantics-keyeddestructuringassignmentevaluation 471 * 472 * @param flattenContext Options used to control flattening. 473 * @param value The RHS value that is the source of the property. 474 * @param propertyName The destructuring property name. 475 */ 476 function createDestructuringPropertyAccess(flattenContext: FlattenContext, value: Expression, propertyName: PropertyName): LeftHandSideExpression { 477 if (isComputedPropertyName(propertyName)) { 478 const argumentExpression = ensureIdentifier(flattenContext, visitNode(propertyName.expression, flattenContext.visitor), /*reuseIdentifierExpressions*/ false, /*location*/ propertyName); 479 return flattenContext.context.factory.createElementAccessExpression(value, argumentExpression); 480 } 481 else if (isStringOrNumericLiteralLike(propertyName)) { 482 const argumentExpression = factory.cloneNode(propertyName); 483 return flattenContext.context.factory.createElementAccessExpression(value, argumentExpression); 484 } 485 else { 486 const name = flattenContext.context.factory.createIdentifier(idText(propertyName)); 487 return flattenContext.context.factory.createPropertyAccessExpression(value, name); 488 } 489 } 490 491 /** 492 * Ensures that there exists a declared identifier whose value holds the given expression. 493 * This function is useful to ensure that the expression's value can be read from in subsequent expressions. 494 * Unless 'reuseIdentifierExpressions' is false, 'value' will be returned if it is just an identifier. 495 * 496 * @param flattenContext Options used to control flattening. 497 * @param value the expression whose value needs to be bound. 498 * @param reuseIdentifierExpressions true if identifier expressions can simply be returned; 499 * false if it is necessary to always emit an identifier. 500 * @param location The location to use for source maps and comments. 501 */ 502 function ensureIdentifier(flattenContext: FlattenContext, value: Expression, reuseIdentifierExpressions: boolean, location: TextRange) { 503 if (isIdentifier(value) && reuseIdentifierExpressions) { 504 return value; 505 } 506 else { 507 const temp = flattenContext.context.factory.createTempVariable(/*recordTempVariable*/ undefined); 508 if (flattenContext.hoistTempVariables) { 509 flattenContext.context.hoistVariableDeclaration(temp); 510 flattenContext.emitExpression(setTextRange(flattenContext.context.factory.createAssignment(temp, value), location)); 511 } 512 else { 513 flattenContext.emitBindingOrAssignment(temp, value, location, /*original*/ undefined); 514 } 515 return temp; 516 } 517 } 518 519 function makeArrayBindingPattern(factory: NodeFactory, elements: BindingOrAssignmentElement[]) { 520 Debug.assertEachNode(elements, isArrayBindingElement); 521 return factory.createArrayBindingPattern(<ArrayBindingElement[]>elements); 522 } 523 524 function makeArrayAssignmentPattern(factory: NodeFactory, elements: BindingOrAssignmentElement[]) { 525 return factory.createArrayLiteralExpression(map(elements, factory.converters.convertToArrayAssignmentElement)); 526 } 527 528 function makeObjectBindingPattern(factory: NodeFactory, elements: BindingOrAssignmentElement[]) { 529 Debug.assertEachNode(elements, isBindingElement); 530 return factory.createObjectBindingPattern(<BindingElement[]>elements); 531 } 532 533 function makeObjectAssignmentPattern(factory: NodeFactory, elements: BindingOrAssignmentElement[]) { 534 return factory.createObjectLiteralExpression(map(elements, factory.converters.convertToObjectAssignmentElement)); 535 } 536 537 function makeBindingElement(factory: NodeFactory, name: Identifier) { 538 return factory.createBindingElement(/*dotDotDotToken*/ undefined, /*propertyName*/ undefined, name); 539 } 540 541 function makeAssignmentElement(name: Identifier) { 542 return name; 543 } 544} 545