/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at . */ "use strict"; const Babel = require("./babel"); const _path = require("path"); function isRequire(t, node) { return node && t.isCallExpression(node) && node.callee.name == "require"; } function shouldLazyLoad(value) { return ( !value.includes("codemirror/") && !value.endsWith(".properties") && !value.startsWith("devtools/") && !value.startsWith("resource://devtools/") && // XXX: the lazyRequire rewriter (in transformMC) fails for this module, it // evaluates `t.thisExpression()` as `void 0` instead of `this`. But the // rewriter still works for other call sites and seems mandatory for the // debugger to start successfully (lazy requires help to break circular // dependencies). value !== "resource://gre/modules/AppConstants.jsm" ); } /** * This Babel plugin is used to transpile a single Debugger module into a module that * can be loaded in Firefox via the regular DevTools loader. */ function transformMC({ types: t }) { return { visitor: { StringLiteral(path, state) { const { filePath } = state.opts; let value = path.node.value; if (!isRequire(t, path.parent)) { return; } if (shouldLazyLoad(value)) { const requireCall = path.parentPath; const declarator = requireCall.parentPath; const declaration = declarator.parentPath; // require()s that are not assigned to a variable cannot be safely lazily required // since we lack anything to initiate the require (= the getter for the variable) if (declarator.type !== "VariableDeclarator") { return; } // update relative paths to be "absolute" (starting with devtools/) // e.g. ./utils/source-queue if (value.startsWith(".")) { // Create full path // e.g. z:\build\build\src\devtools\client\debugger\src\utils\source-queue let newValue = _path.join(_path.dirname(filePath), value); // Select the devtools portion of the path // e.g. devtools\client\debugger\src\utils\source-queue if (!newValue.startsWith("devtools")) { newValue = newValue.match(/^(.*?)(devtools.*)/)[2]; } // Replace forward slashes with back slashes // e.g devtools/client/debugger/src/utils/source-queue newValue = newValue.replace(/\\/g, "/"); value = newValue; } // rewrite to: loader.lazyRequireGetter(this, "variableName", "pathToFile") const lazyRequire = t.callExpression( t.memberExpression( t.identifier("loader"), t.identifier("lazyRequireGetter") ), [ t.thisExpression(), t.stringLiteral(declarator.node.id.name || ""), t.stringLiteral(value), ] ); declaration.replaceWith(lazyRequire); } }, }, }; } Babel.registerPlugin("transform-mc", transformMC); module.exports = function (filePath) { return [ "proposal-class-properties", "transform-modules-commonjs", ["transform-mc", { filePath }], ]; };