gecko-dev/tools/esmify/utils.js

166 строки
4.1 KiB
JavaScript

/* 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 http://mozilla.org/MPL/2.0/. */
// Shared utility functions.
/* eslint-env node */
function warnForPath(inputFile, path, message) {
const loc = path.node.loc;
console.log(
`WARNING: ${inputFile}:${loc.start.line}:${loc.start.column} : ${message}`
);
}
// Get the previous statement of `path.node` in `Program`.
function getPrevStatement(path) {
const parent = path.parent;
if (parent.node.type !== "Program") {
return null;
}
const index = parent.node.body.findIndex(n => n == path.node);
if (index === -1) {
return null;
}
if (index === 0) {
return null;
}
return parent.node.body[index - 1];
}
// Get the next statement of `path.node` in `Program`.
function getNextStatement(path) {
const parent = path.parent;
if (parent.node.type !== "Program") {
return null;
}
const index = parent.node.body.findIndex(n => n == path.node);
if (index === -1) {
return null;
}
if (index + 1 == parent.node.body.length) {
return null;
}
return parent.node.body[index + 1];
}
function isIdentifier(node, name) {
if (node.type !== "Identifier") {
return false;
}
if (node.name !== name) {
return false;
}
return true;
}
function isString(node) {
return node.type === "Literal" && typeof node.value === "string";
}
const jsmExtPattern = /\.(jsm|js|jsm\.js)$/;
function esmifyExtension(path) {
return path.replace(jsmExtPattern, ".sys.mjs");
}
// Given possible member expression, return the list of Identifier nodes in
// the source order.
//
// Returns an empty array if:
// * not a simple MemberExpression tree with Identifiers
// * there's computed property
function memberExpressionsToIdentifiers(memberExpr) {
let ids = [];
function f(node) {
if (node.type !== "MemberExpression" || node.computed) {
return false;
}
if (node.object.type === "Identifier") {
ids.push(node.object);
ids.push(node.property);
return true;
}
if (!f(node.object)) {
return false;
}
ids.push(node.property);
return true;
}
if (!f(memberExpr)) {
return [];
}
return ids;
}
// Returns true if the node is a simple MemberExpression tree with Identifiers
// matches expectedIDs.
function isMemberExpressionWithIdentifiers(node, expectedIDs) {
const actualIDs = memberExpressionsToIdentifiers(node);
if (actualIDs.length !== expectedIDs.length) {
return false;
}
for (let i = 0; i < expectedIDs.length; i++) {
if (actualIDs[i].name !== expectedIDs[i]) {
return false;
}
}
return true;
}
// Rewrite the Identifiers of MemberExpression tree to toIDs.
// `node` must be a simple MemberExpression tree with Identifiers, and
// the length of Identifiers should match.
function rewriteMemberExpressionWithIdentifiers(node, toIDs) {
const actualIDs = memberExpressionsToIdentifiers(node);
for (let i = 0; i < toIDs.length; i++) {
actualIDs[i].name = toIDs[i];
}
}
// Create a simple MemberExpression tree with given Identifiers.
function createMemberExpressionWithIdentifiers(jscodeshift, ids) {
if (ids.length < 2) {
throw new Error("Unexpected length of ids for member expression");
}
if (ids.length > 2) {
return jscodeshift.memberExpression(
createMemberExpressionWithIdentifiers(jscodeshift, ids.slice(0, -1)),
jscodeshift.identifier(ids[ids.length - 1])
);
}
return jscodeshift.memberExpression(
jscodeshift.identifier(ids[0]),
jscodeshift.identifier(ids[1])
);
}
exports.warnForPath = warnForPath;
exports.getPrevStatement = getPrevStatement;
exports.getNextStatement = getNextStatement;
exports.isIdentifier = isIdentifier;
exports.isString = isString;
exports.jsmExtPattern = jsmExtPattern;
exports.esmifyExtension = esmifyExtension;
exports.isMemberExpressionWithIdentifiers = isMemberExpressionWithIdentifiers;
exports.rewriteMemberExpressionWithIdentifiers =
rewriteMemberExpressionWithIdentifiers;
exports.createMemberExpressionWithIdentifiers =
createMemberExpressionWithIdentifiers;