react / wstein / node_modules / react / node_modules / envify / node_modules / jstransform / visitors / es6-destructuring-visitors.js
80540 views/**1* Copyright 2014 Facebook, Inc.2*3* Licensed under the Apache License, Version 2.0 (the "License");4* you may not use this file except in compliance with the License.5* You may obtain a copy of the License at6*7* http://www.apache.org/licenses/LICENSE-2.08*9* Unless required by applicable law or agreed to in writing, software10* distributed under the License is distributed on an "AS IS" BASIS,11* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.12* See the License for the specific language governing permissions and13* limitations under the License.14*/15/*global exports:true*/1617/**18* Implements ES6 destructuring assignment and pattern matchng.19*20* function init({port, ip, coords: [x, y]}) {21* return (x && y) ? {id, port} : {ip};22* };23*24* function init($__0) {25* var26* port = $__0.port,27* ip = $__0.ip,28* $__1 = $__0.coords,29* x = $__1[0],30* y = $__1[1];31* return (x && y) ? {id, port} : {ip};32* }33*34* var x, {ip, port} = init({ip, port});35*36* var x, $__0 = init({ip, port}), ip = $__0.ip, port = $__0.port;37*38*/39var Syntax = require('esprima-fb').Syntax;40var utils = require('../src/utils');4142var reservedWordsHelper = require('./reserved-words-helper');43var restParamVisitors = require('./es6-rest-param-visitors');44var restPropertyHelpers = require('./es7-rest-property-helpers');4546// -------------------------------------------------------47// 1. Structured variable declarations.48//49// var [a, b] = [b, a];50// var {x, y} = {y, x};51// -------------------------------------------------------5253function visitStructuredVariable(traverse, node, path, state) {54// Allocate new temp for the pattern.55utils.append(utils.getTempVar(state.localScope.tempVarIndex) + '=', state);56// Skip the pattern and assign the init to the temp.57utils.catchupWhiteSpace(node.init.range[0], state);58traverse(node.init, path, state);59utils.catchup(node.init.range[1], state);60// Render the destructured data.61utils.append(',' + getDestructuredComponents(node.id, state), state);62state.localScope.tempVarIndex++;63return false;64}6566visitStructuredVariable.test = function(node, path, state) {67return node.type === Syntax.VariableDeclarator &&68isStructuredPattern(node.id);69};7071function isStructuredPattern(node) {72return node.type === Syntax.ObjectPattern ||73node.type === Syntax.ArrayPattern;74}7576// Main function which does actual recursive destructuring77// of nested complex structures.78function getDestructuredComponents(node, state) {79var tmpIndex = state.localScope.tempVarIndex;80var components = [];81var patternItems = getPatternItems(node);8283for (var idx = 0; idx < patternItems.length; idx++) {84var item = patternItems[idx];85if (!item) {86continue;87}8889if (item.type === Syntax.SpreadElement) {90// Spread/rest of an array.91// TODO(dmitrys): support spread in the middle of a pattern92// and also for function param patterns: [x, ...xs, y]93components.push(item.argument.name +94'=Array.prototype.slice.call(' +95utils.getTempVar(tmpIndex) + ',' + idx + ')'96);97continue;98}99100if (item.type === Syntax.SpreadProperty) {101var restExpression = restPropertyHelpers.renderRestExpression(102utils.getTempVar(tmpIndex),103patternItems104);105components.push(item.argument.name + '=' + restExpression);106continue;107}108109// Depending on pattern type (Array or Object), we get110// corresponding pattern item parts.111var accessor = getPatternItemAccessor(node, item, tmpIndex, idx);112var value = getPatternItemValue(node, item);113114// TODO(dmitrys): implement default values: {x, y=5}115if (value.type === Syntax.Identifier) {116// Simple pattern item.117components.push(value.name + '=' + accessor);118} else {119// Complex sub-structure.120components.push(121utils.getTempVar(++state.localScope.tempVarIndex) + '=' + accessor +122',' + getDestructuredComponents(value, state)123);124}125}126127return components.join(',');128}129130function getPatternItems(node) {131return node.properties || node.elements;132}133134function getPatternItemAccessor(node, patternItem, tmpIndex, idx) {135var tmpName = utils.getTempVar(tmpIndex);136if (node.type === Syntax.ObjectPattern) {137if (reservedWordsHelper.isReservedWord(patternItem.key.name)) {138return tmpName + '["' + patternItem.key.name + '"]';139} else if (patternItem.key.type === Syntax.Literal) {140return tmpName + '[' + JSON.stringify(patternItem.key.value) + ']';141} else if (patternItem.key.type === Syntax.Identifier) {142return tmpName + '.' + patternItem.key.name;143}144} else if (node.type === Syntax.ArrayPattern) {145return tmpName + '[' + idx + ']';146}147}148149function getPatternItemValue(node, patternItem) {150return node.type === Syntax.ObjectPattern151? patternItem.value152: patternItem;153}154155// -------------------------------------------------------156// 2. Assignment expression.157//158// [a, b] = [b, a];159// ({x, y} = {y, x});160// -------------------------------------------------------161162function visitStructuredAssignment(traverse, node, path, state) {163var exprNode = node.expression;164utils.append('var ' + utils.getTempVar(state.localScope.tempVarIndex) + '=', state);165166utils.catchupWhiteSpace(exprNode.right.range[0], state);167traverse(exprNode.right, path, state);168utils.catchup(exprNode.right.range[1], state);169170utils.append(171';' + getDestructuredComponents(exprNode.left, state) + ';',172state173);174175utils.catchupWhiteSpace(node.range[1], state);176state.localScope.tempVarIndex++;177return false;178}179180visitStructuredAssignment.test = function(node, path, state) {181// We consider the expression statement rather than just assignment182// expression to cover case with object patters which should be183// wrapped in grouping operator: ({x, y} = {y, x});184return node.type === Syntax.ExpressionStatement &&185node.expression.type === Syntax.AssignmentExpression &&186isStructuredPattern(node.expression.left);187};188189// -------------------------------------------------------190// 3. Structured parameter.191//192// function foo({x, y}) { ... }193// -------------------------------------------------------194195function visitStructuredParameter(traverse, node, path, state) {196utils.append(utils.getTempVar(getParamIndex(node, path)), state);197utils.catchupWhiteSpace(node.range[1], state);198return true;199}200201function getParamIndex(paramNode, path) {202var funcNode = path[0];203var tmpIndex = 0;204for (var k = 0; k < funcNode.params.length; k++) {205var param = funcNode.params[k];206if (param === paramNode) {207break;208}209if (isStructuredPattern(param)) {210tmpIndex++;211}212}213return tmpIndex;214}215216visitStructuredParameter.test = function(node, path, state) {217return isStructuredPattern(node) && isFunctionNode(path[0]);218};219220function isFunctionNode(node) {221return (node.type == Syntax.FunctionDeclaration ||222node.type == Syntax.FunctionExpression ||223node.type == Syntax.MethodDefinition ||224node.type == Syntax.ArrowFunctionExpression);225}226227// -------------------------------------------------------228// 4. Function body for structured parameters.229//230// function foo({x, y}) { x; y; }231// -------------------------------------------------------232233function visitFunctionBodyForStructuredParameter(traverse, node, path, state) {234var funcNode = path[0];235236utils.catchup(funcNode.body.range[0] + 1, state);237renderDestructuredComponents(funcNode, state);238239if (funcNode.rest) {240utils.append(241restParamVisitors.renderRestParamSetup(funcNode, state),242state243);244}245246return true;247}248249function renderDestructuredComponents(funcNode, state) {250var destructuredComponents = [];251252for (var k = 0; k < funcNode.params.length; k++) {253var param = funcNode.params[k];254if (isStructuredPattern(param)) {255destructuredComponents.push(256getDestructuredComponents(param, state)257);258state.localScope.tempVarIndex++;259}260}261262if (destructuredComponents.length) {263utils.append('var ' + destructuredComponents.join(',') + ';', state);264}265}266267visitFunctionBodyForStructuredParameter.test = function(node, path, state) {268return node.type === Syntax.BlockStatement && isFunctionNode(path[0]);269};270271exports.visitorList = [272visitStructuredVariable,273visitStructuredAssignment,274visitStructuredParameter,275visitFunctionBodyForStructuredParameter276];277278exports.renderDestructuredComponents = renderDestructuredComponents;279280281282