From 73d6a4a3cfac446ad9e2f1c5e282d82c0e3b2b4e Mon Sep 17 00:00:00 2001 From: 7086cmd <54303040+7086cmd@users.noreply.github.com> Date: Thu, 10 Oct 2024 10:20:55 +0000 Subject: [PATCH] test(minifier): port all replace_known_methods tests. (#6418) --- .../peephole_replace_known_methods.rs | 653 ++++++++++++++++++ 1 file changed, 653 insertions(+) diff --git a/crates/oxc_minifier/src/ast_passes/peephole_replace_known_methods.rs b/crates/oxc_minifier/src/ast_passes/peephole_replace_known_methods.rs index ee53e9484a07f..ec095261ed67a 100644 --- a/crates/oxc_minifier/src/ast_passes/peephole_replace_known_methods.rs +++ b/crates/oxc_minifier/src/ast_passes/peephole_replace_known_methods.rs @@ -92,4 +92,657 @@ mod test { fold_same("x = `Hello ${name}`.indexOf('a')"); fold_same("x = tag `Hello ${name}`.indexOf('a')"); } + + #[test] + #[ignore] + fn test_string_join_add_sparse() { + fold("x = [,,'a'].join(',')", "x = ',,a'"); + } + + #[test] + #[ignore] + fn test_no_string_join() { + fold_same("x = [].join(',',2)"); + fold_same("x = [].join(f)"); + } + + #[test] + #[ignore] + fn test_string_join_add() { + fold("x = ['a', 'b', 'c'].join('')", "x = \"abc\""); + fold("x = [].join(',')", "x = \"\""); + fold("x = ['a'].join(',')", "x = \"a\""); + fold("x = ['a', 'b', 'c'].join(',')", "x = \"a,b,c\""); + fold("x = ['a', foo, 'b', 'c'].join(',')", "x = [\"a\",foo,\"b,c\"].join()"); + fold("x = [foo, 'a', 'b', 'c'].join(',')", "x = [foo,\"a,b,c\"].join()"); + fold("x = ['a', 'b', 'c', foo].join(',')", "x = [\"a,b,c\",foo].join()"); + + // Works with numbers + fold("x = ['a=', 5].join('')", "x = \"a=5\""); + fold("x = ['a', '5'].join(7)", "x = \"a75\""); + + // Works on boolean + fold("x = ['a=', false].join('')", "x = \"a=false\""); + fold("x = ['a', '5'].join(true)", "x = \"atrue5\""); + fold("x = ['a', '5'].join(false)", "x = \"afalse5\""); + + // Only optimize if it's a size win. + fold( + "x = ['a', '5', 'c'].join('a very very very long chain')", + "x = [\"a\",\"5\",\"c\"].join(\"a very very very long chain\")", + ); + + // Template strings + fold("x = [`a`, `b`, `c`].join(``)", "x = 'abc'"); + fold("x = [`a`, `b`, `c`].join('')", "x = 'abc'"); + + // TODO(user): Its possible to fold this better. + fold_same("x = ['', foo].join('-')"); + fold_same("x = ['', foo, ''].join()"); + + fold( + "x = ['', '', foo, ''].join(',')", // + "x = [ ',' , foo, ''].join()", + ); + fold( + "x = ['', '', foo, '', ''].join(',')", // + "x = [ ',', foo, ','].join()", + ); + + fold( + "x = ['', '', foo, '', '', bar].join(',')", // + "x = [ ',', foo, ',', bar].join()", + ); + + fold( + "x = [1,2,3].join('abcdef')", // + "x = '1abcdef2abcdef3'", + ); + + fold("x = [1,2].join()", "x = '1,2'"); + fold("x = [null,undefined,''].join(',')", "x = ',,'"); + fold("x = [null,undefined,0].join(',')", "x = ',,0'"); + // This can be folded but we don't currently. + fold_same("x = [[1,2],[3,4]].join()"); // would like: "x = '1,2,3,4'" + } + + #[test] + #[ignore] + fn test_string_join_add_b1992789() { + fold("x = ['a'].join('')", "x = \"a\""); + fold_same("x = [foo()].join('')"); + fold_same("[foo()].join('')"); + fold("[null].join('')", "''"); + } + + #[test] + #[ignore] + fn test_fold_string_substr() { + fold("x = 'abcde'.substr(0,2)", "x = 'ab'"); + fold("x = 'abcde'.substr(1,2)", "x = 'bc'"); + fold("x = 'abcde'.substr(2)", "x = 'cde'"); + + // we should be leaving negative indexes alone for now + fold_same("x = 'abcde'.substr(-1)"); + fold_same("x = 'abcde'.substr(1, -2)"); + fold_same("x = 'abcde'.substr(1, 2, 3)"); + fold_same("x = 'a'.substr(0, 2)"); + + // Template strings + fold_same("x = `abcdef`.substr(0,2)"); + fold_same("x = `abc ${xyz} def`.substr(0,2)"); + } + + #[test] + #[ignore] + fn test_fold_string_replace() { + fold("'c'.replace('c','x')", "'x'"); + fold("'ac'.replace('c','x')", "'ax'"); + fold("'ca'.replace('c','x')", "'xa'"); + fold("'ac'.replace('c','xxx')", "'axxx'"); + fold("'ca'.replace('c','xxx')", "'xxxa'"); + + // only one instance replaced + fold("'acaca'.replace('c','x')", "'axaca'"); + fold("'ab'.replace('','x')", "'xab'"); + + fold_same("'acaca'.replace(/c/,'x')"); // this will affect the global RegExp props + fold_same("'acaca'.replace(/c/g,'x')"); // this will affect the global RegExp props + + // not a literal + fold_same("x.replace('x','c')"); + + fold_same("'Xyz'.replace('Xyz', '$$')"); // would fold to '$' + fold_same("'PreXyzPost'.replace('Xyz', '$&')"); // would fold to 'PreXyzPost' + fold_same("'PreXyzPost'.replace('Xyz', '$`')"); // would fold to 'PrePrePost' + fold_same("'PreXyzPost'.replace('Xyz', '$\\'')"); // would fold to 'PrePostPost' + fold_same("'PreXyzPostXyz'.replace('Xyz', '$\\'')"); // would fold to 'PrePostXyzPostXyz' + fold_same("'123'.replace('2', '$`')"); // would fold to '113' + } + + #[test] + #[ignore] + fn test_fold_string_replace_all() { + fold("x = 'abcde'.replaceAll('bcd','c')", "x = 'ace'"); + fold("x = 'abcde'.replaceAll('c','xxx')", "x = 'abxxxde'"); + fold("x = 'abcde'.replaceAll('xxx','c')", "x = 'abcde'"); + fold("'ab'.replaceAll('','x')", "'xaxbx'"); + + fold("x = 'c_c_c'.replaceAll('c','x')", "x = 'x_x_x'"); + + fold_same("x = 'acaca'.replaceAll(/c/,'x')"); // this should throw + fold_same("x = 'acaca'.replaceAll(/c/g,'x')"); // this will affect the global RegExp props + + // not a literal + fold_same("x.replaceAll('x','c')"); + + fold_same("'Xyz'.replaceAll('Xyz', '$$')"); // would fold to '$' + fold_same("'PreXyzPost'.replaceAll('Xyz', '$&')"); // would fold to 'PreXyzPost' + fold_same("'PreXyzPost'.replaceAll('Xyz', '$`')"); // would fold to 'PrePrePost' + fold_same("'PreXyzPost'.replaceAll('Xyz', '$\\'')"); // would fold to 'PrePostPost' + fold_same("'PreXyzPostXyz'.replaceAll('Xyz', '$\\'')"); // would fold to 'PrePostXyzPost' + fold_same("'123'.replaceAll('2', '$`')"); // would fold to '113' + } + + #[test] + #[ignore] + fn test_fold_string_substring() { + fold("x = 'abcde'.substring(0,2)", "x = 'ab'"); + fold("x = 'abcde'.substring(1,2)", "x = 'b'"); + fold("x = 'abcde'.substring(2)", "x = 'cde'"); + + // we should be leaving negative, out-of-bound, and inverted indices alone for now + fold_same("x = 'abcde'.substring(-1)"); + fold_same("x = 'abcde'.substring(1, -2)"); + fold_same("x = 'abcde'.substring(1, 2, 3)"); + fold_same("x = 'abcde'.substring(2, 0)"); + fold_same("x = 'a'.substring(0, 2)"); + + // Template strings + fold_same("x = `abcdef`.substring(0,2)"); + fold_same("x = `abcdef ${abc}`.substring(0,2)"); + } + + #[test] + #[ignore] + fn test_fold_string_slice() { + fold("x = 'abcde'.slice(0,2)", "x = 'ab'"); + fold("x = 'abcde'.slice(1,2)", "x = 'b'"); + fold("x = 'abcde'.slice(2)", "x = 'cde'"); + + // we should be leaving negative, out-of-bound, and inverted indices alone for now + fold_same("x = 'abcde'.slice(-1)"); + fold_same("x = 'abcde'.slice(1, -2)"); + fold_same("x = 'abcde'.slice(1, 2, 3)"); + fold_same("x = 'abcde'.slice(2, 0)"); + fold_same("x = 'a'.slice(0, 2)"); + + // Template strings + fold_same("x = `abcdef`.slice(0,2)"); + fold_same("x = `abcdef ${abc}`.slice(0,2)"); + } + + #[test] + #[ignore] + fn test_fold_string_char_at() { + fold("x = 'abcde'.charAt(0)", "x = 'a'"); + fold("x = 'abcde'.charAt(1)", "x = 'b'"); + fold("x = 'abcde'.charAt(2)", "x = 'c'"); + fold("x = 'abcde'.charAt(3)", "x = 'd'"); + fold("x = 'abcde'.charAt(4)", "x = 'e'"); + fold_same("x = 'abcde'.charAt(5)"); // or x = '' + fold_same("x = 'abcde'.charAt(-1)"); // or x = '' + fold_same("x = 'abcde'.charAt(y)"); + fold_same("x = 'abcde'.charAt()"); // or x = 'a' + fold_same("x = 'abcde'.charAt(0, ++z)"); // or (++z, 'a') + fold_same("x = 'abcde'.charAt(null)"); // or x = 'a' + fold_same("x = 'abcde'.charAt(true)"); // or x = 'b' + // fold("x = '\\ud834\udd1e'.charAt(0)", "x = '\\ud834'"); + // fold("x = '\\ud834\udd1e'.charAt(1)", "x = '\\udd1e'"); + + // Template strings + fold_same("x = `abcdef`.charAt(0)"); + fold_same("x = `abcdef ${abc}`.charAt(0)"); + } + + #[test] + #[ignore] + fn test_fold_string_char_code_at() { + fold("x = 'abcde'.charCodeAt(0)", "x = 97"); + fold("x = 'abcde'.charCodeAt(1)", "x = 98"); + fold("x = 'abcde'.charCodeAt(2)", "x = 99"); + fold("x = 'abcde'.charCodeAt(3)", "x = 100"); + fold("x = 'abcde'.charCodeAt(4)", "x = 101"); + fold_same("x = 'abcde'.charCodeAt(5)"); // or x = (0/0) + fold_same("x = 'abcde'.charCodeAt(-1)"); // or x = (0/0) + fold_same("x = 'abcde'.charCodeAt(y)"); + fold_same("x = 'abcde'.charCodeAt()"); // or x = 97 + fold_same("x = 'abcde'.charCodeAt(0, ++z)"); // or (++z, 97) + fold_same("x = 'abcde'.charCodeAt(null)"); // or x = 97 + fold_same("x = 'abcde'.charCodeAt(true)"); // or x = 98 + // fold("x = '\\ud834\udd1e'.charCodeAt(0)", "x = 55348"); + // fold("x = '\\ud834\udd1e'.charCodeAt(1)", "x = 56606"); + + // Template strings + fold_same("x = `abcdef`.charCodeAt(0)"); + fold_same("x = `abcdef ${abc}`.charCodeAt(0)"); + } + + #[test] + #[ignore] + fn test_fold_string_split() { + // late = false; + fold("x = 'abcde'.split('foo')", "x = ['abcde']"); + fold("x = 'abcde'.split()", "x = ['abcde']"); + fold("x = 'abcde'.split(null)", "x = ['abcde']"); + fold("x = 'a b c d e'.split(' ')", "x = ['a','b','c','d','e']"); + fold("x = 'a b c d e'.split(' ', 0)", "x = []"); + fold("x = 'abcde'.split('cd')", "x = ['ab','e']"); + fold("x = 'a b c d e'.split(' ', 1)", "x = ['a']"); + fold("x = 'a b c d e'.split(' ', 3)", "x = ['a','b','c']"); + fold("x = 'a b c d e'.split(null, 1)", "x = ['a b c d e']"); + fold("x = 'aaaaa'.split('a')", "x = ['', '', '', '', '', '']"); + fold("x = 'xyx'.split('x')", "x = ['', 'y', '']"); + + // Empty separator + fold("x = 'abcde'.split('')", "x = ['a','b','c','d','e']"); + fold("x = 'abcde'.split('', 3)", "x = ['a','b','c']"); + + // Empty separator AND empty string + fold("x = ''.split('')", "x = []"); + + // Separator equals string + fold("x = 'aaa'.split('aaa')", "x = ['','']"); + fold("x = ' '.split(' ')", "x = ['','']"); + + fold_same("x = 'abcde'.split(/ /)"); + fold_same("x = 'abcde'.split(' ', -1)"); + + // Template strings + fold_same("x = `abcdef`.split()"); + fold_same("x = `abcdef ${abc}`.split()"); + + // late = true; + // fold_same("x = 'a b c d e'.split(' ')"); + } + + #[test] + #[ignore] + fn test_join_bug() { + fold("var x = [].join();", "var x = '';"); + fold_same("var x = [x].join();"); + fold_same("var x = [x,y].join();"); + fold_same("var x = [x,y,z].join();"); + + // fold_same( + // lines( + // "shape['matrix'] = [", + // " Number(headingCos2).toFixed(4),", + // " Number(-headingSin2).toFixed(4),", + // " Number(headingSin2 * yScale).toFixed(4),", + // " Number(headingCos2 * yScale).toFixed(4),", + // " 0,", + // " 0", + // " ].join()")); + } + + #[test] + #[ignore] + fn test_join_spread1() { + fold_same("var x = [...foo].join('');"); + fold_same("var x = [...someMap.keys()].join('');"); + fold_same("var x = [foo, ...bar].join('');"); + fold_same("var x = [...foo, bar].join('');"); + fold_same("var x = [...foo, 'bar'].join('');"); + fold_same("var x = ['1', ...'2', '3'].join('');"); + fold_same("var x = ['1', ...['2'], '3'].join('');"); + } + + #[test] + #[ignore] + fn test_join_spread2() { + fold("var x = [...foo].join(',');", "var x = [...foo].join();"); + fold("var x = [...someMap.keys()].join(',');", "var x = [...someMap.keys()].join();"); + fold("var x = [foo, ...bar].join(',');", "var x = [foo, ...bar].join();"); + fold("var x = [...foo, bar].join(',');", "var x = [...foo, bar].join();"); + fold("var x = [...foo, 'bar'].join(',');", "var x = [...foo, 'bar'].join();"); + fold("var x = ['1', ...'2', '3'].join(',');", "var x = ['1', ...'2', '3'].join();"); + fold("var x = ['1', ...['2'], '3'].join(',');", "var x = ['1', ...['2'], '3'].join();"); + } + + #[test] + #[ignore] + fn test_to_upper() { + fold("'a'.toUpperCase()", "'A'"); + fold("'A'.toUpperCase()", "'A'"); + fold("'aBcDe'.toUpperCase()", "'ABCDE'"); + + fold_same("`abc`.toUpperCase()"); + fold_same("`a ${bc}`.toUpperCase()"); + + /* + * Make sure things aren't totally broken for non-ASCII strings, non-exhaustive. + * + *
This includes things like: + * + *
This includes things like: + * + *