use swc_ecma_parser::Syntax; use swc_ecma_transforms_compat::es2015::template_literal; use swc_ecma_transforms_testing::test; use swc_ecma_transforms_testing::test_exec; use swc_ecma_visit::Fold; fn syntax() -> Syntax { Default::default() } fn tr(_: ()) -> impl Fold { template_literal() } test_exec!( syntax(), |_| tr(Default::default()), issue_231, "const truthy = 'a=b'; const foo = `http://example.com/foo/bar${truthy && '?'}${truthy}`; expect(foo).toBe('http://example.com/foo/bar?a=b');\ " ); test_exec!( syntax(), |_| tr(Default::default()), issue_388, " 'use strict'; const write = (text) => { console.log(text) } write(1) write('2') write`3`" ); test!( syntax(), |_| tr(Default::default()), escape_quotes, r#"var t = `'${foo}' "${bar}"`;"#, r#"var t = "'".concat(foo, '\' "').concat(bar, '"');"#, ok_if_code_eq ); test!( syntax(), |_| tr(Default::default()), multiple, r#"var foo = `test ${foo} ${bar}`;"#, r#"var foo = 'test '.concat(foo, ' ').concat(bar);"# ); test!( syntax(), |_| tr(Default::default()), none, r#"var foo = `test`;"#, r#"var foo = "test";"# ); test!( syntax(), |_| tr(Default::default()), only, r#"var foo = `${test}`;"#, r#"var foo = ''.concat(test);"# ); test_exec!( syntax(), |_| tr(Default::default()), order, r#" const calls = []; ` ${ (calls.push(1), { [Symbol.toPrimitive](){ calls.push(2); return 'foo'; } }) } ${ (calls.push(3), { [Symbol.toPrimitive](){ calls.push(4); return 'bar'; } }) } `; expect(calls).toEqual([1, 2, 3, 4]);"# ); test_exec!( syntax(), |_| tr(Default::default()), order2, r#"const calls = []; ` ${{ [Symbol.toPrimitive]() { calls.push(1); return "foo"; } }} ${1 + { valueOf() { calls.push(2); return 2; } }} `; expect(calls).toEqual([1, 2]);"# ); test!( syntax(), |_| tr(Default::default()), single, r#"var foo = `test ${foo}`;"#, r#"var foo = 'test '.concat(foo);"# ); test!( syntax(), |_| tr(Default::default()), statement, r#"var foo = `test ${foo + bar}`;"#, r#"var foo = 'test '.concat(foo + bar);"#, ok_if_code_eq ); test_exec!( syntax(), |_| tr(Default::default()), symbol, r#"const fn = () => `${Symbol()}`; expect(fn).toThrow(TypeError);"# ); test!( // TODO: Fix parser ignore, syntax(), |_| tr(Default::default()), template_revision, r#"tag`\unicode and \u{55}`; tag`\01`; tag`\xg${0}right`; tag`left${0}\xg`; tag`left${0}\xg${1}right`; tag`left${0}\u000g${1}right`; tag`left${0}\u{-0}${1}right`; function a() { var undefined = 4; tag`\01`; }"#, r#" function _templateObject8() { const data = _taggedTemplateLiteral([void 0], ["\\01"]); _templateObject8 = function () { return data; }; return data; } function _templateObject7() { const data = _taggedTemplateLiteral(["left", void 0, "right"], ["left", "\\u{-0}", "right"]); _templateObject7 = function () { return data; }; return data; } function _templateObject6() { const data = _taggedTemplateLiteral(["left", void 0, "right"], ["left", "\\u000g", "right"]); _templateObject6 = function () { return data; }; return data; } function _templateObject5() { const data = _taggedTemplateLiteral(["left", void 0, "right"], ["left", "\\xg", "right"]); _templateObject5 = function () { return data; }; return data; } function _templateObject4() { const data = _taggedTemplateLiteral(["left", void 0], ["left", "\\xg"]); _templateObject4 = function () { return data; }; return data; } function _templateObject3() { const data = _taggedTemplateLiteral([void 0, "right"], ["\\xg", "right"]); _templateObject3 = function () { return data; }; return data; } function _templateObject2() { const data = _taggedTemplateLiteral([void 0], ["\\01"]); _templateObject2 = function () { return data; }; return data; } function _templateObject() { const data = _taggedTemplateLiteral([void 0], ["\\unicode and \\u{55}"]); _templateObject = function () { return data; }; return data; } tag(_templateObject()); tag(_templateObject2()); tag(_templateObject3(), 0); tag(_templateObject4(), 0); tag(_templateObject5(), 0, 1); tag(_templateObject6(), 0, 1); tag(_templateObject7(), 0, 1); function a() { var undefined = 4; tag(_templateObject8()); }"# ); // default_order_exec test_exec!( syntax(), |_| tr(Default::default()), default_order_exec, r#" const calls = []; ` ${ (calls.push(1), { [Symbol.toPrimitive](){ calls.push(2); return 'foo'; } }) } ${ (calls.push(3), { [Symbol.toPrimitive](){ calls.push(4); return 'bar'; } }) } `; expect(calls).toEqual([1, 2, 3, 4]); "# ); // default_only test!( syntax(), |_| tr(Default::default()), default_only, r#" var foo = `${test}`; "#, r#" var foo = "".concat(test); "# ); // default_single test!( syntax(), |_| tr(Default::default()), default_single, r#" var foo = `test ${foo}`; "#, r#" var foo = "test ".concat(foo); "# ); // default_statement test!( syntax(), |_| tr(Default::default()), default_statement, r#" var foo = `test ${foo + bar}`; "#, r#" var foo = "test ".concat(foo + bar); "# ); // default_expression_first test!( syntax(), |_| tr(Default::default()), default_expression_first, r#" var foo = 5; var bar = 10; var baz = 15; var example = `${"a"}`; var example2 = `${1}`; var example3 = 1 + `${foo}${bar}${baz}`; var example4 = 1 + `${foo}bar${baz}`; var example5 = `${""}`; "#, r#" var foo = 5; var bar = 10; var baz = 15; var example = "a"; var example2 = "".concat(1); var example3 = 1 + "".concat(foo).concat(bar).concat(baz); var example4 = 1 + "".concat(foo, "bar").concat(baz); var example5 = ""; "# ); // default_literals test!( syntax(), |_| tr(Default::default()), default_literals, r#" var foo = `${1}${f}oo${true}${b}ar${0}${baz}`; "#, r#" var foo = ''.concat(1).concat(f, 'oo', true).concat(b, 'ar', 0).concat(baz); "# ); // default_multiline test!( syntax(), |_| tr(Default::default()), default_multiline, r#" var o = `wow this is actually multiline!`; "#, r#" var o = "wow\nthis is\nactually multiline!"; "#, ok_if_code_eq ); // default_template_revision test!( // TODO: Improve parser ignore, syntax(), |_| tr(Default::default()), default_template_revision, r#" tag`\unicode and \u{55}`; tag`\01`; tag`\xg${0}right`; tag`left${0}\xg`; tag`left${0}\xg${1}right`; tag`left${0}\u000g${1}right`; tag`left${0}\u{-0}${1}right`; function a() { var undefined = 4; tag`\01`; } "#, r#" function _templateObject8() { const data = _taggedTemplateLiteral([void 0], ["\\01"]); _templateObject8 = function () { return data; }; return data; } function _templateObject7() { const data = _taggedTemplateLiteral(["left", void 0, "right"], ["left", "\\u{-0}", "right"]); _templateObject7 = function () { return data; }; return data; } function _templateObject6() { const data = _taggedTemplateLiteral(["left", void 0, "right"], ["left", "\\u000g", "right"]); _templateObject6 = function () { return data; }; return data; } function _templateObject5() { const data = _taggedTemplateLiteral(["left", void 0, "right"], ["left", "\\xg", "right"]); _templateObject5 = function () { return data; }; return data; } function _templateObject4() { const data = _taggedTemplateLiteral(["left", void 0], ["left", "\\xg"]); _templateObject4 = function () { return data; }; return data; } function _templateObject3() { const data = _taggedTemplateLiteral([void 0, "right"], ["\\xg", "right"]); _templateObject3 = function () { return data; }; return data; } function _templateObject2() { const data = _taggedTemplateLiteral([void 0], ["\\01"]); _templateObject2 = function () { return data; }; return data; } function _templateObject() { const data = _taggedTemplateLiteral([void 0], ["\\unicode and \\u{55}"]); _templateObject = function () { return data; }; return data; } function _taggedTemplateLiteral(strings, raw) { if (!raw) { raw = strings.slice(0); } return Object.freeze(Object.defineProperties(strings, { raw: { value: Object.freeze(raw) } })); } tag(_templateObject()); tag(_templateObject2()); tag(_templateObject3(), 0); tag(_templateObject4(), 0); tag(_templateObject5(), 0, 1); tag(_templateObject6(), 0, 1); tag(_templateObject7(), 0, 1); function a() { var undefined = 4; tag(_templateObject8()); } "# ); // default_order2_exec test_exec!( syntax(), |_| tr(Default::default()), default_order2_exec, r#" const calls = []; ` ${{ [Symbol.toPrimitive]() { calls.push(1); return "foo"; } }} ${1 + { valueOf() { calls.push(2); return 2; } }} `; expect(calls).toEqual([1, 2]); "# ); // default_cache_revision_exec test_exec!( syntax(), |_| tr(Default::default()), default_cache_revision_exec, r#" var tag = v => v; function foo() { return tag`some template`; } function bar() { return tag`some template`; } expect(foo()).toBe(foo()); expect(foo()).toEqual(["some template"]); expect(bar()).toBe(bar()); expect(bar()).toEqual(["some template"]); expect(bar()).not.toBe(foo()); "# ); // default_functions test!( syntax(), |_| tr(Default::default()), default_functions, r#" var foo = `test ${_.test(foo)} ${bar}`; "#, r#" var foo = "test ".concat(_.test(foo), " ").concat(bar); "# ); // default_none test!( syntax(), |_| tr(Default::default()), default_none, r#" var foo = `test`; "#, r#" var foo = "test"; "# ); // default_symbol_exec test_exec!( syntax(), |_| tr(Default::default()), default_symbol_exec, r#" const fn = () => `${Symbol()}`; expect(fn).toThrow(TypeError); "# ); // default_cache_revision test!( syntax(), |_| tr(Default::default()), default_cache_revision, r#" var tag = v => v; function foo() { return tag`some template`; } function bar() { return tag`some template`; } expect(foo()).toBe(foo()); expect(foo()).toEqual(["some template"]); expect(bar()).toBe(bar()); expect(bar()).toEqual(["some template"]); expect(bar()).not.toBe(foo()); "#, r#" function _templateObject() { const data = _taggedTemplateLiteral(["some template"]); _templateObject = function () { return data; }; return data; } function _templateObject1() { const data = _taggedTemplateLiteral(["some template"]); _templateObject1 = function () { return data; }; return data; } var tag = v => v; function foo() { return tag(_templateObject()); } function bar() { return tag(_templateObject1()); } expect(foo()).toBe(foo()); expect(foo()).toEqual(["some template"]); expect(bar()).toBe(bar()); expect(bar()).toEqual(["some template"]); expect(bar()).not.toBe(foo()); "# ); // default_tag test!( syntax(), |_| tr(Default::default()), default_tag, r#" var foo = bar`wow\na${ 42 }b ${_.foobar()}`; var bar = bar`wow\nab${ 42 } ${_.foobar()}`; var bar = bar`wow\naB${ 42 } ${_.baz()}`; "#, r#" function _templateObject() { const data = _taggedTemplateLiteral(["wow\na", "b ", ""], ["wow\\na", "b ", ""]); _templateObject = function () { return data; }; return data; } function _templateObject1() { const data = _taggedTemplateLiteral(["wow\nab", " ", ""], ["wow\\nab", " ", ""]); _templateObject1 = function () { return data; }; return data; } function _templateObject2() { const data = _taggedTemplateLiteral(["wow\naB", " ", ""], ["wow\\naB", " ", ""]); _templateObject2 = function () { return data; }; return data; } var foo = bar(_templateObject(), 42, _.foobar()); var bar = bar(_templateObject1(), 42, _.foobar()); var bar = bar(_templateObject2(), 42, _.baz()); "# ); // default_simple_tag test!( syntax(), |_| tr(Default::default()), default_simple_tag, r#" var foo = tag`wow`; var bar = tag`first${1}second`; "#, r#" function _templateObject() { const data = _taggedTemplateLiteral(["wow"]); _templateObject = function () { return data; }; return data; } function _templateObject1() { const data = _taggedTemplateLiteral(["first", "second"]); _templateObject1 = function () { return data; }; return data; } var foo = tag(_templateObject()); var bar = tag(_templateObject1(), 1); "# ); test!( syntax(), |_| tr(Default::default()), issue_598_1, " export function foo() { console.log(i18n`Hello World`); console.log(i18n`Nobody will ever see this.`); } ", "function _templateObject() { const data = _taggedTemplateLiteral([ \"Hello World\" ]); _templateObject = function() { return data; }; return data; } function _templateObject1() { const data = _taggedTemplateLiteral([ \"Nobody will ever see this.\" ]); _templateObject1 = function() { return data; }; return data; } export function foo() { console.log(i18n(_templateObject())); console.log(i18n(_templateObject1())); } " ); test!( syntax(), |_| tr(Default::default()), codegen_01, "`\"`", r#""\"""#, ok_if_code_eq ); test!( syntax(), |_| tr(Default::default()), codegen_02, "`\"\"`", r#" "\"\"" "#, ok_if_code_eq ); test!( syntax(), |_| tr(Default::default()), codegen_03, "`\"${foo}`", r#" "\"".concat(foo); "#, ok_if_code_eq ); test!( syntax(), |_| tr(Default::default()), codegen_04, "`\"${foo}\"`", r#" "\"".concat(foo, "\""); "#, ok_if_code_eq ); test!( syntax(), |_| tr(Default::default()), codegen_05, "`\"\"${foo}\"\"`", r#" "\"\"".concat(foo, "\"\""); "#, ok_if_code_eq ); test!( syntax(), |_| tr(Default::default()), codegen_06, "\"``\"", "\"``\"", ok_if_code_eq ); test!( syntax(), |_| tr(Default::default()), codegen_07, r#"`The ${argumentName} has unexpected type of "`"#, r#""The ".concat(argumentName, " has unexpected type of \"");"#, ok_if_code_eq ); test!( syntax(), |_| tr(Default::default()), codegen_08, r#"`". Expected argument to be an object with the following `"#, r#""\". Expected argument to be an object with the following ";"#, ok_if_code_eq ); test!( syntax(), |_| tr(Default::default()), codegen_09, r#"`keys: "${reducerKeys.join('", "')}"`"#, r#""keys: \"".concat(reducerKeys.join('\", \"'), "\"");"#, ok_if_code_eq ); test!( syntax(), |_| tr(Default::default()), codegen_10, r#"`The ${argumentName} has unexpected type of "` + matchType + `". Expected argument to be an object with the following ` + `keys: "${reducerKeys.join('", "')}"`"#, r#""The ".concat(argumentName, " has unexpected type of \"") + matchType + "\". Expected argument to be an object with the following " + "keys: \"".concat(reducerKeys.join('", "'), "\"")"#, ok_if_code_eq ); test!( syntax(), |_| tr(Default::default()), issue_1280, " const myVar = T`'Hello'`; ", " function _templateObject() { const data = _taggedTemplateLiteral([ \"'Hello'\" ]); _templateObject = function() { return data; }; return data; } const myVar = T(_templateObject()); ", ok_if_code_eq ); test!( syntax(), |_| tr(Default::default()), issue_1488_1, " `\\`` ", " '`' " ); test!( syntax(), |_| tr(Default::default()), issue_1549_1, "const a = `\r\n`;", "const a = \"\\n\";", ok_if_code_eq ); test!( syntax(), |_| tr(Default::default()), issue_1549_2, "const a = \"\\r\\n\";", "const a = \"\\r\\n\";" ); test!( syntax(), |_| tr(Default::default()), issue_1742_1, " function foo() { return this; } foo`template` ", " function _templateObject() { const data = _taggedTemplateLiteral([ 'template' ]); _templateObject = function() { return data; }; return data; } function foo() { return this; } foo(_templateObject()); " ); test_exec!( syntax(), |_| tr(Default::default()), issue_1742_2, " const obj = { foo() { return this; } } expect(typeof obj.foo`template`).toEqual('object') " );