summaryrefslogtreecommitdiffstats
path: root/tools/esmify/utils.js
diff options
context:
space:
mode:
Diffstat (limited to 'tools/esmify/utils.js')
-rw-r--r--tools/esmify/utils.js163
1 files changed, 163 insertions, 0 deletions
diff --git a/tools/esmify/utils.js b/tools/esmify/utils.js
new file mode 100644
index 0000000000..8ea25d782b
--- /dev/null
+++ b/tools/esmify/utils.js
@@ -0,0 +1,163 @@
+/* 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;