mirror of
https://github.com/swc-project/swc.git
synced 2024-10-04 20:28:43 +03:00
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:
parent
ef6a745599
commit
8726c9caf2
@ -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"
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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]
|
||||
|
@ -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) => {
|
||||
|
@ -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')
|
||||
"
|
||||
);
|
||||
|
@ -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
16
tests/fixture/issue-1742/case1/input/index.js
Normal file
16
tests/fixture/issue-1742/case1/input/index.js
Normal 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();
|
64
tests/fixture/issue-1742/case1/output/index.js
Normal file
64
tests/fixture/issue-1742/case1/output/index.js
Normal 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();
|
1
tests/fixture/issue-1744/case1/input/index.js
Normal file
1
tests/fixture/issue-1744/case1/input/index.js
Normal file
@ -0,0 +1 @@
|
||||
console.log("🤭 ü");
|
1
tests/fixture/issue-1744/case1/output/index.js
Normal file
1
tests/fixture/issue-1744/case1/output/index.js
Normal file
@ -0,0 +1 @@
|
||||
console.log("🤭 \xfc");
|
Loading…
Reference in New Issue
Block a user