UNPKG

babel-plugin-transform-modules-ui5

Version:
121 lines (119 loc) 5.92 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.collapseNamedExports = collapseNamedExports; exports.getDefaultExportName = getDefaultExportName; var _core = require("@babel/core"); var th = _interopRequireWildcard(require("../../utils/templates")); var ast = _interopRequireWildcard(require("../../utils/ast")); function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); } function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } /** * 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 recursively 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, defaultExport, namedExports, opts) { namedExports = filterOutExportsWhichAlreadyMatchPropsOnDefault(programNode, defaultExport, namedExports); if (!namedExports.length || opts.noExportExtend) { return { filteredExports: namedExports, newDefaultExportIdentifier: null }; } if (namedExports.some(exp => exp.conflict)) { return { filteredExports: namedExports, conflictingExports: namedExports.filter(exp => exp.conflict), newDefaultExportIdentifier: null }; } let exportVariableName = getDefaultExportName(defaultExport); let newDefaultExportIdentifier = null; if (!exportVariableName) { // Something anonymous (literal, anon function, etc...) programNode.body.push(th.buildTempExport({ VALUE: defaultExport })); newDefaultExportIdentifier = th.exportsIdentifier; exportVariableName = newDefaultExportIdentifier.name; } const id = _core.types.identifier(exportVariableName); for (const namedExport of namedExports) { programNode.body.push(th.buildAssign({ OBJECT: id, NAME: namedExport.key, VALUE: namedExport.value })); } return { filteredExports: [], conflictingExports: [], newDefaultExportIdentifier: newDefaultExportIdentifier }; } function getDefaultExportName(defaultExport) { return defaultExport.name || ast.getIdName(defaultExport); } function filterOutExportsWhichAlreadyMatchPropsOnDefault(programNode, defaultExport, namedExports) { namedExports = [...namedExports]; // Shallow clone for safe splicing const defaultObjectProperties = ast.findPropertiesOfNode(programNode, defaultExport); // 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. if (defaultObjectProperties) { for (const defaultExportProperty of defaultObjectProperties) { if (!defaultExportProperty.key) { // i.e. SpreadProperty continue; } const matchingNamedExportIndex = namedExports.findIndex(namedExport => namedExport.key.name === defaultExportProperty.key.name); // get the index for splicing const matchingNamedExport = namedExports[matchingNamedExportIndex]; if (matchingNamedExport && !matchingNamedExport.conflict) { if (areSame(defaultExportProperty, matchingNamedExport)) { namedExports.splice(matchingNamedExportIndex, 1); } else { matchingNamedExport.conflict = true; } } } } return namedExports; } function areSame(defaultExportProperty, matchingNamedExport) { const defaultExportValue = defaultExportProperty.value; const declaration = matchingNamedExport.declaration; // i.e. 'export const a = 1' or 'export let a = b' if (!defaultExportValue) { // i.e. object method return false; // always a conflict } else if (_core.types.isIdentifier(defaultExportValue)) { const valueName = defaultExportValue.name; if (valueName === matchingNamedExport.value.name) { // Same identifier reference. Safe to ignore return true; } else if (declaration && _core.types.isIdentifier(declaration.init) && declaration.init.name === valueName) { // i.e. 'export let a = b', and default value for a is 'b'. return true; } } else if (_core.types.isLiteral(defaultExportValue)) { // i.e. { a: 1 } or { a: '1' } // See if the original declaration for the matching export was for the same literal if (_core.types.isLiteral(declaration.init) && declaration.init.value === defaultExportValue.value) { // i.e. 'export const a = 1' // Same literal. Safe to ignore return true; } } // Either a conflicting value or no value at all (i.e. method) return false; }