-
Notifications
You must be signed in to change notification settings - Fork 142
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
126 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
37 changes: 37 additions & 0 deletions
37
packages/webcrack/src/unminify/test/invert-boolean-logic.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import { test } from 'vitest'; | ||
import { testTransform } from '../../../test'; | ||
import invertBooleanLogic from '../transforms/invert-boolean-logic'; | ||
|
||
const expectJS = testTransform(invertBooleanLogic); | ||
|
||
test('loose equal', () => | ||
expectJS('!(a == b);').toMatchInlineSnapshot(`a != b;`)); | ||
|
||
test('strict equal', () => | ||
expectJS('!(a === b);').toMatchInlineSnapshot(`a !== b;`)); | ||
|
||
test('not equal', () => | ||
expectJS('!(a != b);').toMatchInlineSnapshot(`a == b;`)); | ||
|
||
test('not strict equal', () => | ||
expectJS('!(a !== b);').toMatchInlineSnapshot(`a === b;`)); | ||
|
||
test('greater than', () => | ||
expectJS('!(a > b);').toMatchInlineSnapshot(`a <= b;`)); | ||
|
||
test('less than', () => expectJS('!(a < b);').toMatchInlineSnapshot(`a >= b;`)); | ||
|
||
test('greater than or equal', () => | ||
expectJS('!(a >= b);').toMatchInlineSnapshot(`a < b;`)); | ||
|
||
test('less than or equal', () => | ||
expectJS('!(a <= b);').toMatchInlineSnapshot(`a > b;`)); | ||
|
||
test('logical or', () => | ||
expectJS('!(a || b || c);').toMatchInlineSnapshot(`!a && !b && !c;`)); | ||
|
||
test('logical and', () => | ||
expectJS('!(a && b && c);').toMatchInlineSnapshot(`!a || !b || !c;`)); | ||
|
||
test('mixed logical', () => | ||
expectJS('!((a ?? b) || c);').toMatchInlineSnapshot(`!(a ?? b) && !c;`)); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
71 changes: 71 additions & 0 deletions
71
packages/webcrack/src/unminify/transforms/invert-boolean-logic.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
import * as t from '@babel/types'; | ||
import * as m from '@codemod/matchers'; | ||
import { Transform } from '../../ast-utils'; | ||
|
||
const INVERTED_BINARY_OPERATORS = { | ||
'==': '!=', | ||
'===': '!==', | ||
'!=': '==', | ||
'!==': '===', | ||
'>': '<=', | ||
'<': '>=', | ||
'>=': '<', | ||
'<=': '>', | ||
} as const; | ||
|
||
const INVERTED_LOGICAL_OPERATORS = { | ||
'||': '&&', | ||
'&&': '||', | ||
} as const; | ||
|
||
export default { | ||
name: 'invert-boolean-logic', | ||
tags: ['safe'], | ||
visitor: () => { | ||
const logicalExpression = m.logicalExpression( | ||
m.or(...Object.values(INVERTED_LOGICAL_OPERATORS)), | ||
); | ||
const logicalMatcher = m.unaryExpression('!', logicalExpression); | ||
|
||
const binaryExpression = m.capture( | ||
m.binaryExpression(m.or(...Object.values(INVERTED_BINARY_OPERATORS))), | ||
); | ||
const binaryMatcher = m.unaryExpression('!', binaryExpression); | ||
|
||
return { | ||
UnaryExpression: { | ||
exit(path) { | ||
const { argument } = path.node; | ||
|
||
if (binaryMatcher.match(path.node)) { | ||
binaryExpression.current!.operator = | ||
INVERTED_BINARY_OPERATORS[ | ||
binaryExpression.current! | ||
.operator as keyof typeof INVERTED_BINARY_OPERATORS | ||
]; | ||
|
||
path.replaceWith(binaryExpression.current!); | ||
this.changes++; | ||
} else if (logicalMatcher.match(path.node)) { | ||
let current = argument; | ||
while (logicalExpression.match(current)) { | ||
current.operator = | ||
INVERTED_LOGICAL_OPERATORS[ | ||
current.operator as keyof typeof INVERTED_LOGICAL_OPERATORS | ||
]; | ||
|
||
current.right = t.unaryExpression('!', current.right); | ||
if (!logicalExpression.match(current.left)) { | ||
current.left = t.unaryExpression('!', current.left); | ||
} | ||
current = current.left; | ||
} | ||
|
||
path.replaceWith(argument); | ||
this.changes++; | ||
} | ||
}, | ||
}, | ||
}; | ||
}, | ||
} satisfies Transform; |