summaryrefslogtreecommitdiffstats
path: root/browser/components/newtab/tools/babel-jsm-to-commonjs.js
diff options
context:
space:
mode:
Diffstat (limited to 'browser/components/newtab/tools/babel-jsm-to-commonjs.js')
-rw-r--r--browser/components/newtab/tools/babel-jsm-to-commonjs.js287
1 files changed, 287 insertions, 0 deletions
diff --git a/browser/components/newtab/tools/babel-jsm-to-commonjs.js b/browser/components/newtab/tools/babel-jsm-to-commonjs.js
new file mode 100644
index 0000000000..0bf652da72
--- /dev/null
+++ b/browser/components/newtab/tools/babel-jsm-to-commonjs.js
@@ -0,0 +1,287 @@
+// The MIT License
+
+// Copyright (c) Kate Hudson <k88hudson@gmail.com>
+
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+"use strict";
+
+const DEFAULT_OPTIONS = {
+ // Only Cu.imports matching the following pattern will be rewritten as import statements.
+ basePath: /^resource:\/\//,
+
+ // Should the import path be rewritten to exclude the basePath?
+ // e.g. if the basePath is "resource://}, "resource://foo.jsm" becomes "foo.jsm"
+ replace: false,
+};
+
+module.exports = function plugin(babel) {
+ const t = babel.types;
+ let exportItems = [];
+
+ // module.exports = {foo, bar, baz};
+ function createModuleExports(exportedIdentifiers) {
+ const left = t.memberExpression(
+ t.identifier("module"),
+ t.identifier("exports")
+ );
+ const right = t.objectExpression(
+ exportedIdentifiers.map(item => {
+ return t.objectProperty(
+ t.identifier(item),
+ t.identifier(item),
+ false,
+ true
+ );
+ // return typeof item === "string" ? t.objectProperty(item, item) : t.objectProperty(item[0], item[1]);
+ })
+ );
+ return t.expressionStatement(t.assignmentExpression("=", left, right));
+ }
+
+ function replaceExports(nodes) {
+ nodes.forEach(path => {
+ if (
+ path.isVariableDeclaration() &&
+ path.get("declarations")[0] &&
+ path.get("declarations")[0].node.id.name === "EXPORTED_SYMBOLS"
+ ) {
+ exportItems = path
+ .get("declarations")[0]
+ .get("init.elements")
+ .map(e => e.node.value);
+ path.remove();
+ } else if (
+ path.isExpressionStatement() &&
+ path.get("expression").isAssignmentExpression() &&
+ path.get("expression.left.object").isThisExpression() &&
+ path.get("expression.left.property").isIdentifier()
+ ) {
+ const left = path.node.expression.left.property;
+ const { right } = path.node.expression;
+ if (left.name === "EXPORTED_SYMBOLS") {
+ // const names = right.elements.map(el => el.value);
+ // path.replaceWith(createModuleExports(names));
+ exportItems = right.elements.map(el => el.value);
+ path.remove();
+ } else {
+ const decl = t.variableDeclaration("var", [
+ t.variableDeclarator(left, right),
+ ]);
+ if (left.name === right.name) {
+ path.remove();
+ } else {
+ path.replaceWith(decl);
+ }
+ }
+ }
+ });
+ }
+
+ function checkForDeclarations(nodes, id, initFinalResults = []) {
+ const results = [];
+ let finalResults = [...initFinalResults];
+ nodes.forEach(parentPath => {
+ if (!parentPath.isVariableDeclaration()) return;
+ parentPath.traverse({
+ VariableDeclarator(path) {
+ if (!path.get("id").isIdentifier()) return;
+ const init = path.get("init");
+ if (init.isIdentifier() && init.node.name === id) {
+ results.push(path.node.id.name);
+ }
+ },
+ });
+ });
+ if (results.length) {
+ finalResults.push(...results);
+ results.forEach(name => {
+ finalResults = checkForDeclarations(nodes, name, finalResults);
+ });
+ return finalResults;
+ }
+ return finalResults;
+ }
+
+ function checkForUtilsDeclarations(nodes, ids) {
+ const results = [];
+ nodes.forEach(parentPath => {
+ if (!parentPath.isVariableDeclaration()) return;
+ parentPath.traverse({
+ VariableDeclarator(path) {
+ const id = path.get("id");
+ const init = path.get("init");
+
+ // const {utils} = Components;
+ if (
+ id.isObjectPattern() &&
+ init.isIdentifier() &&
+ ids.includes(init.node.name)
+ ) {
+ id.node.properties.forEach(prop => {
+ if (prop.key.name === "utils") {
+ results.push(prop.value.name);
+ }
+ });
+ }
+
+ // const foo = Components.utils;
+ else if (
+ id.isIdentifier() &&
+ init.isMemberExpression() &&
+ init.get("object").isIdentifier() &&
+ ids.includes(init.get("object").node.name) &&
+ init.get("property").isIdentifier() &&
+ init.get("property").node.name === "utils"
+ ) {
+ results.push(id.node.name);
+ }
+ },
+ });
+ });
+ return results;
+ }
+
+ function replaceImports(
+ nodes,
+ ComponentNames,
+ CuNames,
+ basePath,
+ replacePath,
+ removeOtherImports
+ ) {
+ nodes.forEach(p => {
+ if (!p.isVariableDeclaration()) return;
+ p.traverse({
+ CallExpression(path) {
+ if (
+ t.isStringLiteral(path.node.arguments[0]) &&
+ // path.node.arguments[0].value.match(basePath) &&
+ t.isObjectPattern(path.parentPath.node.id) &&
+ // Check if actually Components.utils.import
+ path.get("callee").isMemberExpression() &&
+ (path.get("callee.property").node.name === "import" ||
+ path.get("callee.property").node.name === "importESModule")
+ ) {
+ const callee = path.get("callee");
+ if (callee.get("object").isMemberExpression()) {
+ if (
+ !ComponentNames.includes(
+ callee.get("object.object").node.name
+ ) ||
+ callee.get("object.property").node.name !== "utils"
+ ) {
+ return;
+ }
+ } else {
+ const objectName = callee.get("object").node.name;
+ if (
+ objectName !== "ChromeUtils" &&
+ !CuNames.includes(objectName)
+ ) {
+ return;
+ }
+ }
+ let filePath = path.node.arguments[0].value;
+
+ if (
+ !removeOtherImports ||
+ (replacePath && filePath.match(basePath))
+ ) {
+ if (replacePath) filePath = filePath.replace(basePath, "");
+ const requireStatement = t.callExpression(
+ t.identifier("require"),
+ [t.stringLiteral(filePath)]
+ );
+ path.replaceWith(requireStatement);
+ } else if (removeOtherImports) {
+ path.parentPath.parentPath.remove();
+ }
+ }
+ },
+ });
+ });
+ }
+
+ function replaceModuleGetters(paths, basePath, replacePath) {
+ paths.forEach(path => {
+ if (
+ path.isExpressionStatement() &&
+ path.get("expression").isCallExpression() &&
+ ["XPCOMUtils", "ChromeUtils"].includes(
+ path.get("expression.callee.object.name").node
+ ) &&
+ ["defineLazyModuleGetter", "defineModuleGetter"].includes(
+ path.get("expression.callee.property.name").node
+ )
+ ) {
+ const argPaths = path.get("expression.arguments");
+ const idName = argPaths[1].node.value;
+ let filePath = argPaths[2].node.value;
+
+ if (!filePath.match(basePath)) return;
+
+ if (replacePath) filePath = filePath.replace(basePath, "");
+ const requireStatement = t.callExpression(t.identifier("require"), [
+ t.stringLiteral(filePath),
+ ]);
+ const varDecl = t.variableDeclaration("var", [
+ t.variableDeclarator(
+ t.objectPattern([
+ t.objectProperty(
+ t.identifier(idName),
+ t.identifier(idName),
+ false,
+ true
+ ),
+ ]),
+ requireStatement
+ ),
+ ]);
+ path.replaceWith(varDecl);
+ }
+ });
+ }
+
+ return {
+ visitor: {
+ Program(path, state) {
+ const opts = Object.assign({}, DEFAULT_OPTIONS, state.opts);
+ const topLevelNodes = path.get("body");
+ const ids = checkForDeclarations(topLevelNodes, "Components", [
+ "Components",
+ ]);
+ const utils = checkForUtilsDeclarations(topLevelNodes, ids);
+ replaceImports(
+ topLevelNodes,
+ ids,
+ utils,
+ opts.basePath,
+ opts.replace,
+ opts.removeOtherImports
+ );
+ replaceModuleGetters(topLevelNodes, opts.basePath, opts.replace);
+ replaceExports(topLevelNodes);
+ if (exportItems.length) {
+ path.pushContainer("body", createModuleExports(exportItems));
+ }
+ },
+ },
+ };
+};