mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-05-12 17:04:57 +00:00
281 lines
8.3 KiB
JavaScript
281 lines
8.3 KiB
JavaScript
/**
|
|
* Copyright 2014 Facebook, Inc.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
/*global exports:true*/
|
|
|
|
/**
|
|
* Implements ES6 destructuring assignment and pattern matchng.
|
|
*
|
|
* function init({port, ip, coords: [x, y]}) {
|
|
* return (x && y) ? {id, port} : {ip};
|
|
* };
|
|
*
|
|
* function init($__0) {
|
|
* var
|
|
* port = $__0.port,
|
|
* ip = $__0.ip,
|
|
* $__1 = $__0.coords,
|
|
* x = $__1[0],
|
|
* y = $__1[1];
|
|
* return (x && y) ? {id, port} : {ip};
|
|
* }
|
|
*
|
|
* var x, {ip, port} = init({ip, port});
|
|
*
|
|
* var x, $__0 = init({ip, port}), ip = $__0.ip, port = $__0.port;
|
|
*
|
|
*/
|
|
var Syntax = require('esprima-fb').Syntax;
|
|
var utils = require('../src/utils');
|
|
|
|
var reservedWordsHelper = require('./reserved-words-helper');
|
|
var restParamVisitors = require('./es6-rest-param-visitors');
|
|
var restPropertyHelpers = require('./es7-rest-property-helpers');
|
|
|
|
// -------------------------------------------------------
|
|
// 1. Structured variable declarations.
|
|
//
|
|
// var [a, b] = [b, a];
|
|
// var {x, y} = {y, x};
|
|
// -------------------------------------------------------
|
|
|
|
function visitStructuredVariable(traverse, node, path, state) {
|
|
// Allocate new temp for the pattern.
|
|
utils.append(utils.getTempVar(state.localScope.tempVarIndex) + '=', state);
|
|
// Skip the pattern and assign the init to the temp.
|
|
utils.catchupWhiteSpace(node.init.range[0], state);
|
|
traverse(node.init, path, state);
|
|
utils.catchup(node.init.range[1], state);
|
|
// Render the destructured data.
|
|
utils.append(',' + getDestructuredComponents(node.id, state), state);
|
|
state.localScope.tempVarIndex++;
|
|
return false;
|
|
}
|
|
|
|
visitStructuredVariable.test = function(node, path, state) {
|
|
return node.type === Syntax.VariableDeclarator &&
|
|
isStructuredPattern(node.id);
|
|
};
|
|
|
|
function isStructuredPattern(node) {
|
|
return node.type === Syntax.ObjectPattern ||
|
|
node.type === Syntax.ArrayPattern;
|
|
}
|
|
|
|
// Main function which does actual recursive destructuring
|
|
// of nested complex structures.
|
|
function getDestructuredComponents(node, state) {
|
|
var tmpIndex = state.localScope.tempVarIndex;
|
|
var components = [];
|
|
var patternItems = getPatternItems(node);
|
|
|
|
for (var idx = 0; idx < patternItems.length; idx++) {
|
|
var item = patternItems[idx];
|
|
if (!item) {
|
|
continue;
|
|
}
|
|
|
|
if (item.type === Syntax.SpreadElement) {
|
|
// Spread/rest of an array.
|
|
// TODO(dmitrys): support spread in the middle of a pattern
|
|
// and also for function param patterns: [x, ...xs, y]
|
|
components.push(item.argument.name +
|
|
'=Array.prototype.slice.call(' +
|
|
utils.getTempVar(tmpIndex) + ',' + idx + ')'
|
|
);
|
|
continue;
|
|
}
|
|
|
|
if (item.type === Syntax.SpreadProperty) {
|
|
var restExpression = restPropertyHelpers.renderRestExpression(
|
|
utils.getTempVar(tmpIndex),
|
|
patternItems
|
|
);
|
|
components.push(item.argument.name + '=' + restExpression);
|
|
continue;
|
|
}
|
|
|
|
// Depending on pattern type (Array or Object), we get
|
|
// corresponding pattern item parts.
|
|
var accessor = getPatternItemAccessor(node, item, tmpIndex, idx);
|
|
var value = getPatternItemValue(node, item);
|
|
|
|
// TODO(dmitrys): implement default values: {x, y=5}
|
|
if (value.type === Syntax.Identifier) {
|
|
// Simple pattern item.
|
|
components.push(value.name + '=' + accessor);
|
|
} else {
|
|
// Complex sub-structure.
|
|
components.push(
|
|
utils.getTempVar(++state.localScope.tempVarIndex) + '=' + accessor +
|
|
',' + getDestructuredComponents(value, state)
|
|
);
|
|
}
|
|
}
|
|
|
|
return components.join(',');
|
|
}
|
|
|
|
function getPatternItems(node) {
|
|
return node.properties || node.elements;
|
|
}
|
|
|
|
function getPatternItemAccessor(node, patternItem, tmpIndex, idx) {
|
|
var tmpName = utils.getTempVar(tmpIndex);
|
|
if (node.type === Syntax.ObjectPattern) {
|
|
if (reservedWordsHelper.isReservedWord(patternItem.key.name)) {
|
|
return tmpName + '["' + patternItem.key.name + '"]';
|
|
} else if (patternItem.key.type === Syntax.Literal) {
|
|
return tmpName + '[' + JSON.stringify(patternItem.key.value) + ']';
|
|
} else if (patternItem.key.type === Syntax.Identifier) {
|
|
return tmpName + '.' + patternItem.key.name;
|
|
}
|
|
} else if (node.type === Syntax.ArrayPattern) {
|
|
return tmpName + '[' + idx + ']';
|
|
}
|
|
}
|
|
|
|
function getPatternItemValue(node, patternItem) {
|
|
return node.type === Syntax.ObjectPattern
|
|
? patternItem.value
|
|
: patternItem;
|
|
}
|
|
|
|
// -------------------------------------------------------
|
|
// 2. Assignment expression.
|
|
//
|
|
// [a, b] = [b, a];
|
|
// ({x, y} = {y, x});
|
|
// -------------------------------------------------------
|
|
|
|
function visitStructuredAssignment(traverse, node, path, state) {
|
|
var exprNode = node.expression;
|
|
utils.append('var ' + utils.getTempVar(state.localScope.tempVarIndex) + '=', state);
|
|
|
|
utils.catchupWhiteSpace(exprNode.right.range[0], state);
|
|
traverse(exprNode.right, path, state);
|
|
utils.catchup(exprNode.right.range[1], state);
|
|
|
|
utils.append(
|
|
';' + getDestructuredComponents(exprNode.left, state) + ';',
|
|
state
|
|
);
|
|
|
|
utils.catchupWhiteSpace(node.range[1], state);
|
|
state.localScope.tempVarIndex++;
|
|
return false;
|
|
}
|
|
|
|
visitStructuredAssignment.test = function(node, path, state) {
|
|
// We consider the expression statement rather than just assignment
|
|
// expression to cover case with object patters which should be
|
|
// wrapped in grouping operator: ({x, y} = {y, x});
|
|
return node.type === Syntax.ExpressionStatement &&
|
|
node.expression.type === Syntax.AssignmentExpression &&
|
|
isStructuredPattern(node.expression.left);
|
|
};
|
|
|
|
// -------------------------------------------------------
|
|
// 3. Structured parameter.
|
|
//
|
|
// function foo({x, y}) { ... }
|
|
// -------------------------------------------------------
|
|
|
|
function visitStructuredParameter(traverse, node, path, state) {
|
|
utils.append(utils.getTempVar(getParamIndex(node, path)), state);
|
|
utils.catchupWhiteSpace(node.range[1], state);
|
|
return true;
|
|
}
|
|
|
|
function getParamIndex(paramNode, path) {
|
|
var funcNode = path[0];
|
|
var tmpIndex = 0;
|
|
for (var k = 0; k < funcNode.params.length; k++) {
|
|
var param = funcNode.params[k];
|
|
if (param === paramNode) {
|
|
break;
|
|
}
|
|
if (isStructuredPattern(param)) {
|
|
tmpIndex++;
|
|
}
|
|
}
|
|
return tmpIndex;
|
|
}
|
|
|
|
visitStructuredParameter.test = function(node, path, state) {
|
|
return isStructuredPattern(node) && isFunctionNode(path[0]);
|
|
};
|
|
|
|
function isFunctionNode(node) {
|
|
return (node.type == Syntax.FunctionDeclaration ||
|
|
node.type == Syntax.FunctionExpression ||
|
|
node.type == Syntax.MethodDefinition ||
|
|
node.type == Syntax.ArrowFunctionExpression);
|
|
}
|
|
|
|
// -------------------------------------------------------
|
|
// 4. Function body for structured parameters.
|
|
//
|
|
// function foo({x, y}) { x; y; }
|
|
// -------------------------------------------------------
|
|
|
|
function visitFunctionBodyForStructuredParameter(traverse, node, path, state) {
|
|
var funcNode = path[0];
|
|
|
|
utils.catchup(funcNode.body.range[0] + 1, state);
|
|
renderDestructuredComponents(funcNode, state);
|
|
|
|
if (funcNode.rest) {
|
|
utils.append(
|
|
restParamVisitors.renderRestParamSetup(funcNode, state),
|
|
state
|
|
);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
function renderDestructuredComponents(funcNode, state) {
|
|
var destructuredComponents = [];
|
|
|
|
for (var k = 0; k < funcNode.params.length; k++) {
|
|
var param = funcNode.params[k];
|
|
if (isStructuredPattern(param)) {
|
|
destructuredComponents.push(
|
|
getDestructuredComponents(param, state)
|
|
);
|
|
state.localScope.tempVarIndex++;
|
|
}
|
|
}
|
|
|
|
if (destructuredComponents.length) {
|
|
utils.append('var ' + destructuredComponents.join(',') + ';', state);
|
|
}
|
|
}
|
|
|
|
visitFunctionBodyForStructuredParameter.test = function(node, path, state) {
|
|
return node.type === Syntax.BlockStatement && isFunctionNode(path[0]);
|
|
};
|
|
|
|
exports.visitorList = [
|
|
visitStructuredVariable,
|
|
visitStructuredAssignment,
|
|
visitStructuredParameter,
|
|
visitFunctionBodyForStructuredParameter
|
|
];
|
|
|
|
exports.renderDestructuredComponents = renderDestructuredComponents;
|
|
|