diff --git a/packages/webcrack/src/unminify/test/number-expressions.test.ts b/packages/webcrack/src/unminify/test/number-expressions.test.ts index 59724021..6b5a20c1 100644 --- a/packages/webcrack/src/unminify/test/number-expressions.test.ts +++ b/packages/webcrack/src/unminify/test/number-expressions.test.ts @@ -22,5 +22,5 @@ test('keep divisions if it results in a decimal number', () => '(-0x152f + 0x1281 * -0x1 + -0x18 * -0x1d1) / (0x83 * -0x1a + -0x19ea + 0x5f * 0x6a)', ).toMatchInlineSnapshot('1000 / 30;')); -test('ignore string results', () => - expectJS('0x1021e + "test"').toMatchInlineSnapshot('0x1021e + "test";')); +test('string and number concatenation', () => + expectJS('0x1021e + "test"').toMatchInlineSnapshot('"66078test";')); diff --git a/packages/webcrack/src/unminify/transforms/for-to-while.ts b/packages/webcrack/src/unminify/transforms/for-to-while.ts index b990748a..e20385fa 100644 --- a/packages/webcrack/src/unminify/transforms/for-to-while.ts +++ b/packages/webcrack/src/unminify/transforms/for-to-while.ts @@ -11,9 +11,7 @@ export default { const { test, body, init, update } = path.node; if (init || update) return; path.replaceWith( - test - ? t.whileStatement(test, body) - : t.whileStatement(t.booleanLiteral(true), body), + t.whileStatement(test ?? t.booleanLiteral(true), body), ); this.changes++; }, diff --git a/packages/webcrack/src/unminify/transforms/logical-to-if.ts b/packages/webcrack/src/unminify/transforms/logical-to-if.ts index 8159220b..8ca40a05 100644 --- a/packages/webcrack/src/unminify/transforms/logical-to-if.ts +++ b/packages/webcrack/src/unminify/transforms/logical-to-if.ts @@ -1,15 +1,11 @@ import { statement } from '@babel/template'; -import type * as t from '@babel/types'; -import * as m from '@codemod/matchers'; +import * as t from '@babel/types'; import type { Transform } from '../../ast-utils'; export default { name: 'logical-to-if', tags: ['safe'], visitor: () => { - const andMatcher = m.expressionStatement(m.logicalExpression('&&')); - const orMatcher = m.expressionStatement(m.logicalExpression('||')); - const buildIf = statement`if (TEST) { BODY; }`; const buildIfNot = statement`if (!TEST) { BODY; }`; @@ -17,7 +13,8 @@ export default { ExpressionStatement: { exit(path) { const expression = path.node.expression as t.LogicalExpression; - if (andMatcher.match(path.node)) { + if (!t.isLogicalExpression(expression)) return; + if (expression.operator === '&&') { path.replaceWith( buildIf({ TEST: expression.left, @@ -25,7 +22,7 @@ export default { }), ); this.changes++; - } else if (orMatcher.match(path.node)) { + } else if (expression.operator === '||') { path.replaceWith( buildIfNot({ TEST: expression.left, diff --git a/packages/webcrack/src/unminify/transforms/merge-strings.ts b/packages/webcrack/src/unminify/transforms/merge-strings.ts index c1a41f82..8fb7f78e 100644 --- a/packages/webcrack/src/unminify/transforms/merge-strings.ts +++ b/packages/webcrack/src/unminify/transforms/merge-strings.ts @@ -1,42 +1,31 @@ -import * as t from '@babel/types'; import * as m from '@codemod/matchers'; import type { Transform } from '../../ast-utils'; +// "a" + "b" -> "ab" +// (a + "b") + "c" -> a + "bc" +// left ^ ^ right (path) export default { name: 'merge-strings', tags: ['safe'], visitor() { - const left = m.capture(m.stringLiteral(m.anyString())); - const right = m.capture(m.stringLiteral(m.anyString())); + const left = m.capture(m.stringLiteral()); + const right = m.capture(m.stringLiteral()); - const matcher = m.binaryExpression('+', left, right); - const nestedMatcher = m.binaryExpression( + const matcher = m.binaryExpression( '+', - m.binaryExpression('+', m.anything(), left), + m.or(left, m.binaryExpression('+', m.anything(), left)), right, ); return { BinaryExpression: { exit(path) { - if (matcher.match(path.node)) { - // "a" + "b" -> "ab" - path.replaceWith( - t.stringLiteral(left.current!.value + right.current!.value), - ); - this.changes++; - } - }, - }, - StringLiteral: { - exit(path) { - if (nestedMatcher.match(path.parent)) { - // (a + "b") + "c" -> a + "bc" - // left ^ ^ right (path) - left.current!.value += right.current!.value; - path.remove(); - this.changes++; - } + if (!matcher.match(path.node)) return; + left.current!.value += right.current!.value; + right.current!.value = ''; // Otherwise it concatenates multiple times for some reason + path.replaceWith(path.node.left); + path.skip(); + this.changes++; }, }, }; diff --git a/packages/webcrack/src/unminify/transforms/number-expressions.ts b/packages/webcrack/src/unminify/transforms/number-expressions.ts index 4aa352ef..d87be5ea 100644 --- a/packages/webcrack/src/unminify/transforms/number-expressions.ts +++ b/packages/webcrack/src/unminify/transforms/number-expressions.ts @@ -8,51 +8,35 @@ export default { visitor: () => ({ 'BinaryExpression|UnaryExpression': { exit(path) { - if (matcher.match(path.node)) { - const evaluated = path.evaluate(); - if (evaluated.confident) { - // Heuristic: Simplifying a division that results in a non-integer probably doesn't increase readability - if ( - path.node.type === 'BinaryExpression' && - path.node.operator === '/' && - !Number.isInteger(evaluated.value) - ) { - return; - } - - path.replaceWith(t.valueToNode(evaluated.value)); - path.skip(); - this.changes++; - } + if (!matcher.match(path.node)) return; + const evaluated = path.evaluate(); + if ( + t.isBinaryExpression(path.node, { operator: '/' }) && + !Number.isInteger(evaluated.value) + ) { + return; } + path.replaceWith(t.valueToNode(evaluated.value)); + path.skip(); + this.changes++; }, }, }), } satisfies Transform; -const matcher: m.Matcher = m.or( - m.binaryExpression( - m.or('+', '-', '*', '/'), - m.matcher((node) => matcher.match(node)), - m.matcher((node) => matcher.match(node)), - ), +const matcher = m.or( + m.unaryExpression('-', m.or(m.stringLiteral(), m.numericLiteral())), m.binaryExpression( - '-', + m.or('+', '-', '/', '%', '*', '**', '&', '|', '>>', '>>>', '<<', '^'), m.or( m.stringLiteral(), - m.matcher((node) => matcher.match(node)), + m.numericLiteral(), + m.unaryExpression('-', m.numericLiteral()), ), m.or( m.stringLiteral(), - m.matcher((node) => matcher.match(node)), - ), - ), - m.unaryExpression( - '-', - m.or( - m.stringLiteral(), - m.matcher((node) => matcher.match(node)), + m.numericLiteral(), + m.unaryExpression('-', m.numericLiteral()), ), ), - m.numericLiteral(), );