"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ exports.factorifyObjects = factorifyObjects; var _babelTypes = require("babel-types"); var t = _interopRequireWildcard(_babelTypes); var _generator = require("../utils/generator.js"); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } function isLiteral(node) { switch (node.type) { case "NullLiteral": case "BooleanLiteral": case "StringLiteral": case "NumericLiteral": return true; case "UnaryExpression": return node.operator === "void" && isLiteral(node.argument); default: return false; } } function isSameNode(left, right) { var type = left.type; if (type !== right.type) { return false; } if (type === "Identifier") { return left.name === right.name; } if (type === "NullLiteral") { return true; } if (type === "BooleanLiteral" || type === "StringLiteral" || type === "NumericLiteral") { return left.value === right.value; } if (type === "UnaryExpression") { return left.operator === "void" && right.operator === "void" && isLiteral(left.argument) && isLiteral(right.argument); } return false; } function getObjectKeys(obj) { var keys = []; var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = obj.properties[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { var prop = _step.value; if (prop.type !== "ObjectProperty") return false; var key = prop.key; if (key.type === "StringLiteral") { keys.push(key.value); } else if (key.type === "Identifier") { if (prop.computed) return false; keys.push(key.name); } else { return false; } } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator.return) { _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } var _iteratorNormalCompletion2 = true; var _didIteratorError2 = false; var _iteratorError2 = undefined; try { for (var _iterator2 = keys[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { var key = _step2.value; if (key.indexOf("|") >= 0) return false; } } catch (err) { _didIteratorError2 = true; _iteratorError2 = err; } finally { try { if (!_iteratorNormalCompletion2 && _iterator2.return) { _iterator2.return(); } } finally { if (_didIteratorError2) { throw _iteratorError2; } } } return keys.join("|"); } // This function looks for recurring initialization patterns in the code of the form // var x = { a: literal1, b: literal2 } // var y = { a: literal1, b: literal3 } // and transforms them into something like // function factory(b) { return { a: literal1, b } } // var x = factory(literal2); // var y = factory(literal3); // TODO #884: Right now, the visitor below only looks into top-level variable declaration // with a flat object literal initializer. // It should also look into conditional control flow, residual functions, and nested object literals. function factorifyObjects(body, factoryNameGenerator) { var signatures = Object.create(null); var _iteratorNormalCompletion3 = true; var _didIteratorError3 = false; var _iteratorError3 = undefined; try { for (var _iterator3 = body[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { var node = _step3.value; switch (node.type) { case "VariableDeclaration": var _iteratorNormalCompletion10 = true; var _didIteratorError10 = false; var _iteratorError10 = undefined; try { for (var _iterator10 = node.declarations[Symbol.iterator](), _step10; !(_iteratorNormalCompletion10 = (_step10 = _iterator10.next()).done); _iteratorNormalCompletion10 = true) { var _declar2 = _step10.value; var init = _declar2.init; if (!init) continue; if (init.type !== "ObjectExpression") continue; var _keys2 = getObjectKeys(init); if (!_keys2) continue; var _initializerAstNodeName2 = "init"; var _declars2 = signatures[_keys2] = signatures[_keys2] || []; _declars2.push({ declar: _declar2, initializerAstNodeName: _initializerAstNodeName2 }); } } catch (err) { _didIteratorError10 = true; _iteratorError10 = err; } finally { try { if (!_iteratorNormalCompletion10 && _iterator10.return) { _iterator10.return(); } } finally { if (_didIteratorError10) { throw _iteratorError10; } } } break; case "ExpressionStatement": var expr = node.expression; if (expr.type !== "AssignmentExpression") { break; } var right = expr.right; if (right.type !== "ObjectExpression") { break; } var _keys = getObjectKeys(right); if (!_keys) continue; var _initializerAstNodeName = "right"; var _declars = signatures[_keys] = signatures[_keys] || []; _declars.push({ declar: node.expression, initializerAstNodeName: _initializerAstNodeName }); break; default: // Continue to next node. break; } } } catch (err) { _didIteratorError3 = true; _iteratorError3 = err; } finally { try { if (!_iteratorNormalCompletion3 && _iterator3.return) { _iterator3.return(); } } finally { if (_didIteratorError3) { throw _iteratorError3; } } } for (var signatureKey in signatures) { var declars = signatures[signatureKey]; if (declars.length < 5) continue; var keys = signatureKey.split("|"); // var rootFactoryParams = []; var rootFactoryProps = []; for (var keyIndex = 0; keyIndex < keys.length; keyIndex++) { var key = keys[keyIndex]; var id = t.identifier("__" + keyIndex); rootFactoryParams.push(id); var keyNode = t.isValidIdentifier(key) ? t.identifier(key) : t.stringLiteral(key); rootFactoryProps.push(t.objectProperty(keyNode, id)); } var rootFactoryId = t.identifier(factoryNameGenerator.generate("root")); var rootFactoryBody = t.blockStatement([t.returnStatement(t.objectExpression(rootFactoryProps))]); var rootFactory = t.functionDeclaration(rootFactoryId, rootFactoryParams, rootFactoryBody); body.unshift(rootFactory); // var _iteratorNormalCompletion4 = true; var _didIteratorError4 = false; var _iteratorError4 = undefined; try { for (var _iterator4 = declars[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) { var _ref = _step4.value; var declar = _ref.declar, initializerAstNodeName = _ref.initializerAstNodeName; var args = []; var _iteratorNormalCompletion6 = true; var _didIteratorError6 = false; var _iteratorError6 = undefined; try { for (var _iterator6 = declar[initializerAstNodeName].properties[Symbol.iterator](), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) { var prop = _step6.value; args.push(prop.value); } } catch (err) { _didIteratorError6 = true; _iteratorError6 = err; } finally { try { if (!_iteratorNormalCompletion6 && _iterator6.return) { _iterator6.return(); } } finally { if (_didIteratorError6) { throw _iteratorError6; } } } declar[initializerAstNodeName] = t.callExpression(rootFactoryId, args); } // } catch (err) { _didIteratorError4 = true; _iteratorError4 = err; } finally { try { if (!_iteratorNormalCompletion4 && _iterator4.return) { _iterator4.return(); } } finally { if (_didIteratorError4) { throw _iteratorError4; } } } var seen = new Set(); var _loop = function _loop(_ref2) { var declar = _ref2.declar, initializerAstNodeName = _ref2.initializerAstNodeName; if (seen.has(declar)) return "continue"; // build up a map containing the arguments that are shared var common = new Map(); var mostSharedArgsLength = 0; var _iteratorNormalCompletion7 = true; var _didIteratorError7 = false; var _iteratorError7 = undefined; try { for (var _iterator7 = declars[Symbol.iterator](), _step7; !(_iteratorNormalCompletion7 = (_step7 = _iterator7.next()).done); _iteratorNormalCompletion7 = true) { var _ref3 = _step7.value; var declar2 = _ref3.declar, initializerAstNodeName2 = _ref3.initializerAstNodeName; if (seen.has(declar2)) continue; if (declar === declar2) continue; var _sharedArgs = []; for (var _i = 0; _i < keys.length; _i++) { if (isSameNode(declar[initializerAstNodeName].arguments[_i], declar2[initializerAstNodeName2].arguments[_i])) { _sharedArgs.push(_i); } } if (!_sharedArgs.length) continue; mostSharedArgsLength = Math.max(mostSharedArgsLength, _sharedArgs.length); common.set(declar2, _sharedArgs); } // build up a mapping of the argument positions that are shared so we can pick the top one } catch (err) { _didIteratorError7 = true; _iteratorError7 = err; } finally { try { if (!_iteratorNormalCompletion7 && _iterator7.return) { _iterator7.return(); } } finally { if (_didIteratorError7) { throw _iteratorError7; } } } var sharedPairs = Object.create(null); var _iteratorNormalCompletion8 = true; var _didIteratorError8 = false; var _iteratorError8 = undefined; try { for (var _iterator8 = common.entries()[Symbol.iterator](), _step8; !(_iteratorNormalCompletion8 = (_step8 = _iterator8.next()).done); _iteratorNormalCompletion8 = true) { var _ref4 = _step8.value; var _ref5 = _slicedToArray(_ref4, 2); var _declar = _ref5[0]; var _args = _ref5[1]; if (_args.length === mostSharedArgsLength) { _args = _args.join(","); var _pair = sharedPairs[_args] = sharedPairs[_args] || []; _pair.push(_declar); } } // get the highest pair } catch (err) { _didIteratorError8 = true; _iteratorError8 = err; } finally { try { if (!_iteratorNormalCompletion8 && _iterator8.return) { _iterator8.return(); } } finally { if (_didIteratorError8) { throw _iteratorError8; } } } var highestPairArgs = void 0; var highestPairCount = void 0; for (var pairArgs in sharedPairs) { var pair = sharedPairs[pairArgs]; if (!highestPairArgs || pair.length > highestPairCount) { highestPairCount = pair.length; highestPairArgs = pairArgs; } } if (!highestPairArgs) return "continue"; // var declarsSub = sharedPairs[highestPairArgs].concat(declar); var removeArgs = highestPairArgs.split(","); var subFactoryArgs = []; var subFactoryParams = []; var sharedArgs = declarsSub[0][initializerAstNodeName].arguments; for (var i = 0; i < sharedArgs.length; i++) { var arg = sharedArgs[i]; if (removeArgs.indexOf(i + "") >= 0) { subFactoryArgs.push(arg); } else { var _id = t.identifier("__" + i); subFactoryArgs.push(_id); subFactoryParams.push(_id); } } var subFactoryId = t.identifier(factoryNameGenerator.generate("sub")); var subFactoryBody = t.blockStatement([t.returnStatement(t.callExpression(rootFactoryId, subFactoryArgs))]); var subFactory = t.functionDeclaration(subFactoryId, subFactoryParams, subFactoryBody); body.unshift(subFactory); var _iteratorNormalCompletion9 = true; var _didIteratorError9 = false; var _iteratorError9 = undefined; try { for (var _iterator9 = declarsSub[Symbol.iterator](), _step9; !(_iteratorNormalCompletion9 = (_step9 = _iterator9.next()).done); _iteratorNormalCompletion9 = true) { var declarSub = _step9.value; seen.add(declarSub); var call = declarSub[initializerAstNodeName]; call.callee = subFactoryId; call.arguments = call.arguments.filter(function (val, i) { return removeArgs.indexOf(i + "") < 0; }); } } catch (err) { _didIteratorError9 = true; _iteratorError9 = err; } finally { try { if (!_iteratorNormalCompletion9 && _iterator9.return) { _iterator9.return(); } } finally { if (_didIteratorError9) { throw _iteratorError9; } } } }; var _iteratorNormalCompletion5 = true; var _didIteratorError5 = false; var _iteratorError5 = undefined; try { for (var _iterator5 = declars[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) { var _ref2 = _step5.value; var _ret = _loop(_ref2); if (_ret === "continue") continue; } } catch (err) { _didIteratorError5 = true; _iteratorError5 = err; } finally { try { if (!_iteratorNormalCompletion5 && _iterator5.return) { _iterator5.return(); } } finally { if (_didIteratorError5) { throw _iteratorError5; } } } } } //# sourceMappingURL=factorify.js.map