Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 25 additions & 1 deletion crates/oxc_mangler/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -424,8 +424,32 @@ fn is_keyword(s: &str) -> bool {
#[repr(C, align(64))]
struct Aligned64([u8; 64]);

/// The characters are in frequency order, so that the characters with higher frequency are used first.
///
/// This idea was inspired by nanoid. <https://github.com/ai/nanoid/blob/5.0.9/url-alphabet/index.js>
///
/// This list was generated by the following steps:
/// 1. Generate a source code with replacing all manglable variable names with `$` (assuming `$` is the least used character).
/// You can do this by passing the following `blank` function to the `generate_name` parameter of [Mangler::build_with_symbols_and_scopes_impl].
/// ```no_run
/// fn blank(_: usize) -> InlineString<12> {
/// let mut str = InlineString::new();
/// unsafe { str.push_unchecked(b"$"[0]); }
/// str
/// }
/// ```
/// 2. Run the following command in `target/minifier/default` to check generate the list:
/// ```shell
/// find . -type f -exec cat {} + | `# concat all files in that directory` \
/// tr -d '\n' | fold -w1 | `# separate each characters in to each line` \
/// grep -E '[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_0123456789]' | `# filter the character` \
/// sort | uniq -c | `# count each characters` \
/// sort -nr | awk '{print $2}' | tr -d '\n' `# format output`
/// ```
/// The result I got is `etnriaoscludfpmhg_10vy2436b8x579SCwTEDOkAjMNPFILRzBVHUWGKqJYXZQ`.
/// 3. Add `$` at the end and then move all numbers to the end of the list.
const BASE54_CHARS: Aligned64 =
Aligned64(*b"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_0123456789");
Aligned64(*b"etnriaoscludfpmhg_vybxSCwTEDOkAjMNPFILRzBVHUWGKqJYXZQ$1024368579");

/// Get the shortest mangled name for a given n.
/// Code adapted from [terser](https://github.com/terser/terser/blob/8b966d687395ab493d2c6286cc9dd38650324c11/lib/scope.js#L1041-L1051)
Expand Down
136 changes: 68 additions & 68 deletions crates/oxc_minifier/tests/mangler/snapshots/mangler.snap
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,23 @@
source: crates/oxc_minifier/tests/mangler/mod.rs
---
function foo(a) {a}
function foo(a) {
a;
function foo(e) {
e;
}

function foo(a) { let _ = { x } }
function foo(a) {
let b = { x };
function foo(e) {
let t = { x };
}

function foo(a) { let { x } = y }
function foo(a) {
let { x: b } = y;
function foo(e) {
let { x: t } = y;
}

var x; function foo(a) { ({ x } = y) }
var x;
function foo(b) {
function foo(t) {
({x} = y);
}

Expand All @@ -32,189 +32,189 @@ function _(exports) {
}

function foo(foo_a, foo_b, foo_c) {}; function bar(bar_a, bar_b, bar_c) {}
function foo(a, b, c) {}
function foo(e, t, n) {}
;
function bar(a, b, c) {}
function bar(e, t, n) {}

function _() { function foo() { var x; foo; } }
function _() {
function a() {
var b;
a;
function e() {
var t;
e;
}
}

function _() { var x; function foo() { var y; function bar() { x } } }
function _() {
var a;
function b() {
var b;
function c() {
a;
var e;
function t() {
var t;
function n() {
e;
}
}
}

function _() { function x(a) {} }
function _() {
function a(a) {}
function e(e) {}
}

function _() { function x(a) { x } }
function _() {
function a(b) {
a;
function e(t) {
e;
}
}

function _() { var x; { var y }}
function _() {
var a;
var e;
{
var b;
var t;
}
}

function _() { var x; { let y }}
function _() {
var a;
var e;
{
let a;
let e;
}
}

function _() { let x; { let y }}
function _() {
let a;
let e;
{
let a;
let e;
}
}

function _() { var x; { const y }}
function _() {
var a;
var e;
{
const a;
const e;
}
}

function _() { let x; { const y }}
function _() {
let a;
let e;
{
const a;
const e;
}
}

function _() { var x; { class Y{} }}
function _() {
var a;
var e;
{
class a {}
class e {}
}
}

function _() { let x; { class Y{} }}
function _() {
let a;
let e;
{
class a {}
class e {}
}
}

function _() { var x; try { throw 0 } catch (e) { e } }
function _() {
var a;
var e;
try {
throw 0;
} catch (a) {
a;
} catch (e) {
e;
}
}

function _() { var x; try { throw 0 } catch (e) { var e } }
function _() {
var a;
var e;
try {
throw 0;
} catch (b) {
var b;
} catch (t) {
var t;
}
}

function _() { var x; try { throw 0 } catch { var e } }
function _() {
var a;
var e;
try {
throw 0;
} catch {
var b;
var t;
}
}

function _() { var x; var y; }
function _() {
var a;
var b;
var e;
var t;
}

function _() { var x; let y; }
function _() {
var a;
let b;
var e;
let t;
}

function _() { { var x; var y; } }
function _() {
{
var a;
var b;
var e;
var t;
}
}

function _() { { var x; let y; } }
function _() {
{
var a;
let b;
var e;
let t;
}
}

function _() { let a; { let b; { let c; { let d; var x; } } } }
function _() {
let a;
let e;
{
let a;
let e;
{
let a;
let e;
{
let a;
var b;
let e;
var t;
}
}
}
}

function _() { let a; { let b; { let c; { console.log(a); let d; var x; } } } }
function _() {
let a;
let e;
{
let c;
let n;
{
let c;
let n;
{
console.log(a);
let c;
var b;
console.log(e);
let n;
var t;
}
}
}
}

function foo(a) {a}
function a(a) {
a;
function e(e) {
e;
}

export function foo() {}; foo()
Expand All @@ -223,15 +223,15 @@ export function foo() {}
foo();

export default function foo() {}; foo()
export default function a() {}
export default function e() {}
;
a();
e();

export const foo = 1; foo
export const foo = 1;
foo;

const foo = 1; foo; export { foo }
const a = 1;
a;
export { a as foo };
const e = 1;
e;
export { e as foo };
2 changes: 1 addition & 1 deletion napi/minify/test/minify.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ describe('simple', () => {
it('matches output', () => {
const ret = minify('test.js', code, { sourcemap: true });
expect(ret).toStrictEqual({
'code': 'function foo(){var a;a(void 0)}foo();',
'code': 'function foo(){var e;e(void 0)}foo();',
'map': {
'mappings': 'AAAA,SAAS,KAAM,CAAE,IAAIA,EAAK,SAAc,AAAE,CAAC,KAAK',
'names': [
Expand Down
20 changes: 12 additions & 8 deletions napi/minify/test/terser.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,16 @@ import { run_code } from './sandbox';

function run(input: string, expected: string[], prepend_code?: string) {
const consoleMock = vi.spyOn(console, 'log').mockImplementation(() => undefined);
const minified = minify('test.mjs', input).code;
expect(minified).not.toBeFalsy();
// Use `consoleMock` instead of the returned output.
const _ = run_code(minified, prepend_code);
const calls = consoleMock.mock.calls.map((args) => args.map(convert).join(' '));
expect(calls).toStrictEqual(expected);
consoleMock.mockReset();
try {
const minified = minify('test.mjs', input).code;
expect(minified).not.toBeFalsy();
// Use `consoleMock` instead of the returned output.
const _ = run_code(minified, prepend_code);
const calls = consoleMock.mock.calls.map((args) => args.map(convert).join(' '));
expect(calls).toStrictEqual(expected);
} finally {
consoleMock.mockReset();
}
}

function convert(arg: any) {
Expand Down Expand Up @@ -4451,7 +4454,8 @@ test('issue_1922_1', () => {
run(code, expected);
});

test('issue_1922_2', () => {
// TODO: mangler does not support eval yet
test('issue_1922_2', { todo: true }, () => {
const code = 'console.log(function(){var a;eval("a = 1");return a}(1));';
const expected = ['1'];
run(code, expected);
Expand Down
Loading
Loading