Skip to content

Commit

Permalink
Fully support || and && in pluginToggleBooleanFlag (#15961)
Browse files Browse the repository at this point in the history
* Fully support `||` and `&&` in `pluginToggleBooleanFlag`

* Cleanup babel-standalone/src/available-plugins.ts

* Cleanup `USE_ESM`
  • Loading branch information
nicolo-ribaudo committed Sep 14, 2023
1 parent 90ef9e8 commit 3ed28b2
Show file tree
Hide file tree
Showing 10 changed files with 217 additions and 201 deletions.
119 changes: 76 additions & 43 deletions babel.config.js
Expand Up @@ -241,15 +241,6 @@ module.exports = function (api) {
{ name: "IS_STANDALONE", value: env === "standalone" },
"flag-IS_STANDALONE",
],
[
pluginToggleBooleanFlag,
{
name: "USE_ESM_OR_STANDALONE",
value: outputType === "module" || env === "standalone",
},
"flag-USE_ESM_OR_STANDALONE",
],

[
pluginToggleBooleanFlag,
{
Expand Down Expand Up @@ -384,7 +375,7 @@ function importInteropTest(source) {

// env vars from the cli are always strings, so !!ENV_VAR returns true for "false"
function bool(value) {
return value && value !== "false" && value !== "0";
return Boolean(value) && value !== "false" && value !== "0";
}

// A minimum semver GTE implementation
Expand Down Expand Up @@ -507,24 +498,72 @@ function pluginPolyfillsOldNode({ template, types: t }) {
* @returns {import("@babel/core").PluginObj}
*/
function pluginToggleBooleanFlag({ types: t }, { name, value }) {
function check(test) {
let keepConsequent = value;
if (typeof value !== "boolean") throw new Error(`.value must be a boolean`);

function evaluate(test) {
const res = {
replace: replacement => ({ replacement, value: null, unrelated: false }),
value: value => ({ replacement: null, value, unrelated: false }),
unrelated: () => ({
replacement: test.node,
value: null,
unrelated: true,
}),
};

if (test.isIdentifier({ name }) || test.matchesPattern(name)) {
return res.value(value);
}

if (test.isUnaryExpression({ operator: "!" })) {
test = test.get("argument");
keepConsequent = !keepConsequent;
const arg = evaluate(test.get("argument"));
return arg.unrelated
? res.unrelated()
: arg.replacement
? res.replacement(t.unaryExpression("!", arg.replacement))
: res.value(!arg.value);
}
return {
test,
keepConsequent,
};

if (test.isLogicalExpression({ operator: "||" })) {
const left = evaluate(test.get("left"));
const right = evaluate(test.get("right"));

if (left.value === true || right.value === true) return res.value(true);
if (left.value === false && right.value === false) {
return res.value(false);
}
if (left.value === false) return res.replace(right.replacement);
if (right.value === false) return res.replace(left.replacement);
if (left.unrelated && right.unrelated) return res.unrelated();
console.log(left, right);
return res.replace(
t.logicalExpression("||", left.replacement, right.replacement)
);
}

if (test.isLogicalExpression({ operator: "&&" })) {
const left = evaluate(test.get("left"));
const right = evaluate(test.get("right"));

if (left.value === true && right.value === true) return res.value(true);
if (left.value === false || right.value === false) {
return res.value(false);
}
if (left.value === true) return res.replace(right.replacement);
if (right.value === true) return res.replace(left.replacement);
if (left.unrelated && right.unrelated) return res.unrelated();
return res.replace(
t.logicalExpression("&&", left.replacement, right.replacement)
);
}

return res.unrelated();
}

return {
visitor: {
"IfStatement|ConditionalExpression"(path) {
// eslint-disable-next-line prefer-const
let { test, keepConsequent } = check(path.get("test"));
let test = path.get("test");

// yarn-plugin-conditions injects bool(process.env.BABEL_8_BREAKING)
// tests, to properly cast the env variable to a boolean.
Expand All @@ -536,32 +575,26 @@ function pluginToggleBooleanFlag({ types: t }, { name, value }) {
test = test.get("arguments")[0];
}

if (!test.isIdentifier({ name }) && !test.matchesPattern(name)) return;
const res = evaluate(test);

path.replaceWith(
keepConsequent
? path.node.consequent
: path.node.alternate || t.emptyStatement()
);
if (res.unrelated) return;
if (res.replacement) {
path.get("test").replaceWith(res.replacement);
} else {
path.replaceWith(
res.value
? path.node.consequent
: path.node.alternate || t.emptyStatement()
);
}
},
LogicalExpression(path) {
const { test, keepConsequent } = check(path.get("left"));

if (!test.matchesPattern(name)) return;

switch (path.node.operator) {
case "&&":
path.replaceWith(
keepConsequent ? path.node.right : t.booleanLiteral(false)
);
break;
case "||":
path.replaceWith(
keepConsequent ? t.booleanLiteral(true) : path.node.right
);
break;
default:
throw path.buildCodeFrameError("This check could not be stripped.");
const res = evaluate(path.get("test"));
if (res.unrelated) return;
if (res.replacement) {
path.get("test").replaceWith(res.replacement);
} else {
path.replaceWith(t.booleanLiteral(res.value));
}
},
MemberExpression(path) {
Expand Down
50 changes: 21 additions & 29 deletions packages/babel-core/src/index.ts
@@ -1,11 +1,7 @@
if (!process.env.IS_PUBLISH) {
if (!USE_ESM) {
if (process.env.BABEL_8_BREAKING) {
throw new Error(
"BABEL_8_BREAKING is only supported in ESM. Please run `make use-esm`.",
);
}
}
if (!process.env.IS_PUBLISH && !USE_ESM && process.env.BABEL_8_BREAKING) {
throw new Error(
"BABEL_8_BREAKING is only supported in ESM. Please run `make use-esm`.",
);
}

export const version = PACKAGE_JSON.version;
Expand Down Expand Up @@ -83,29 +79,25 @@ export const DEFAULT_EXTENSIONS = Object.freeze([

import Module from "module";
import * as thisFile from "./index.ts";
if (USE_ESM) {
if (!IS_STANDALONE) {
// Pass this module to the CJS proxy, so that it can be synchronously accessed.
const cjsProxy = Module.createRequire(import.meta.url)("../cjs-proxy.cjs");
cjsProxy["__ initialize @babel/core cjs proxy __"] = thisFile;
}
if (USE_ESM && !IS_STANDALONE) {
// Pass this module to the CJS proxy, so that it can be synchronously accessed.
const cjsProxy = Module.createRequire(import.meta.url)("../cjs-proxy.cjs");
cjsProxy["__ initialize @babel/core cjs proxy __"] = thisFile;
}

if (!process.env.BABEL_8_BREAKING) {
if (!process.env.BABEL_8_BREAKING && !USE_ESM) {
// For easier backward-compatibility, provide an API like the one we exposed in Babel 6.
if (!USE_ESM) {
// eslint-disable-next-line no-restricted-globals
exports.OptionManager = class OptionManager {
init(opts: {}) {
return loadOptionsSync(opts);
}
};
// eslint-disable-next-line no-restricted-globals
exports.OptionManager = class OptionManager {
init(opts: {}) {
return loadOptionsSync(opts);
}
};

// eslint-disable-next-line no-restricted-globals
exports.Plugin = function Plugin(alias: string) {
throw new Error(
`The (${alias}) Babel 5 plugin is being run with an unsupported Babel version.`,
);
};
}
// eslint-disable-next-line no-restricted-globals
exports.Plugin = function Plugin(alias: string) {
throw new Error(
`The (${alias}) Babel 5 plugin is being run with an unsupported Babel version.`,
);
};
}
24 changes: 10 additions & 14 deletions packages/babel-helper-environment-visitor/src/index.ts
@@ -1,21 +1,17 @@
import type { NodePath, Visitor } from "@babel/traverse";
import type * as t from "@babel/types";

if (!process.env.BABEL_8_BREAKING) {
if (!USE_ESM) {
if (!IS_STANDALONE) {
// eslint-disable-next-line no-restricted-globals
exports.skipAllButComputedKey = function skipAllButComputedKey(
path: NodePath<t.Method | t.ClassProperty>,
) {
path.skip();
if (path.node.computed) {
// requeue the computed key
path.context.maybeQueue(path.get("key"));
}
};
if (!process.env.BABEL_8_BREAKING && !USE_ESM && !IS_STANDALONE) {
// eslint-disable-next-line no-restricted-globals
exports.skipAllButComputedKey = function skipAllButComputedKey(
path: NodePath<t.Method | t.ClassProperty>,
) {
path.skip();
if (path.node.computed) {
// requeue the computed key
path.context.maybeQueue(path.get("key"));
}
}
};
}

export function requeueComputedKeyAndDecorators(
Expand Down
24 changes: 10 additions & 14 deletions packages/babel-helper-module-transforms/src/dynamic-import.ts
Expand Up @@ -3,21 +3,17 @@

import { types as t, template } from "@babel/core";

if (!process.env.BABEL_8_BREAKING) {
if (!USE_ESM) {
if (!IS_STANDALONE) {
// eslint-disable-next-line no-restricted-globals
exports.getDynamicImportSource = function getDynamicImportSource(
node: t.CallExpression,
): t.StringLiteral | t.TemplateLiteral {
const [source] = node.arguments;
if (!process.env.BABEL_8_BREAKING && !USE_ESM && !IS_STANDALONE) {
// eslint-disable-next-line no-restricted-globals
exports.getDynamicImportSource = function getDynamicImportSource(
node: t.CallExpression,
): t.StringLiteral | t.TemplateLiteral {
const [source] = node.arguments;

return t.isStringLiteral(source) || t.isTemplateLiteral(source)
? source
: (template.expression.ast`\`\${${source}}\`` as t.TemplateLiteral);
};
}
}
return t.isStringLiteral(source) || t.isTemplateLiteral(source)
? source
: (template.expression.ast`\`\${${source}}\`` as t.TemplateLiteral);
};
}

export function buildDynamicImport(
Expand Down
14 changes: 5 additions & 9 deletions packages/babel-helper-module-transforms/src/index.ts
Expand Up @@ -37,15 +37,11 @@ const {

export { buildDynamicImport } from "./dynamic-import.ts";

if (!process.env.BABEL_8_BREAKING) {
if (!USE_ESM) {
if (!IS_STANDALONE) {
// eslint-disable-next-line no-restricted-globals
exports.getDynamicImportSource =
// eslint-disable-next-line no-restricted-globals, import/extensions
require("./dynamic-import").getDynamicImportSource;
}
}
if (!process.env.BABEL_8_BREAKING && !USE_ESM && !IS_STANDALONE) {
// eslint-disable-next-line no-restricted-globals
exports.getDynamicImportSource =
// eslint-disable-next-line no-restricted-globals, import/extensions
require("./dynamic-import").getDynamicImportSource;
}

export { default as getModuleName } from "./get-module-name.ts";
Expand Down
18 changes: 7 additions & 11 deletions packages/babel-helper-replace-supers/src/index.ts
Expand Up @@ -17,17 +17,13 @@ const {
thisExpression,
} = t;

if (!process.env.BABEL_8_BREAKING) {
if (!USE_ESM) {
if (!IS_STANDALONE) {
// eslint-disable-next-line no-restricted-globals
const ns = require("@babel/helper-environment-visitor");
// eslint-disable-next-line no-restricted-globals
exports.environmentVisitor = ns.default;
// eslint-disable-next-line no-restricted-globals
exports.skipAllButComputedKey = ns.skipAllButComputedKey;
}
}
if (!process.env.BABEL_8_BREAKING && !USE_ESM && !IS_STANDALONE) {
// eslint-disable-next-line no-restricted-globals
const ns = require("@babel/helper-environment-visitor");
// eslint-disable-next-line no-restricted-globals
exports.environmentVisitor = ns.default;
// eslint-disable-next-line no-restricted-globals
exports.skipAllButComputedKey = ns.skipAllButComputedKey;
}

type ThisRef =
Expand Down
8 changes: 3 additions & 5 deletions packages/babel-highlight/src/index.ts
Expand Up @@ -262,11 +262,9 @@ function getChalk(forceColor: boolean) {
}
return chalk;
}
if (!process.env.BABEL_8_BREAKING) {
if (!USE_ESM) {
// eslint-disable-next-line no-restricted-globals
exports.getChalk = (options: Options) => getChalk(options.forceColor);
}
if (!process.env.BABEL_8_BREAKING && !USE_ESM) {
// eslint-disable-next-line no-restricted-globals
exports.getChalk = (options: Options) => getChalk(options.forceColor);
}

/**
Expand Down

0 comments on commit 3ed28b2

Please sign in to comment.