fix(swc): Fix bugs (#1745)

swc_ecma_codegen:
 - Don't escape unicode characters for old targets. (#1744)

swc_ecma_transforms_compat:
 - `class_properties`: Preserve `this` for tagged template literals. (#1742)
This commit is contained in:
강동윤 2021-05-26 01:24:58 +09:00 committed by GitHub
parent ef6a745599
commit 8726c9caf2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 265 additions and 12 deletions

View File

@ -7,7 +7,7 @@ include = ["Cargo.toml", "src/**/*.rs"]
license = "Apache-2.0/MIT"
name = "swc_ecma_codegen"
repository = "https://github.com/swc-project/swc.git"
version = "0.55.2"
version = "0.55.3"
[dependencies]
bitflags = "1"

View File

@ -2503,15 +2503,19 @@ fn escape_without_source(v: &str, target: JscTarget, single_quote: bool) -> Stri
}
_ => {
let escaped = c.escape_unicode().to_string();
if target >= EsVersion::Es2015 {
let escaped = c.escape_unicode().to_string();
if escaped.starts_with('\\') {
buf.push_str("\\u");
if escaped.len() == 8 {
buf.push_str(&escaped[3..=6]);
} else {
buf.push_str(&escaped[2..]);
if escaped.starts_with('\\') {
buf.push_str("\\u");
if escaped.len() == 8 {
buf.push_str(&escaped[3..=6]);
} else {
buf.push_str(&escaped[2..]);
}
}
} else {
buf.push(c);
}
}
}

View File

@ -6,7 +6,7 @@ edition = "2018"
license = "Apache-2.0/MIT"
name = "swc_ecma_transforms_compat"
repository = "https://github.com/swc-project/swc.git"
version = "0.17.6"
version = "0.17.7"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

View File

@ -354,6 +354,40 @@ impl<'a> Fold for FieldAccessFolder<'a> {
})
}
// Actuall this is a call and we should bind `this`.
Expr::TaggedTpl(TaggedTpl {
span,
tag,
tpl,
type_params,
}) if tag.is_member() => {
let tag = tag.member().unwrap().fold_with(self);
let tpl = tpl.fold_with(self);
let (e, this) = self.fold_private_get(tag, None);
if let Some(this) = this {
Expr::TaggedTpl(TaggedTpl {
span,
tag: Box::new(Expr::Call(CallExpr {
span: DUMMY_SP,
callee: e.make_member(quote_ident!("bind")).as_callee(),
args: vec![this.as_arg()],
type_args: Default::default(),
})),
tpl,
type_params,
})
} else {
Expr::TaggedTpl(TaggedTpl {
span,
tag: Box::new(e),
tpl,
type_params,
})
}
}
Expr::Call(CallExpr {
span,
callee: ExprOrSuper::Expr(callee),
@ -379,7 +413,6 @@ impl<'a> Fold for FieldAccessFolder<'a> {
args,
type_args,
})
.fold_children_with(self)
}
}
Expr::Member(e) => {

View File

@ -957,3 +957,44 @@ test!(
"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')
"
);

View File

@ -5,7 +5,7 @@ use swc_common::chain;
use swc_ecma_parser::{EsConfig, Syntax, TsConfig};
use swc_ecma_transforms_base::resolver::resolver;
use swc_ecma_transforms_compat::{
es2015::{arrow, block_scoping, classes, function_name},
es2015::{arrow, block_scoping, classes, function_name, template_literal},
es2016::exponentation,
es2017::async_to_generator,
es2020::{class_properties, typescript_class_properties},
@ -5386,3 +5386,96 @@ test!(
}
"
);
test_exec!(
syntax(),
|_| class_properties(),
issue_1742_1,
"
class Foo {
#tag() {
return this;
}
#tag2 = this.#tag;
constructor() {
const receiver = this.#tag`tagged template`;
expect(receiver).toBe(this);
const receiver2 = this.#tag2`tagged template`;
expect(receiver2).toBe(this);
}
}
new Foo();
"
);
test_exec!(
syntax(),
|_| chain!(class_properties(), template_literal()),
issue_1742_2,
"
class Foo {
#tag() {
return this;
}
#tag2 = this.#tag;
constructor() {
const receiver = this.#tag`tagged template`;
expect(receiver).toBe(this);
const receiver2 = this.#tag2`tagged template`;
expect(receiver2).toBe(this);
}
}
new Foo();
"
);
test!(
syntax(),
|_| class_properties(),
issue_1742_3,
"
class Foo {
#tag() {
return this;
}
#tag2 = this.#tag;
constructor() {
const receiver = this.#tag`tagged template`;
expect(receiver).toBe(this);
const receiver2 = this.#tag2`tagged template`;
expect(receiver2).toBe(this);
}
}
new Foo();
",
"
var _tag = new WeakSet();
class Foo {
constructor(){
_tag.add(this);
_tag2.set(this, {
writable: true,
value: _classPrivateMethodGet(this, _tag, tag)
});
const receiver = _classPrivateMethodGet(this, _tag, tag).bind(this)`tagged template`;
expect(receiver).toBe(this);
const receiver2 = _classPrivateFieldGet(this, _tag2).bind(this)`tagged template`;
expect(receiver2).toBe(this);
}
}
var _tag2 = new WeakMap();
function tag() {
return this;
}
new Foo();
"
);

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,16 @@
class Foo {
#tag() {
return this;
}
#tag2 = this.#tag;
constructor() {
const receiver = this.#tag`tagged template`;
console.log(receiver === this);
const receiver2 = this.#tag2`tagged template`;
console.log(receiver2 === this);
}
}
new Foo();

View File

@ -0,0 +1,64 @@
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _classPrivateFieldGet(receiver, privateMap) {
if (!privateMap.has(receiver)) {
throw new TypeError("attempted to get private field on non-instance");
}
return privateMap.get(receiver).value;
}
function _classPrivateMethodGet(receiver, privateSet, fn) {
if (!privateSet.has(receiver)) {
throw new TypeError("attempted to get private field on non-instance");
}
return fn;
}
function _taggedTemplateLiteral(strings, raw) {
if (!raw) {
raw = strings.slice(0);
}
return Object.freeze(Object.defineProperties(strings, {
raw: {
value: Object.freeze(raw)
}
}));
}
function _templateObject() {
var data = _taggedTemplateLiteral([
"tagged template"
]);
_templateObject = function _templateObject() {
return data;
};
return data;
}
function _templateObject1() {
var data = _taggedTemplateLiteral([
"tagged template"
]);
_templateObject1 = function _templateObject1() {
return data;
};
return data;
}
var _tag = new WeakSet();
var Foo = function Foo() {
"use strict";
_classCallCheck(this, Foo);
_tag.add(this);
_tag2.set(this, {
writable: true,
value: _classPrivateMethodGet(this, _tag, tag)
});
var receiver = _classPrivateMethodGet(this, _tag, tag).bind(this)(_templateObject());
console.log(receiver === this);
var receiver2 = _classPrivateFieldGet(this, _tag2).bind(this)(_templateObject1());
console.log(receiver2 === this);
};
var _tag2 = new WeakMap();
function tag() {
return this;
}
new Foo();

View File

@ -0,0 +1 @@
console.log("🤭 ü");

View File

@ -0,0 +1 @@
console.log("🤭 \xfc");