/* 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;