UNPKG

babel-plugin-transform-modules-ui5

Version:
230 lines (218 loc) 11.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.wrap = wrap; var _core = require("@babel/core"); var eh = _interopRequireWildcard(require("./exports")); 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; } function wrap(visitor, programNode, opts) { var _body; let { defaultExport, exportGlobal, firstImportMarked, imports, namedExports, ignoredImports, injectDynamicImportHelper } = visitor; const needsWrap = !!(defaultExport || imports.length || namedExports.length || injectDynamicImportHelper); if (!needsWrap) { // cleanup the program node if it's empty (just having empty imports) programNode.body = programNode.body.filter(node => { if (_core.types.isExportNamedDeclaration(node)) { return node.declaration != null; } return true; }); return; } let { body } = programNode; // find the copyright comment from the original program body and remove it there // since it need to be put around the new program body (which is sap.ui.define) let copyright = (_body = body) === null || _body === void 0 || (_body = _body[0]) === null || _body === void 0 || (_body = _body.leadingComments) === null || _body === void 0 ? void 0 : _body.find((comment, idx, arr) => { if (comment.value.startsWith("!")) { arr.splice(idx, 1); return true; } }); // in case of TypeScript transpiling taking place upfront, the copyright comment // is associcated with the program and not the program body, so we need to find it // and move it to the new program body (which is sap.ui.define) if (!copyright) { var _visitor$parent; copyright = (_visitor$parent = visitor.parent) === null || _visitor$parent === void 0 || (_visitor$parent = _visitor$parent.comments) === null || _visitor$parent === void 0 ? void 0 : _visitor$parent.find((comment, idx, arr) => { if (comment.value.startsWith("!")) { arr.splice(idx, 1); return true; } }); } let allExportHelperAdded = false; let extendAdded = false; opts.collapse = !opts.noExportCollapse; // opts.extend = !opts.noExportExtend // Before adding anything, see if the named exports can be collapsed into the default export. if (defaultExport && namedExports.length && opts.collapse) { let { filteredExports, conflictingExports, newDefaultExportIdentifier } = eh.collapseNamedExports(programNode, defaultExport, namedExports, opts); if (filteredExports.length && !opts.allowUnsafeMixedExports) { throw new Error(`Unsafe mixing of conflicting default and named exports. The following named exports are conflicting: (${ast.getPropNames(conflictingExports).join(", ")}).`); } else { namedExports = filteredExports; } // The default export may have changed if the collapse logic needed to assign a prop when the default export was previously anonymous. if (newDefaultExportIdentifier) { extendAdded = true; // If an anonymous default export needed to be assigned to a a variable, it uses the exports name for convenience. defaultExport = newDefaultExportIdentifier; } } let moveUseStrictIfNeeded = false; const preDefine = [...ignoredImports]; // If the noWrapBeforeImport opt is set, split any code before the first import and afterwards into separate arrays. // This should be done before any interops or other vars are injected. if (opts.noWrapBeforeImport && firstImportMarked) { let reachedFirstImport = false; const fullBody = body; const newBody = []; // If there is no lastBeforeWrapping, the first import is not marked if (!fullBody.find(item => item.lastBeforeWrapping)) { reachedFirstImport = true; } for (const item of fullBody) { if (reachedFirstImport) { newBody.push(item); } else { preDefine.push(item); } if (item.lastBeforeWrapping) { reachedFirstImport = true; } } moveUseStrictIfNeeded = true; body = newBody; } // If the QUnit.config.autostart is found it needs to be moved to the top of the program if (opts.noWrapQUnitConfigAutostart === undefined || opts.noWrapQUnitConfigAutostart) { const qunitConfigAutostart = findQUnitConfigAutostart(body, imports); if (qunitConfigAutostart) { preDefine.push(qunitConfigAutostart); body = body.filter(node => node !== qunitConfigAutostart); moveUseStrictIfNeeded = true; } } // if code has been moved to preDefine, we need to move the "use strict" directive if (moveUseStrictIfNeeded) { if (!opts.neverUseStrict && preDefine.length && !hasUseStrict(programNode)) { programNode.directives = [_core.types.directive(_core.types.directiveLiteral("use strict")), ...(programNode.directives || [])]; } } if (injectDynamicImportHelper) { // import() to sap.ui.require() w/ promise and interop body.unshift(th.buildDynamicImportHelper()); } if (!namedExports.length && defaultExport) { // If there's no named exports, return the default export body.push(_core.types.returnStatement(defaultExport)); } else if (namedExports.length) { if (!extendAdded) { body.push(th.buildDeclareExports()); // i.e. const __exports = {__esModule: true}; } for (const namedExport of namedExports) { if (namedExport.all) { if (!allExportHelperAdded) { body.push(th.buildAllExportHelper()); allExportHelperAdded = true; } body.push(th.buildAllExport({ LOCAL: namedExport.value })); } else { body.push(th.buildNamedExport(namedExport)); } } if (defaultExport) { body.push(th.buildNamedExport({ key: _core.types.identifier("default"), value: defaultExport })); } body.push(th.buildReturnExports()); } if (imports.some(imp => imp.interop)) { body.unshift(th.buildDefaultImportInterop()); } // should we use sap.ui.require instead of sap.ui.define? let useSapUiRequire = hasUseSapUiRequire(visitor.parent.comments, body, true); // generate the sap.ui.define or sap.ui.require const defineOrRequire = generateDefineOrRequire(body, imports, exportGlobal || opts.exportAllGlobal, useSapUiRequire); // add the "use strict" directive if not on program node if (!opts.neverUseStrict && !hasUseStrict(programNode)) { const defineOrRequireFnBody = defineOrRequire.expression.arguments[1].body; defineOrRequireFnBody.directives = [_core.types.directive(_core.types.directiveLiteral("use strict")), ...(defineOrRequireFnBody.directives || [])]; } programNode.body = [...preDefine, defineOrRequire]; // if a copyright comment is present we append it to the new program node if (copyright && visitor.parent) { visitor.parent.leadingComments = visitor.parent.leadingComments || []; visitor.parent.leadingComments.unshift(copyright); } } function hasUseStrict(node) { return (node.directives || []).some(directive => directive.value.value === "use strict"); } function hasUseSapUiRequire(comments, body, remove) { // detect the @sapUiRequire comment return comments.some(comment => { let found = false; // check for existing comment block if (comment.type === "CommentBlock") { found = comment.value.trim() === "@sapUiRequire"; } // remove the comment (if it is somewhere in the body) if (found && remove) { body === null || body === void 0 || body.forEach(node => { (0, _core.traverse)(node, { enter(path) { ["leadingComments", "trailingComments", "innerComments"].forEach(key => { var _path$node$key; path.node[key] = (_path$node$key = path.node[key]) === null || _path$node$key === void 0 ? void 0 : _path$node$key.filter(c => c !== comment); }); }, noScope: true }); }); } return found; }); } function findQUnitConfigAutostart(body, imports) { // if one imports QUnit, we don't need to move the QUnit.config.autostart // as the configuration should apply to the local QUnit module if (imports !== null && imports !== void 0 && imports.some(imp => imp.name === "QUnit")) { return undefined; } // find the QUnit.config.autostart return body === null || body === void 0 ? void 0 : body.find(node => { return _core.types.isExpressionStatement(node) && _core.types.isAssignmentExpression(node.expression) && _core.types.isMemberExpression(node.expression.left) && _core.types.isMemberExpression(node.expression.left.object) && _core.types.isIdentifier(node.expression.left.object.object) && node.expression.left.object.object.name === "QUnit" && _core.types.isIdentifier(node.expression.left.object.property) && node.expression.left.object.property.name === "config" && _core.types.isIdentifier(node.expression.left.property) && node.expression.left.property.name === "autostart" && node.expression.operator === "=" /* && t.isBooleanLiteral(node.expression.right) && node.expression.right.value === false */; }); } function generateDefineOrRequire(body, imports, exportGlobal, useRequire) { const defineOpts = { SOURCES: _core.types.arrayExpression(imports.map(i => _core.types.stringLiteral(i.src))), PARAMS: imports.map(i => _core.types.identifier(i.tmpName)), BODY: body }; return useRequire ? th.buildRequire(defineOpts) : exportGlobal ? th.buildDefineGlobal(defineOpts) : th.buildDefine(defineOpts); }