/
githubmirror
/
babel
Обзор
Документация
Войти
/
githubmirror
/
babel
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
scripts/babel-plugin-toggle-boolean-flag/plugin.ts
224 строки
7 KB
liuxingbaoyu
Enable `strictFunctionTypes` (#17946)
22 май 2026, 17:12
Не верифицирован
22 май 2026, 17:12
c6d71f3
Код
Авторство
О чём код?
import type { NodePath, PluginAPI, PluginObject, types as t, } from "@babel/core"; export default pluginToggleBooleanFlag; /** * If `value` is null, it will leave the conditions in code. It will remove * them in attributes by replacing them with <if true> || <if false> */ function pluginToggleBooleanFlag( { types: t, template, traverse }: PluginAPI, { name, value }: { name: string; value: boolean | null } ): PluginObject { if (typeof value !== "boolean" && value !== null) { throw new Error(`.value must be a boolean, or null`); } function parseExpression(source: string) { // eslint-disable-next-line regexp/no-useless-assertions return template.expression(source, { placeholderPattern: /(?!.)./ })({}); } function evaluate(test: t.Expression, value: boolean): any { const res = { replace: (replacement: t.Expression) => ({ replacement, value: null, unrelated: false, }), value: (value: boolean) => ({ replacement: null, value, unrelated: false, }), unrelated: () => ({ replacement: test, value: null, unrelated: true }), }; if (t.isIdentifier(test, { name }) || t.matchesPattern(test, name)) { return res.value(value); } if (t.isUnaryExpression(test, { operator: "!" })) { const arg = evaluate(test.argument, value); return arg.unrelated ? res.unrelated() : arg.replacement ? res.replace(t.unaryExpression("!", arg.replacement)) : res.value(!arg.value); } if (t.isLogicalExpression(test, { operator: "||" })) { const left = evaluate(test.left, value); const right = evaluate(test.right, value); 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(); return res.replace( t.logicalExpression("||", left.replacement, right.replacement) ); } if (t.isLogicalExpression(test, { operator: "&&" })) { const left = evaluate(test.left, value); const right = evaluate(test.right, value); 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: traverse.explode({ "IfStatement|ConditionalExpression"( path: NodePath<t.IfStatement | t.ConditionalExpression> ) { if (value === null) return; let test = path.get("test") as NodePath<t.Expression>; // yarn-plugin-conditions injects bool(process.env.BABEL_8_BREAKING) // tests, to properly cast the env variable to a boolean. if ( test.isCallExpression() && test.get("callee").isIdentifier({ name: "bool" }) && test.get("arguments").length === 1 ) { test = test.get("arguments")[0] as NodePath<t.Expression>; } const res = evaluate(test.node, value); if (res.unrelated) return; if (res.replacement) { path.get("test").replaceWith(res.replacement); } else { const replacementNode = res.value ? path.node.consequent : path.node.alternate; if (t.isBlockStatement(replacementNode)) { path.replaceWithMultiple(replacementNode.body); } else if (replacementNode) { path.replaceWith(replacementNode); } else { path.remove(); } } }, LogicalExpression(path) { if (value === null) return; const res = evaluate(path.node, value); if (res.unrelated) return; if (res.replacement) { path.replaceWith(res.replacement); } else { path.replaceWith(t.booleanLiteral(res.value)); } }, MemberExpression(path) { if (value === null) return; if (path.matchesPattern(name)) { throw path.buildCodeFrameError("This check could not be stripped."); } }, ReferencedIdentifier(path) { if (value === null) return; if (path.node.name === name) { throw path.buildCodeFrameError("This check could not be stripped."); } }, ImportDeclaration(path) { if (!path.node.attributes) return; const ifAttribute = path .get("attributes") .find(attr => (attr.node.key as t.Identifier).name === "if"); if (ifAttribute == null) { return; } const condition = parseExpression(ifAttribute.node.value.value); let res; res_block: if (value !== null) { res = evaluate(condition, value); } else { const ifTrue = evaluate(condition, true); if (ifTrue.unrelated || ifTrue.value === true) { res = ifTrue; break res_block; } const ifFalse = evaluate(condition, false); if (ifFalse.unrelated) throw new Error("Cannot be unrelated"); if (ifFalse.value === true) { res = ifFalse; break res_block; } if (ifTrue.value === false) { res = ifFalse; break res_block; } if (ifTrue.value === false) { res = ifTrue; break res_block; } if (!ifTrue.replacement && !ifFalse.replacement) { throw new Error("Expected two replacements"); } res = { replacement: t.logicalExpression( "||", ifTrue.replacement, ifFalse.replacement ), value: null, unrelated: false, }; } if (res.unrelated) return; if (res.replacement) { ifAttribute .get("value") .replaceWith( t.stringLiteral( ifAttribute.toString.call({ node: res.replacement }) ) ); } else if (res.value === true) { ifAttribute.remove(); if (path.node.attributes.length === 0) { path.node.attributes = null; } } else if (res.value === false) { path.remove(); } }, }), }; }