UNPKG

golfy

Version:

An aggressive JavaScript minifier for code golf

216 lines (204 loc) 7.4 kB
// @ts-check import { generateShortUniqueName } from "./utils.js"; /** * @param {import('@babel/core')} babel * @returns {import('@babel/core').PluginObj} */ export default function golfyPlugin({ types: t }) { let shortUniqueNameGenerator; let funcRefCounter; return { name: 'golfy-plugin', pre: (_state) => { // Initialize the short unique name generator shortUniqueNameGenerator = generateShortUniqueName(); funcRefCounter = new Map(); }, visitor: { CallExpression(path) { // Replace read stdio with numeric fds if ( path.node.callee.type === "MemberExpression" && path.node.callee.property.type === "Identifier" ) { if (path.node.callee.property.name === "readFileSync" || path.node.callee.property.name === "readFile" ) { if (path.node.arguments[0].type === "StringLiteral") { switch (path.node.arguments[0].value) { case '/dev/stdin': path.node.arguments[0] = t.numericLiteral(0); break; case '/dev/stdout': path.node.arguments[0] = t.numericLiteral(1); break; case '/dev/stderr': path.node.arguments[0] = t.numericLiteral(2); break; default: break; } path.skip(); return; } } if (path.node.callee.property.name === "toString") { if (path.node.arguments.length === 0) { path.replaceWith( t.templateLiteral( [ t.templateElement({ raw: '', cooked: '' }), t.templateElement({ raw: '', cooked: '' }) ], [t.cloneNode(path.node.callee.object)] ) ); path.skip(); return; } } if ( path.node.callee.property.name === "join" || path.node.callee.property.name === "split" ) { if (path.node.arguments.length === 1 && path.node.arguments[0].type === "StringLiteral") { path.replaceWith( t.taggedTemplateExpression( t.memberExpression( path.node.callee.object, t.identifier(path.node.callee.property.name) ), t.templateLiteral( [ t.templateElement({ raw: path.node.arguments[0].value, cooked: path.node.arguments[0].value }) ], [] ) ) ); path.skip(); return; } } } // inlining Object.entries(path.scope.bindings).forEach(([_name, binding]) => { const declarator = binding.path.find((p) => p.isVariableDeclarator()); const count = binding.references; if (count === 1) { if ( declarator && declarator.node.type === "VariableDeclarator" && declarator.node.init ) { binding.referencePaths[0].replaceWith(declarator.node.init); declarator.remove(); path.skip(); } } }); // TODO: assign function to variable and call const functionName = path.getSource().split('(')[0].trim(); if (funcRefCounter.has(functionName)) { funcRefCounter.set(functionName, funcRefCounter.get(functionName) + 1); } else { funcRefCounter.set(functionName, 1); } // console.log(`Function ${functionName} has been referenced ${funcRefCounter.get(functionName)} times`); /* if (funcRefCounter.get(functionName) > 1) { const newName = shortUniqueNameGenerator.next().value; if (newName === undefined) { throw new Error("No more unique names available"); } if (functionName.includes('.')) { // MemberExpression const [objectName, methodName] = functionName.split('.'); const binding = path.scope.getBinding(methodName); if (binding) { binding.path.replaceWith( t.memberExpression( t.identifier(newName), t.identifier(methodName) ) ); } } } */ }, VariableDeclarator(path) { if (path.node.id.type === "Identifier") { const binding = path.scope.getBinding(path.node.id.name); if (binding) { // if (binding.references + binding.constantViolations.length === 0) { // path.remove(); // path.skip(); // return; // } if (path.parent.type === "VariableDeclaration") { if ( path.node.init && path.parent.kind === 'const' && binding.references === 1 ) { switch (binding.referencePaths[0].parent.type) { case 'MemberExpression': binding.referencePaths[0].parent.object = path.node.init; path.remove(); path.skip(); return; } } if ( path.parent.kind !== 'const' && path.node.init === null && binding.constantViolations.length === 1 && binding.constantViolations[0].node.type === "AssignmentExpression" && binding.constantViolations[0].node.operator === "=" ) { if (binding.references === 1) { binding.referencePaths[0].replaceWith( binding.constantViolations[0].node.right ); binding.constantViolations[0].remove(); path.skip(); return; } } } if (Object.keys(path.scope.bindings).length > 0) { // Replace with short unique names let newName; do { newName = shortUniqueNameGenerator.next().value; if (newName === undefined) { throw new Error("No more unique names available"); } } while (path.scope.hasBinding(newName)); path.scope.rename(path.node.id.name, newName); } if (path.node.init && binding.references + binding.constantViolations.length > 1) { path.parentPath.replaceWith( t.assignmentExpression( '=', t.cloneNode(path.node.id), t.cloneNode(path.node.init) ) ); } } } }, WhileStatement(path) { if (path.node.test.type === "BooleanLiteral" && path.node.test.value === true) { path.replaceWith(t.forStatement(null, null, null, path.node.body)); path.skip(); } }, }, }; };