Bug 1779538 - Rewrite ChromeUtils.importESModule with static import in sys.mjs. r=yulia

Differential Revision: https://phabricator.services.mozilla.com/D151801
This commit is contained in:
Tooru Fujisawa 2022-07-14 08:54:01 +00:00
Родитель 72ba7fb691
Коммит b9aa9e471a
2 изменённых файлов: 82 добавлений и 4 удалений

Просмотреть файл

@ -8,7 +8,10 @@
/* global require, __dirname, process */ /* global require, __dirname, process */
const _path = require("path"); const _path = require("path");
const { isESMified } = require(_path.resolve(__dirname, "./is-esmified.js")); const { isESMified, getESMFiles } = require(_path.resolve(
__dirname,
"./is-esmified.js"
));
/* global module */ /* global module */
@ -41,6 +44,22 @@ function isESMifiedAndTarget(resourceURI) {
return true; return true;
} }
function isTargetESM(resourceURI) {
if ("ESMIFY_TARGET_PREFIX" in process.env) {
const files = getESMFiles(resourceURI);
const targetPrefix = process.env.ESMIFY_TARGET_PREFIX;
for (const esm of files) {
if (esm.startsWith(targetPrefix)) {
return true;
}
}
return false;
}
return true;
}
function IsIdentifier(node, name) { function IsIdentifier(node, name) {
if (node.type !== "Identifier") { if (node.type !== "Identifier") {
return false; return false;
@ -68,6 +87,11 @@ function isImportCall(node) {
return ["Cu.import", "ChromeUtils.import"].includes(s); return ["Cu.import", "ChromeUtils.import"].includes(s);
} }
function isImportESModuleCall(node) {
const s = calleeToString(node.callee);
return ["ChromeUtils.importESModule"].includes(s);
}
function isLazyGetterCall(node) { function isLazyGetterCall(node) {
const s = calleeToString(node.callee); const s = calleeToString(node.callee);
return [ return [
@ -98,7 +122,9 @@ function isString(node) {
return node.type === "Literal" && typeof node.value === "string"; return node.type === "Literal" && typeof node.value === "string";
} }
function tryReplacingWithStatciImport( // Replace `ChromeUtils.import`, `Cu.import`, and `ChromeUtils.importESModule`
// with static import if it's at the top-level of system ESM file.
function tryReplacingWithStaticImport(
jscodeshift, jscodeshift,
inputFile, inputFile,
path, path,
@ -109,6 +135,7 @@ function tryReplacingWithStatciImport(
return false; return false;
} }
// Check if it's at the top-level.
if (path.parent.node.type !== "VariableDeclarator") { if (path.parent.node.type !== "VariableDeclarator") {
return false; return false;
} }
@ -132,8 +159,8 @@ function tryReplacingWithStatciImport(
const resourceURI = resourceURINode.value; const resourceURI = resourceURINode.value;
// Collect imported symbols.
const specs = []; const specs = [];
if (path.parent.node.id.type === "Identifier") { if (path.parent.node.id.type === "Identifier") {
specs.push(jscodeshift.importNamespaceSpecifier(path.parent.node.id)); specs.push(jscodeshift.importNamespaceSpecifier(path.parent.node.id));
} else if (path.parent.node.id.type === "ObjectPattern") { } else if (path.parent.node.id.type === "ObjectPattern") {
@ -150,6 +177,8 @@ function tryReplacingWithStatciImport(
return false; return false;
} }
// If this is `ChromeUtils.import` or `Cu.import`, replace the extension.
// no-op for `ChromeUtils.importESModule`.
resourceURINode.value = esmify(resourceURI); resourceURINode.value = esmify(resourceURI);
const e = jscodeshift.importDeclaration(specs, resourceURINode); const e = jscodeshift.importDeclaration(specs, resourceURINode);
@ -183,7 +212,7 @@ function replaceImportCall(inputFile, jscodeshift, path) {
} }
if ( if (
!tryReplacingWithStatciImport(jscodeshift, inputFile, path, resourceURINode) !tryReplacingWithStaticImport(jscodeshift, inputFile, path, resourceURINode)
) { ) {
path.node.callee.object.name = "ChromeUtils"; path.node.callee.object.name = "ChromeUtils";
path.node.callee.property.name = "importESModule"; path.node.callee.property.name = "importESModule";
@ -191,6 +220,31 @@ function replaceImportCall(inputFile, jscodeshift, path) {
} }
} }
function replaceImportESModuleCall(inputFile, jscodeshift, path) {
if (path.node.arguments.length !== 1) {
warnForPath(
inputFile,
path,
`importESModule call should have only one argument`
);
return;
}
const resourceURINode = path.node.arguments[0];
if (!isString(resourceURINode)) {
warnForPath(inputFile, path, `resource URI should be a string`);
return;
}
const resourceURI = resourceURINode.value;
if (!isTargetESM(resourceURI)) {
return;
}
// If this cannot be replaced with static import, do nothing.
tryReplacingWithStaticImport(jscodeshift, inputFile, path, resourceURINode);
}
function replaceLazyGetterCall(inputFile, jscodeshift, path) { function replaceLazyGetterCall(inputFile, jscodeshift, path) {
if (path.node.arguments.length !== 3) { if (path.node.arguments.length !== 3) {
warnForPath(inputFile, path, `lazy getter call should have 3 arguments`); warnForPath(inputFile, path, `lazy getter call should have 3 arguments`);
@ -366,6 +420,8 @@ function doTranslate(inputFile, jscodeshift, root) {
root.find(jscodeshift.CallExpression).forEach(path => { root.find(jscodeshift.CallExpression).forEach(path => {
if (isImportCall(path.node)) { if (isImportCall(path.node)) {
replaceImportCall(inputFile, jscodeshift, path); replaceImportCall(inputFile, jscodeshift, path);
} else if (isImportESModuleCall(path.node)) {
replaceImportESModuleCall(inputFile, jscodeshift, path);
} else if (isLazyGetterCall(path.node)) { } else if (isLazyGetterCall(path.node)) {
replaceLazyGetterCall(inputFile, jscodeshift, path); replaceLazyGetterCall(inputFile, jscodeshift, path);
} else if (isLazyGettersCall(path.node)) { } else if (isLazyGettersCall(path.node)) {

Просмотреть файл

@ -14,6 +14,20 @@ const _path = require("path");
const uri_map = JSON.parse( const uri_map = JSON.parse(
fs.readFileSync(_path.resolve(__dirname, "./map.json")) fs.readFileSync(_path.resolve(__dirname, "./map.json"))
); );
const esm_uri_map = generateESMURIMap(uri_map);
function generateESMURIMap(jsm_map) {
const esm_map = {};
for (let [uri, jsms] of Object.entries(jsm_map)) {
if (typeof jsms === "string") {
jsms = [jsms];
}
esm_map[esmify(uri)] = jsms.map(esmify);
}
return esm_map;
}
function esmify(path) { function esmify(path) {
return path.replace(/\.(jsm|js|jsm\.js)$/, ".sys.mjs"); return path.replace(/\.(jsm|js|jsm\.js)$/, ".sys.mjs");
@ -57,4 +71,12 @@ function isESMified(resourceURI, files) {
return isESMified_memo[resourceURI].result; return isESMified_memo[resourceURI].result;
} }
function getESMFiles(resourceURI) {
if (resourceURI in esm_uri_map) {
return esm_uri_map[resourceURI];
}
return [];
}
exports.isESMified = isESMified; exports.isESMified = isESMified;
exports.getESMFiles = getESMFiles;