From 16f575fdace65327b630dd84d235080e7a18a234 Mon Sep 17 00:00:00 2001 From: j4k0xb <55899582+j4k0xb@users.noreply.github.com> Date: Sat, 17 Feb 2024 17:52:04 +0100 Subject: [PATCH] fix: conflict detection of unreferenced binding and assignments --- packages/webcrack/src/ast-utils/rename.ts | 9 ++++++--- .../webcrack/src/ast-utils/test/rename.test.ts | 14 ++++++++++++++ .../unminify/test/rename-destructuring.test.ts | 18 ++++++++++-------- 3 files changed, 30 insertions(+), 11 deletions(-) diff --git a/packages/webcrack/src/ast-utils/rename.ts b/packages/webcrack/src/ast-utils/rename.ts index 0654ffdb..a5493f6a 100644 --- a/packages/webcrack/src/ast-utils/rename.ts +++ b/packages/webcrack/src/ast-utils/rename.ts @@ -5,6 +5,8 @@ import * as m from '@codemod/matchers'; import { codePreview } from './generator'; export function renameFast(binding: Binding, newName: string): void { + if (binding.scope.hasBinding(newName)) binding.scope.rename(newName); + binding.referencePaths.forEach((ref) => { if (!ref.isIdentifier()) { throw new Error( @@ -62,9 +64,10 @@ export function renameFast(binding: Binding, newName: string): void { */ export function renameCarefully(binding: Binding, newName: string): void { const hasConflicts = () => - binding.referencePaths.some((referencePath) => - referencePath.scope.hasBinding(newName), - ); + binding.scope.hasBinding(newName) || + binding.referencePaths.some((ref) => ref.scope.hasBinding(newName)) || + binding.constantViolations.some((ref) => ref.scope.hasBinding(newName)); + if (!t.isValidIdentifier(newName) || hasConflicts()) { newName = binding.scope.generateUid(newName); } diff --git a/packages/webcrack/src/ast-utils/test/rename.test.ts b/packages/webcrack/src/ast-utils/test/rename.test.ts index f3521aec..9d8ffc59 100644 --- a/packages/webcrack/src/ast-utils/test/rename.test.ts +++ b/packages/webcrack/src/ast-utils/test/rename.test.ts @@ -20,6 +20,20 @@ describe('rename variable', () => { `); }); + test('conflict with existing binding 2', () => { + const ast = parse('let a = 1; let b = 2;'); + traverse(ast, { + Program(path) { + const binding = path.scope.getBinding('a')!; + renameFast(binding, 'b'); + }, + }); + expect(ast).toMatchInlineSnapshot(` + let b = 1; + let _b = 2; + `); + }); + test('duplicate function binding', () => { const ast = parse('var a; function a() {}'); traverse(ast, { diff --git a/packages/webcrack/src/unminify/test/rename-destructuring.test.ts b/packages/webcrack/src/unminify/test/rename-destructuring.test.ts index 64d83fea..96b5e5a4 100644 --- a/packages/webcrack/src/unminify/test/rename-destructuring.test.ts +++ b/packages/webcrack/src/unminify/test/rename-destructuring.test.ts @@ -24,30 +24,32 @@ test('rename object destructuring', () => test('rename object destructuring with conflict', () => expectJS(` const gql = 1; + const { + gql: t, + dispatchers: o, + listener: i + } = n; function foo({ gql: t, dispatchers: o, listener: i - }, { - gql: a, - dispatchers: b, - listener: c }) { - o.delete(t, i, a, b, c); + o.delete(t, i); } `).toMatchInlineSnapshot(` const gql = 1; - function foo({ + const { gql: _gql, dispatchers, listener - }, { + } = n; + function foo({ gql: _gql2, dispatchers: _dispatchers, listener: _listener }) { - dispatchers.delete(_gql, listener, _gql2, _dispatchers, _listener); + _dispatchers.delete(_gql2, _listener); } `));