UNPKG

react-magnetic-di

Version:
110 lines (105 loc) 5.65 kB
"use strict"; function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); } function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } } function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); } function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); } function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; } var _require = require('./utils'), assert = _require.assert, getComponentDeclaration = _require.getComponentDeclaration; function processReference(t, path, locationValue, state) { var _locationValue$diRef; var self = getComponentDeclaration(t, path.scope); var bodyPath = path.get('body'); var shadowsOwnName = false; if (self) { var selfShadow = bodyPath.scope.getBinding(self.name); if (selfShadow && selfShadow.scope === bodyPath.scope && selfShadow.path.node.id !== self) { shadowsOwnName = true; } } // Build list of dependencies // combining used imports/exports in this function block // with existing di expression (if any) var depNames = []; locationValue.dependencyRefs.forEach(function (n) { var _n$node; var name = (_n$node = n.node) === null || _n$node === void 0 ? void 0 : _n$node.name; // quick check that the path is not detached if (!name || !n.parentPath) return; // Some babel plugins might rename imports (eg emotion) and references break // For now we skip, but ideally we would refresh the reference if (!bodyPath.scope.getBinding(name)) return; // Ensure we do not di() self name if (name === (self === null || self === void 0 ? void 0 : self.name)) { shadowsOwnName = true; return; } // Ensure we do not duplicate if (depNames.includes(name)) return; depNames.push(name); }); (_locationValue$diRef = locationValue.diRef) === null || _locationValue$diRef === void 0 || (_locationValue$diRef = _locationValue$diRef.container) === null || _locationValue$diRef === void 0 || (_locationValue$diRef = _locationValue$diRef.arguments) === null || _locationValue$diRef === void 0 || _locationValue$diRef.forEach(function (n) { assert.isValidArgument(t, n, locationValue.diRef, self); if (!depNames.includes(n.name)) depNames.push(n.name); }); depNames.sort(); // if there are no valid candidates, exit if (!depNames.length) return; var elements = depNames.map(function (v) { return t.identifier(v); }); var args = depNames.map(function (v) { return t.identifier(v); }); // add di there var declaration = t.variableDeclaration('const', [t.variableDeclarator(t.arrayPattern(elements), t.callExpression(t.identifier(state.diIdentifier.name), [self && !shadowsOwnName ? t.identifier(self.name) : t.nullLiteral()].concat(_toConsumableArray(args))))]); // We inject the new declaration either by replacing existing di // or by replacing and adding the statement at the top. // We need replacing to ensure we get a path so that registerDeclaration works var declarationPath; if (locationValue.diRef) { declarationPath = locationValue.diRef.getStatementParent(); declarationPath.replaceWith(declaration); } else { bodyPath.unshiftContainer('body', declaration); declarationPath = bodyPath.get('body.0'); } bodyPath.scope.registerDeclaration(declarationPath); var argsPaths = declarationPath.get('declarations.0.init.arguments'); argsPaths.forEach(function (argPath, idx) { var _bodyPath$parentPath; // the first argument is the self reference if (idx === 0) return; // For each argument we get the dependency variable name // then we rename it locally so we get a new unique identifier. // Then we manually revert just the argument identifier name back, // so it still points to the original dependency identifier name var name = argPath.node.name; var newName = state.getAlias(name, bodyPath.scope); bodyPath.scope.rename(name, newName); argPath.replaceWith(t.identifier(name)); // this is ugly but scope also renames dynamic object computed props // so we revert that change too if ((_bodyPath$parentPath = bodyPath.parentPath) !== null && _bodyPath$parentPath !== void 0 && (_bodyPath$parentPath = _bodyPath$parentPath.node) !== null && _bodyPath$parentPath !== void 0 && _bodyPath$parentPath.computed) { var key = bodyPath.parentPath.get('key'); if (key.isIdentifier() && key.node.name === newName) { // get [foo] () key.replaceWith(t.identifier(name)); } else { // get [foo()] {} / get [foo.bar] {} / ... key.traverse({ Identifier: function Identifier(keyPath) { if (keyPath.node.name === newName) { keyPath.replaceWith(t.identifier(name)); } } }); } } }); // ensure we add di import state.prependDiImport(t); } module.exports = processReference;