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:
강동윤 2021-01-14 21:56:25 +09:00 committed by GitHub
parent 6984217200
commit a9bf9bb9e1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 368 additions and 99 deletions

View File

@ -0,0 +1,2 @@
import axiod from 'https://deno.land/x/axiod/mod.ts';
console.log(axiod)

View File

@ -1,3 +1,4 @@
const a = import('./dep')
console.log(a)
console.log(a)

View File

@ -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));
}

View File

@ -105,4 +105,8 @@ where
fn write_punct(&mut self, s: &'static str) -> Result {
(**self).write_punct(s)
}
fn target(&self) -> JscTarget {
(**self).target()
}
}

View File

@ -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> {

View File

@ -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 {

View File

@ -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();
"
);

View File

@ -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(),

View File

@ -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
}
}

View File

@ -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)

View File

@ -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

View File

@ -0,0 +1,5 @@
{
"jsc": {
"target": "es5"
}
}

View File

@ -0,0 +1 @@
const foo = "\u{a0}";

View File

@ -0,0 +1 @@
var foo = "\xa0";

View File

@ -1,5 +1,5 @@
function Component() {
return React.createElement("div", {
name: "A\n B"
name: "A\n\n B"
});
}

View File

@ -1,2 +1,2 @@
var a = "\/\/";
var a = "//";
console.log(a);

View File

@ -0,0 +1,8 @@
{
"jsc": {
"parser": {
"syntax": "typescript"
},
"target": "es5"
}
}

View File

@ -0,0 +1,11 @@
class Animal {
readonly #name: string
constructor(name: string) {
this.#name = name
}
public noise() {
return this.#name.toUpperCase()
}
}

View 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();

View File

@ -0,0 +1,8 @@
{
"jsc": {
"parser": {
"syntax": "ecmascript"
},
"target": "es5"
}
}

View File

@ -0,0 +1,11 @@
class Animal {
#name;
constructor(name) {
this.#name = name
}
noise() {
return this.#name.toUpperCase()
}
}

View 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();

View 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
}

View File

@ -0,0 +1 @@
export * as foo from "./foo";

View 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;

View 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
}
}
}

View 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
`;
}
}

View 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 ");
}
};