mirror of
https://github.com/swc-project/swc.git
synced 2024-11-23 17:54:15 +03:00
fix(swc): Fix bugs (#1300)
swc_ecma_codegen: - Handle unicode escape sequences when target is es5. (#1227, #1326) swc_ecma_transforms_compat: - Handle template literals correctly. (#1314) - Handle private class properties correctly. (#1306) swc: - Don't panic on `export * as foo from 'foo'`. (#1307)
This commit is contained in:
parent
6984217200
commit
a9bf9bb9e1
2
bundler/tests/deno-exec/issue-8302/entry.ts
Normal file
2
bundler/tests/deno-exec/issue-8302/entry.ts
Normal file
@ -0,0 +1,2 @@
|
||||
import axiod from 'https://deno.land/x/axiod/mod.ts';
|
||||
console.log(axiod)
|
@ -1,3 +1,4 @@
|
||||
const a = import('./dep')
|
||||
|
||||
console.log(a)
|
||||
console.log(a)
|
||||
|
||||
|
@ -2493,6 +2493,10 @@ fn escape_with_source<'s>(
|
||||
s: &'s str,
|
||||
single_quote: Option<bool>,
|
||||
) -> String {
|
||||
if target <= JscTarget::Es5 {
|
||||
return escape_without_source(s, target, single_quote.unwrap_or(false));
|
||||
}
|
||||
|
||||
if span.is_dummy() {
|
||||
return escape_without_source(s, target, single_quote.unwrap_or(false));
|
||||
}
|
||||
|
@ -105,4 +105,8 @@ where
|
||||
fn write_punct(&mut self, s: &'static str) -> Result {
|
||||
(**self).write_punct(s)
|
||||
}
|
||||
|
||||
fn target(&self) -> JscTarget {
|
||||
(**self).target()
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
use super::{Result, WriteJs};
|
||||
use std::io::{self, Write};
|
||||
use swc_common::{sync::Lrc, BytePos, LineCol, SourceMap, Span};
|
||||
use swc_ecma_parser::JscTarget;
|
||||
|
||||
///
|
||||
/// -----
|
||||
@ -19,6 +20,7 @@ pub struct JsWriter<'a, W: Write> {
|
||||
srcmap: Option<&'a mut Vec<(BytePos, LineCol)>>,
|
||||
wr: W,
|
||||
written_bytes: usize,
|
||||
target: JscTarget,
|
||||
}
|
||||
|
||||
impl<'a, W: Write> JsWriter<'a, W> {
|
||||
@ -27,6 +29,16 @@ impl<'a, W: Write> JsWriter<'a, W> {
|
||||
new_line: &'a str,
|
||||
wr: W,
|
||||
srcmap: Option<&'a mut Vec<(BytePos, LineCol)>>,
|
||||
) -> Self {
|
||||
Self::with_target(cm, new_line, wr, srcmap, JscTarget::Es2020)
|
||||
}
|
||||
|
||||
pub fn with_target(
|
||||
cm: Lrc<SourceMap>,
|
||||
new_line: &'a str,
|
||||
wr: W,
|
||||
srcmap: Option<&'a mut Vec<(BytePos, LineCol)>>,
|
||||
target: JscTarget,
|
||||
) -> Self {
|
||||
JsWriter {
|
||||
_cm: cm,
|
||||
@ -38,6 +50,7 @@ impl<'a, W: Write> JsWriter<'a, W> {
|
||||
srcmap,
|
||||
wr,
|
||||
written_bytes: 0,
|
||||
target,
|
||||
}
|
||||
}
|
||||
|
||||
@ -187,6 +200,10 @@ impl<'a, W: Write> WriteJs for JsWriter<'a, W> {
|
||||
self.write(None, s)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn target(&self) -> JscTarget {
|
||||
self.target
|
||||
}
|
||||
}
|
||||
|
||||
fn compute_line_starts(s: &str) -> Vec<usize> {
|
||||
|
@ -372,11 +372,22 @@ impl<'a> Fold for FieldAccessFolder<'a> {
|
||||
.fold_children_with(self)
|
||||
}
|
||||
}
|
||||
Expr::Member(e) => self.fold_private_get(e, None).0,
|
||||
Expr::Member(e) => {
|
||||
let e = e.fold_with(self);
|
||||
self.fold_private_get(e, None).0
|
||||
}
|
||||
_ => e.fold_children_with(self),
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_member_expr(&mut self, mut e: MemberExpr) -> MemberExpr {
|
||||
e.obj = e.obj.fold_with(self);
|
||||
if e.computed {
|
||||
e.prop = e.prop.fold_with(self);
|
||||
}
|
||||
e
|
||||
}
|
||||
|
||||
fn fold_pat(&mut self, p: Pat) -> Pat {
|
||||
if let Pat::Expr(expr) = &p {
|
||||
if let Expr::Member(me) = &**expr {
|
||||
|
@ -4840,3 +4840,71 @@ export class HygieneTest {
|
||||
}",
|
||||
ok_if_code_eq
|
||||
);
|
||||
|
||||
test!(
|
||||
syntax(),
|
||||
|_| class_properties(),
|
||||
issue_1306_1,
|
||||
r#"
|
||||
class Animal {
|
||||
#name;
|
||||
|
||||
constructor(name) {
|
||||
this.#name = name
|
||||
}
|
||||
|
||||
noise() {
|
||||
return this.#name
|
||||
}
|
||||
}
|
||||
"#,
|
||||
"
|
||||
class Animal {
|
||||
noise() {
|
||||
return _classPrivateFieldGet(this, _name);
|
||||
}
|
||||
constructor(name){
|
||||
_name.set(this, {
|
||||
writable: true,
|
||||
value: void 0
|
||||
});
|
||||
_classPrivateFieldSet(this, _name, name);
|
||||
}
|
||||
}
|
||||
var _name = new WeakMap();
|
||||
"
|
||||
);
|
||||
|
||||
test!(
|
||||
syntax(),
|
||||
|_| class_properties(),
|
||||
issue_1306_2,
|
||||
r#"
|
||||
class Animal {
|
||||
#name;
|
||||
|
||||
constructor(name) {
|
||||
this.#name = name
|
||||
}
|
||||
|
||||
noise() {
|
||||
return this.#name.toUpperCase()
|
||||
}
|
||||
}
|
||||
"#,
|
||||
"
|
||||
class Animal {
|
||||
noise() {
|
||||
return _classPrivateFieldGet(this, _name).toUpperCase();
|
||||
}
|
||||
constructor(name){
|
||||
_name.set(this, {
|
||||
writable: true,
|
||||
value: void 0
|
||||
});
|
||||
_classPrivateFieldSet(this, _name, name);
|
||||
}
|
||||
}
|
||||
var _name = new WeakMap();
|
||||
"
|
||||
);
|
||||
|
@ -1,4 +1,5 @@
|
||||
use crate::config::{GlobalPassOption, JscTarget, ModuleConfig};
|
||||
use compat::es2020::export_namespace_from;
|
||||
use either::Either;
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
use swc_atoms::JsWord;
|
||||
@ -176,6 +177,7 @@ impl<'a, 'b, P: swc_ecma_visit::Fold> PassBuilder<'a, 'b, P> {
|
||||
self.pass,
|
||||
compat_pass,
|
||||
compat::reserved_words::reserved_words(),
|
||||
Optional::new(export_namespace_from(), need_interop_analysis),
|
||||
// module / helper
|
||||
Optional::new(
|
||||
modules::import_analysis::import_analyzer(),
|
||||
|
@ -1,80 +0,0 @@
|
||||
use swc_common::Span;
|
||||
use swc_ecma_codegen::{text_writer::WriteJs, Result};
|
||||
use swc_ecma_parser::JscTarget;
|
||||
|
||||
pub(crate) struct WriterWapper<W>
|
||||
where
|
||||
W: WriteJs,
|
||||
{
|
||||
pub target: JscTarget,
|
||||
pub inner: W,
|
||||
}
|
||||
|
||||
impl<W> WriteJs for WriterWapper<W>
|
||||
where
|
||||
W: WriteJs,
|
||||
{
|
||||
fn increase_indent(&mut self) -> Result {
|
||||
self.inner.increase_indent()
|
||||
}
|
||||
|
||||
fn decrease_indent(&mut self) -> Result {
|
||||
self.inner.decrease_indent()
|
||||
}
|
||||
|
||||
fn write_semi(&mut self) -> Result {
|
||||
self.inner.write_semi()
|
||||
}
|
||||
|
||||
fn write_space(&mut self) -> Result {
|
||||
self.inner.write_space()
|
||||
}
|
||||
|
||||
fn write_keyword(&mut self, span: Option<Span>, s: &'static str) -> Result {
|
||||
self.inner.write_keyword(span, s)
|
||||
}
|
||||
|
||||
fn write_operator(&mut self, s: &str) -> Result {
|
||||
self.inner.write_operator(s)
|
||||
}
|
||||
|
||||
fn write_param(&mut self, s: &str) -> Result {
|
||||
self.inner.write_param(s)
|
||||
}
|
||||
|
||||
fn write_property(&mut self, s: &str) -> Result {
|
||||
self.inner.write_property(s)
|
||||
}
|
||||
|
||||
fn write_line(&mut self) -> Result {
|
||||
self.inner.write_line()
|
||||
}
|
||||
|
||||
fn write_lit(&mut self, span: Span, s: &str) -> Result {
|
||||
self.inner.write_lit(span, s)
|
||||
}
|
||||
|
||||
fn write_comment(&mut self, span: Span, s: &str) -> Result {
|
||||
self.inner.write_comment(span, s)
|
||||
}
|
||||
|
||||
fn write_str_lit(&mut self, span: Span, s: &str) -> Result {
|
||||
self.inner.write_str_lit(span, s)
|
||||
}
|
||||
|
||||
fn write_str(&mut self, s: &str) -> Result {
|
||||
self.inner.write_str(s)
|
||||
}
|
||||
|
||||
fn write_symbol(&mut self, span: Span, s: &str) -> Result {
|
||||
self.inner.write_symbol(span, s)
|
||||
}
|
||||
|
||||
fn write_punct(&mut self, s: &'static str) -> Result {
|
||||
self.inner.write_punct(s)
|
||||
}
|
||||
|
||||
fn target(&self) -> JscTarget {
|
||||
self.target
|
||||
}
|
||||
}
|
23
src/lib.rs
23
src/lib.rs
@ -33,7 +33,6 @@ use swc_ecma_transforms::{
|
||||
use swc_ecma_visit::FoldWith;
|
||||
|
||||
mod builder;
|
||||
mod codegen;
|
||||
pub mod config;
|
||||
|
||||
pub struct Compiler {
|
||||
@ -207,19 +206,17 @@ impl Compiler {
|
||||
cfg: swc_ecma_codegen::Config { minify },
|
||||
comments: if minify { None } else { Some(&self.comments) },
|
||||
cm: self.cm.clone(),
|
||||
wr: Box::new(self::codegen::WriterWapper {
|
||||
wr: Box::new(swc_ecma_codegen::text_writer::JsWriter::with_target(
|
||||
self.cm.clone(),
|
||||
"\n",
|
||||
&mut buf,
|
||||
if source_map.enabled() {
|
||||
Some(&mut src_map_buf)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
target,
|
||||
inner: swc_ecma_codegen::text_writer::JsWriter::new(
|
||||
self.cm.clone(),
|
||||
"\n",
|
||||
&mut buf,
|
||||
if source_map.enabled() {
|
||||
Some(&mut src_map_buf)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
),
|
||||
}),
|
||||
)),
|
||||
};
|
||||
|
||||
node.emit_with(&mut emitter)
|
||||
|
@ -3,5 +3,5 @@ Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = void 0;
|
||||
var _default = "\nvoid main() {\n gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}\n";
|
||||
var _default = "\nvoid main() {\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}\n";
|
||||
exports.default = _default;
|
||||
|
File diff suppressed because one or more lines are too long
5
tests/fixture/issue-1227/case-1/input/.swcrc
Normal file
5
tests/fixture/issue-1227/case-1/input/.swcrc
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"jsc": {
|
||||
"target": "es5"
|
||||
}
|
||||
}
|
1
tests/fixture/issue-1227/case-1/input/index.js
Normal file
1
tests/fixture/issue-1227/case-1/input/index.js
Normal file
@ -0,0 +1 @@
|
||||
const foo = "\u{a0}";
|
1
tests/fixture/issue-1227/case-1/output/index.js
Normal file
1
tests/fixture/issue-1227/case-1/output/index.js
Normal file
@ -0,0 +1 @@
|
||||
var foo = "\xa0";
|
@ -1,5 +1,5 @@
|
||||
function Component() {
|
||||
return React.createElement("div", {
|
||||
name: "A\n B"
|
||||
name: "A\n\n B"
|
||||
});
|
||||
}
|
||||
|
@ -1,2 +1,2 @@
|
||||
var a = "\/\/";
|
||||
var a = "//";
|
||||
console.log(a);
|
||||
|
8
tests/fixture/issue-1306-1/input/.swcrc
Normal file
8
tests/fixture/issue-1306-1/input/.swcrc
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"jsc": {
|
||||
"parser": {
|
||||
"syntax": "typescript"
|
||||
},
|
||||
"target": "es5"
|
||||
}
|
||||
}
|
11
tests/fixture/issue-1306-1/input/index.ts
Normal file
11
tests/fixture/issue-1306-1/input/index.ts
Normal file
@ -0,0 +1,11 @@
|
||||
class Animal {
|
||||
readonly #name: string
|
||||
|
||||
constructor(name: string) {
|
||||
this.#name = name
|
||||
}
|
||||
|
||||
public noise() {
|
||||
return this.#name.toUpperCase()
|
||||
}
|
||||
}
|
57
tests/fixture/issue-1306-1/output/index.ts
Normal file
57
tests/fixture/issue-1306-1/output/index.ts
Normal file
@ -0,0 +1,57 @@
|
||||
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 _classPrivateFieldSet(receiver, privateMap, value) {
|
||||
if (!privateMap.has(receiver)) {
|
||||
throw new TypeError("attempted to set private field on non-instance");
|
||||
}
|
||||
var descriptor = privateMap.get(receiver);
|
||||
if (!descriptor.writable) {
|
||||
throw new TypeError("attempted to set read only private field");
|
||||
}
|
||||
descriptor.value = value;
|
||||
return value;
|
||||
}
|
||||
function _defineProperties(target, props) {
|
||||
for(var i = 0; i < props.length; i++){
|
||||
var descriptor = props[i];
|
||||
descriptor.enumerable = descriptor.enumerable || false;
|
||||
descriptor.configurable = true;
|
||||
if ("value" in descriptor) descriptor.writable = true;
|
||||
Object.defineProperty(target, descriptor.key, descriptor);
|
||||
}
|
||||
}
|
||||
function _createClass(Constructor, protoProps, staticProps) {
|
||||
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
|
||||
if (staticProps) _defineProperties(Constructor, staticProps);
|
||||
return Constructor;
|
||||
}
|
||||
var Animal = function() {
|
||||
"use strict";
|
||||
function Animal(name) {
|
||||
_classCallCheck(this, Animal);
|
||||
_name.set(this, {
|
||||
writable: true,
|
||||
value: void 0
|
||||
});
|
||||
_classPrivateFieldSet(this, _name, name);
|
||||
}
|
||||
_createClass(Animal, [
|
||||
{
|
||||
key: "noise",
|
||||
value: function noise() {
|
||||
return _classPrivateFieldGet(this, _name).toUpperCase();
|
||||
}
|
||||
}
|
||||
]);
|
||||
return Animal;
|
||||
}();
|
||||
var _name = new WeakMap();
|
8
tests/fixture/issue-1306-2/input/.swcrc
Normal file
8
tests/fixture/issue-1306-2/input/.swcrc
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"jsc": {
|
||||
"parser": {
|
||||
"syntax": "ecmascript"
|
||||
},
|
||||
"target": "es5"
|
||||
}
|
||||
}
|
11
tests/fixture/issue-1306-2/input/index.js
Normal file
11
tests/fixture/issue-1306-2/input/index.js
Normal file
@ -0,0 +1,11 @@
|
||||
class Animal {
|
||||
#name;
|
||||
|
||||
constructor(name) {
|
||||
this.#name = name
|
||||
}
|
||||
|
||||
noise() {
|
||||
return this.#name.toUpperCase()
|
||||
}
|
||||
}
|
57
tests/fixture/issue-1306-2/output/index.js
Normal file
57
tests/fixture/issue-1306-2/output/index.js
Normal file
@ -0,0 +1,57 @@
|
||||
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 _classPrivateFieldSet(receiver, privateMap, value) {
|
||||
if (!privateMap.has(receiver)) {
|
||||
throw new TypeError("attempted to set private field on non-instance");
|
||||
}
|
||||
var descriptor = privateMap.get(receiver);
|
||||
if (!descriptor.writable) {
|
||||
throw new TypeError("attempted to set read only private field");
|
||||
}
|
||||
descriptor.value = value;
|
||||
return value;
|
||||
}
|
||||
function _defineProperties(target, props) {
|
||||
for(var i = 0; i < props.length; i++){
|
||||
var descriptor = props[i];
|
||||
descriptor.enumerable = descriptor.enumerable || false;
|
||||
descriptor.configurable = true;
|
||||
if ("value" in descriptor) descriptor.writable = true;
|
||||
Object.defineProperty(target, descriptor.key, descriptor);
|
||||
}
|
||||
}
|
||||
function _createClass(Constructor, protoProps, staticProps) {
|
||||
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
|
||||
if (staticProps) _defineProperties(Constructor, staticProps);
|
||||
return Constructor;
|
||||
}
|
||||
var Animal = function() {
|
||||
"use strict";
|
||||
function Animal(name) {
|
||||
_classCallCheck(this, Animal);
|
||||
_name.set(this, {
|
||||
writable: true,
|
||||
value: void 0
|
||||
});
|
||||
_classPrivateFieldSet(this, _name, name);
|
||||
}
|
||||
_createClass(Animal, [
|
||||
{
|
||||
key: "noise",
|
||||
value: function noise() {
|
||||
return _classPrivateFieldGet(this, _name).toUpperCase();
|
||||
}
|
||||
}
|
||||
]);
|
||||
return Animal;
|
||||
}();
|
||||
var _name = new WeakMap();
|
21
tests/fixture/issue-1307/input/.swcrc
Normal file
21
tests/fixture/issue-1307/input/.swcrc
Normal file
@ -0,0 +1,21 @@
|
||||
{
|
||||
"exclude": ".*.test.ts$",
|
||||
"jsc": {
|
||||
"parser": {
|
||||
"syntax": "typescript",
|
||||
"tsx": false,
|
||||
"decorators": false,
|
||||
"dynamicImport": true
|
||||
},
|
||||
"target": "es2020",
|
||||
"loose": true
|
||||
},
|
||||
"module": {
|
||||
"type": "commonjs",
|
||||
"strict": false,
|
||||
"strictMode": true,
|
||||
"lazy": false,
|
||||
"noInterop": false
|
||||
},
|
||||
"minify": false
|
||||
}
|
1
tests/fixture/issue-1307/input/index.ts
Normal file
1
tests/fixture/issue-1307/input/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * as foo from "./foo";
|
30
tests/fixture/issue-1307/output/index.ts
Normal file
30
tests/fixture/issue-1307/output/index.ts
Normal file
@ -0,0 +1,30 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.foo = void 0;
|
||||
var _foo = _interopRequireWildcard(require("./foo"));
|
||||
function _interopRequireWildcard(obj) {
|
||||
if (obj && obj.__esModule) {
|
||||
return obj;
|
||||
} else {
|
||||
var newObj = {
|
||||
};
|
||||
if (obj != null) {
|
||||
for(var key in obj){
|
||||
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
||||
var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {
|
||||
};
|
||||
if (desc.get || desc.set) {
|
||||
Object.defineProperty(newObj, key, desc);
|
||||
} else {
|
||||
newObj[key] = obj[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
newObj.default = obj;
|
||||
return newObj;
|
||||
}
|
||||
}
|
||||
exports.foo = _foo;
|
16
tests/fixture/issue-1314/input/.swcrc
Normal file
16
tests/fixture/issue-1314/input/.swcrc
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"jsc": {
|
||||
"target": "es2015",
|
||||
"parser": {
|
||||
"syntax": "ecmascript",
|
||||
"privateMethod": false,
|
||||
"functionBind": false,
|
||||
"exportDefaultFrom": false,
|
||||
"exportNamespaceFrom": false,
|
||||
"decorators": false,
|
||||
"decoratorsBeforeExport": false,
|
||||
"topLevelAwait": false,
|
||||
"importMeta": false
|
||||
}
|
||||
}
|
||||
}
|
11
tests/fixture/issue-1314/input/index.js
Normal file
11
tests/fixture/issue-1314/input/index.js
Normal file
@ -0,0 +1,11 @@
|
||||
const a = {
|
||||
method() {
|
||||
const string = `
|
||||
width: ${Math.abs(this.currentX - this.startX - left)}px;
|
||||
height: ${Math.abs(this.currentY - this.realtimeStartY - top)}px;
|
||||
top: ${Math.min(this.currentY - top, this.realtimeStartY) + this.scrollTop}px;
|
||||
left: ${Math.min(this.currentX - left, this.startX) + this.scrollLeft}px
|
||||
`;
|
||||
|
||||
}
|
||||
}
|
5
tests/fixture/issue-1314/output/index.js
Normal file
5
tests/fixture/issue-1314/output/index.js
Normal file
@ -0,0 +1,5 @@
|
||||
var a = {
|
||||
method: function() {
|
||||
var string = "\n width: ".concat(Math.abs(this.currentX - this.startX - left), "px;\n height: ").concat(Math.abs(this.currentY - this.realtimeStartY - top), "px;\n top: ").concat(Math.min(this.currentY - top, this.realtimeStartY) + this.scrollTop, "px;\n left: ").concat(Math.min(this.currentX - left, this.startX) + this.scrollLeft, "px\n ");
|
||||
}
|
||||
};
|
Loading…
Reference in New Issue
Block a user