1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 11x 11x 11x 5x 6x 6x 6x 6x 2x 8x 4x 4x 8x 4x 11x 11x 11x 11x 57x 57x 113x 41x 41x 32x 31x 1x 11x 11x 11x 11x 3x 8x 1x 7x 5x 2x 2x 6x 11x 99x 13x 13x 9x 1x 8x 8x 4x 86x 48x 99x 3x 12x 7x 5x 5x 2x | 'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.collapseNamedExports = collapseNamedExports; exports.extendDefaultExportWithNamedExports = extendDefaultExportWithNamedExports; exports.filterOutExportsWhichMatchPropsOnDefault = filterOutExportsWhichMatchPropsOnDefault; exports.findPropertiesOfDeclaration = findPropertiesOfDeclaration; exports.getPropNames = getPropNames; require('source-map-support/register'); var _babelTypes = require('babel-types'); var t = _interopRequireWildcard(_babelTypes); var _arrayFlatten = require('array-flatten'); var _arrayFlatten2 = _interopRequireDefault(_arrayFlatten); var _ast = require('./ast'); var _templates = require('./templates'); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _interopRequireWildcard(obj) { Eif (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; } } /** * Collapse named exports onto the default export so that the default export can be returned directly, * so that exports can be easily used by code that does not include an import interop. * This includes the following: * - Ignore named exports that already exist on the default export and which reference the same identifer. * - If possible, assign any remaining exports to the default export. * - This cannot be done if there is a naming conflict. * * In order to determine what properties the default export already has, the plugin will scan the * top level of the program to find any assignments, including Object.assign() and _extend() calls. * It does this recurively in the case of those method calls. * * If there are any named exports left, they get returned, so the main plugin can check the opts * and decide if an error should be thrown. */ function collapseNamedExports(programNode, defaultExportDeclaration, namedExports, opts) { namedExports = [...namedExports]; namedExports = filterOutExportsWhichMatchPropsOnDefault(programNode, defaultExportDeclaration, namedExports); if (!namedExports.length) { return []; } else Iif (opts.noExportExtend) { return namedExports; } else { return extendDefaultExportWithNamedExports(programNode, defaultExportDeclaration, namedExports); } } function extendDefaultExportWithNamedExports(programNode, defaultExportDeclaration, namedExports) { namedExports = [...namedExports]; // Shallow clone for safe splicing if (!defaultExportDeclaration.name) { // Something anonymous //TODO see if we can give it a name return namedExports; } else Iif (namedExports.some(exp => exp.conflict)) { return namedExports.conflicts.filter(exp => exp.conflict); } const id = t.isIdentifier(defaultExportDeclaration) ? defaultExportDeclaration : t.identifier(defaultExportDeclaration.name); for (const namedExport of namedExports) { programNode.body.push((0, _templates.buildAssign)({ OBJECT: id, NAME: namedExport.key, VALUE: namedExport.value })); } return []; } function filterOutExportsWhichMatchPropsOnDefault(programNode, defaultExportDeclaration, namedExports) { namedExports = [...namedExports]; // Shallow clone for safe splicing const defaultObjectInfo = findPropertiesOfDeclaration(programNode, defaultExportDeclaration); // Loop through the default object's props and see if it already has a matching definition of the named exports. // If the definition matches, we can ignore the named export. If the definition does not match, mark it as a conflict. Eif (defaultObjectInfo.properties) { for (const _ref of defaultObjectInfo.properties) { const { key, value } = _ref; if (t.isIdentifier(value)) { //let matchingNamedExportIndex = -1 const matchingNamedExportIndex = namedExports.findIndex(namedExport => namedExport.key.name === key.name); const matchingNamedExport = namedExports[matchingNamedExportIndex]; if (matchingNamedExport) { if (value.name === matchingNamedExport.value.name) { // Safe to ignore namedExports.splice(matchingNamedExportIndex, 1); } else { namedExports.conflict = true; } } } } } return namedExports; } function findPropertiesOfDeclaration(programNode, declaration) { const { type } = declaration; Iif (t.isFunctionDeclaration(declaration) || t.isArrowFunctionExpression(declaration)) { return { type }; } else if (t.isObjectExpression(declaration)) { return { type, properties: declaration.properties }; } else if (t.isClassDeclaration(declaration)) { return { type, properties: [...getStaticThingsOfClassDeclaration(declaration), ...getOtherPropertyOfIdentifier(programNode, declaration.id.name)] }; } else if (t.isIdentifier(declaration)) { return { type, properties: getOtherPropertyOfIdentifier(programNode, declaration.name) }; } else Eif ((0, _ast.isObjectAssignOrExtendsExpression)(declaration)) { return { type, properties: getPropertiesOfObjectAssignOrExtendHelper(declaration, programNode) }; } // console.log(require('util').inspect(declaration, { depth: null })); return { type }; } function getStaticThingsOfClassDeclaration(classDeclaration) { return classDeclaration.body.body.filter(item => item.static); } /** * Traverse the top level of the program body looking for either: * - ObjectExpression assignments to the object variable. * - Property assignments directly to our object (but not to nested properties). * * @return Array<{key, value}> */ function getOtherPropertyOfIdentifier(programNode, idName) { return (0, _arrayFlatten2.default)(programNode.body.map(node => { if (t.isExpressionStatement(node)) { // ID = value | ID.key = value | ID.key.nested = value const { left, right } = node.expression; if (t.isAssignmentExpression(node.expression)) { if (t.isIdentifier(left) && left.name === idName) { // ID = value Iif (t.isObjectExpression(right)) { // ID = {} return right.properties; // Array<ObjectProperty> } } else { const { object, property: key } = left; if (t.isIdentifier(object) && object.name === idName) { // ID.key = value return { key, value: right }; // ObjectProperty-like (key, value) } } } } else if (t.isVariableDeclaration(node)) { // console.log(require('util').inspect(node, { depth: 4 })); return node.declarations.filter(declaration => declaration.id.name === idName).map(declaration => declaration.init).filter(init => init).filter(init => t.isObjectExpression(init) || (0, _ast.isObjectAssignOrExtendsExpression)(init)).map(init => t.isObjectExpression(init) ? init.properties : getPropertiesOfObjectAssignOrExtendHelper(init, programNode)); } }).filter(item => item)); } function getPropertiesOfObjectAssignOrExtendHelper(node, programNode) { // Object.assign(...). Check all the args and recursively try to get props of identifiers (although they may be imported) return (0, _arrayFlatten2.default)(node.arguments.map(arg => { if (t.isObjectExpression(arg)) { return arg.properties; } else Eif (t.isIdentifier(arg)) { // recurse. although props will be empty if arg is an imported object return getOtherPropertyOfIdentifier(programNode, arg.name); } })); } // function getPropsFromObjectAssign() function getPropNames(props) { return props.map(prop => prop.key.name); } |