fix(es/minifier): Fix minifier using Deno test suite (#2503)

swc_ecma_codegen:
 - Emit `;` after private class properties.

swc_ecma_minifier:
 - `pure`: Drop more invalid expressions.
 - `sequences`: Drop more invalid expressions.
 - `strings`: Fix concat.
 - `inline`: Inline into `b` in `a[b] = foo`.
This commit is contained in:
Donny/강동윤 2021-10-21 20:56:48 +09:00 committed by GitHub
parent a9869e60f2
commit 9e215769cc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
73 changed files with 317 additions and 355 deletions

7
Cargo.lock generated
View File

@ -2456,6 +2456,7 @@ dependencies = [
"swc_ecma_ast",
"swc_ecma_codegen",
"swc_ecma_loader",
"swc_ecma_minifier",
"swc_ecma_parser",
"swc_ecma_transforms_base",
"swc_ecma_transforms_optimization",
@ -2601,7 +2602,7 @@ dependencies = [
[[package]]
name = "swc_ecma_codegen"
version = "0.77.1"
version = "0.77.2"
dependencies = [
"bitflags",
"memchr",
@ -2678,7 +2679,7 @@ dependencies = [
[[package]]
name = "swc_ecma_minifier"
version = "0.44.3"
version = "0.44.4"
dependencies = [
"ansi_term 0.12.1",
"anyhow",
@ -3536,7 +3537,7 @@ checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
[[package]]
name = "wasm"
version = "1.2.102"
version = "1.2.103"
dependencies = [
"anyhow",
"console_error_panic_hook",

View File

@ -55,6 +55,7 @@ path-clean = "=0.1.0"
reqwest = {version = "0.11.4", features = ["blocking"]}
sha-1 = "0.9"
swc_ecma_loader = {version = "0.22.0", path = "../ecmascript/loader", features = ["node", "lru"]}
swc_ecma_minifier = {version = "0.44.3", path = "../ecmascript/minifier"}
swc_ecma_transforms_react = {version = "0.53.0", path = "../ecmascript/transforms/react"}
swc_ecma_transforms_typescript = {version = "0.54.0", path = "../ecmascript/transforms/typescript"}
swc_node_base = {version = "0.5.0", path = "../node/base"}

View File

@ -1,5 +0,0 @@
#!/usr/bin/env bash
export CI=1
cargo test --test fixture
cargo test --test deno

7
bundler/scripts/minifier.sh Executable file
View File

@ -0,0 +1,7 @@
#!/usr/bin/env bash
set -eu
export RUST_LOG=swc_ecma_minifier=debug
export RUST_BACKTRACE=1
cargo test --features swc_ecma_minifier/debug --test deno $@

View File

@ -14,11 +14,15 @@ use std::{
};
use swc_atoms::js_word;
use swc_bundler::{Bundler, Load, ModuleRecord};
use swc_common::{collections::AHashSet, FileName, Span, GLOBALS};
use swc_common::{collections::AHashSet, FileName, Mark, Span, GLOBALS};
use swc_ecma_ast::*;
use swc_ecma_codegen::{text_writer::JsWriter, Emitter};
use swc_ecma_codegen::{
text_writer::{omit_trailing_semi, JsWriter, WriteJs},
Emitter,
};
use swc_ecma_transforms_base::{fixer::fixer, resolver::resolver_with_mark};
use swc_ecma_utils::{find_ids, Id};
use swc_ecma_visit::{Node, Visit, VisitWith};
use swc_ecma_visit::{Node, Visit, VisitMutWith, VisitWith};
use testing::assert_eq;
#[path = "common/mod.rs"]
@ -978,7 +982,7 @@ fn run(url: &str, exports: &[&str]) {
let path = dir.path().join("main.js");
// println!("{}", path.display());
let src = bundle(url);
let src = bundle(url, false);
write(&path, &src).unwrap();
::testing::run_test2(false, |cm, _| {
@ -1017,7 +1021,7 @@ fn run(url: &str, exports: &[&str]) {
assert!(output.success());
}
fn bundle(url: &str) -> String {
fn bundle(url: &str, minify: bool) -> String {
let result = testing::run_test2(false, |cm, _handler| {
GLOBALS.with(|globals| {
let mut bundler = Bundler::new(
@ -1042,15 +1046,42 @@ fn bundle(url: &str) -> String {
},
);
let output = bundler.bundle(entries).unwrap();
let module = output.into_iter().next().unwrap().module;
let mut module = output.into_iter().next().unwrap().module;
if minify {
let top_level_mark = Mark::fresh(Mark::root());
module.visit_mut_with(&mut resolver_with_mark(top_level_mark));
module = swc_ecma_minifier::optimize(
module,
cm.clone(),
None,
None,
&swc_ecma_minifier::option::MinifyOptions {
compress: Some(Default::default()),
mangle: Some(Default::default()),
..Default::default()
},
&swc_ecma_minifier::option::ExtraOptions { top_level_mark },
);
module.visit_mut_with(&mut fixer(None));
}
let mut buf = vec![];
{
let mut wr: Box<dyn WriteJs> =
Box::new(JsWriter::new(cm.clone(), "\n", &mut buf, None));
if minify {
wr = Box::new(omit_trailing_semi(wr));
}
Emitter {
cfg: swc_ecma_codegen::Config { minify: false },
cfg: swc_ecma_codegen::Config { minify },
cm: cm.clone(),
comments: None,
wr: Box::new(JsWriter::new(cm.clone(), "\n", &mut buf, None)),
wr,
}
.emit_module(&module)
.unwrap();
@ -1166,7 +1197,38 @@ fn exec(input: PathBuf) {
let path = dir.path().join("main.js");
println!("{}", path.display());
let src = bundle(&input.to_string_lossy());
let src = bundle(&input.to_string_lossy(), false);
write(&path, &src).unwrap();
// println!("{}", src);
let output = Command::new("deno")
.arg("run")
.arg("--no-check")
.arg("--allow-net")
.arg(&path)
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.status()
.unwrap();
std::mem::forget(dir);
assert!(output.success());
}
#[testing::fixture("tests/deno-exec/**/entry.ts")]
fn exec_minified(input: PathBuf) {
// TODO: Fix the bug.
if input.to_string_lossy().contains("deno-9464") {
return;
}
let dir = tempfile::tempdir().expect("failed to crate temp file");
let path = dir.path().join("main.js");
println!("{}", path.display());
let src = bundle(&input.to_string_lossy(), true);
write(&path, &src).unwrap();
// println!("{}", src);

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.77.1"
version = "0.77.2"
[dependencies]
bitflags = "1"

View File

@ -1189,7 +1189,7 @@ where
}
}
formatting_semi!();
semi!();
}
#[emitter]

View File

@ -7,7 +7,7 @@ include = ["Cargo.toml", "src/**/*.rs", "src/lists/*.json"]
license = "Apache-2.0/MIT"
name = "swc_ecma_minifier"
repository = "https://github.com/swc-project/swc.git"
version = "0.44.3"
version = "0.44.4"
[features]
debug = ["backtrace"]

View File

@ -27,7 +27,7 @@ where
return;
}
if self.ctx.is_delete_arg || self.ctx.is_update_arg || self.ctx.in_lhs_of_assign {
if self.ctx.is_delete_arg || self.ctx.is_update_arg || self.ctx.is_lhs_of_assign {
return;
}
@ -92,7 +92,7 @@ where
return;
}
if self.ctx.is_delete_arg || self.ctx.is_update_arg || self.ctx.in_lhs_of_assign {
if self.ctx.is_delete_arg || self.ctx.is_update_arg || self.ctx.is_lhs_of_assign {
return;
}
@ -307,7 +307,7 @@ where
return;
}
if self.ctx.is_delete_arg || self.ctx.is_update_arg || self.ctx.in_lhs_of_assign {
if self.ctx.is_delete_arg || self.ctx.is_update_arg || self.ctx.is_lhs_of_assign {
return;
}

View File

@ -93,16 +93,18 @@ where
match &p.key {
PropName::Str(s) => {
tracing::trace!(
"hoist_props: Storing a varaible to inline \
properties"
"hoist_props: Storing a variable (`{}`) to inline \
properties",
name.id
);
self.simple_props
.insert((name.to_id(), s.value.clone()), value);
}
PropName::Ident(i) => {
tracing::trace!(
"hoist_props: Storing a varaible to inline \
properties"
"hoist_props: Storing a variable(`{}`) to inline \
properties",
name.id
);
self.simple_props
.insert((name.to_id(), i.sym.clone()), value);

View File

@ -554,7 +554,7 @@ where
{
match &*value {
Expr::Lit(Lit::Num(..)) => {
if self.ctx.in_lhs_of_assign {
if self.ctx.is_lhs_of_assign {
return;
}
}

View File

@ -63,7 +63,7 @@ where
///
/// - `while(false) { var a; foo() }` => `var a;`
pub(super) fn optiimze_loops_if_cond_is_false(&mut self, stmt: &mut Stmt) {
pub(super) fn optimize_loops_if_cond_is_false(&mut self, stmt: &mut Stmt) {
if !self.options.loops {
return;
}

View File

@ -4,7 +4,7 @@ use self::util::MultiReplacer;
use crate::{
analyzer::{ProgramData, UsageAnalyzer},
compress::util::is_pure_undefined,
debug::dump,
debug::{dump, AssertValid},
marks::Marks,
mode::Mode,
option::CompressOptions,
@ -126,7 +126,7 @@ struct Ctx {
is_delete_arg: bool,
/// `true` if we are in `arg` of `++arg` or `--arg`.
is_update_arg: bool,
in_lhs_of_assign: bool,
is_lhs_of_assign: bool,
/// `false` for `d` in `d[0] = foo`.
is_exact_lhs_of_assign: bool,
@ -685,6 +685,15 @@ where
self.changed = true;
return None;
}
Expr::Tpl(t) if t.exprs.is_empty() => {
if cfg!(feature = "debug") {
tracing::debug!("ignore_return_value: Dropping tpl expr without expr");
}
self.changed = true;
return None;
}
// Function expression cannot have a side effect.
Expr::Fn(_) => {
tracing::debug!(
@ -1527,7 +1536,7 @@ where
fn visit_mut_assign_expr(&mut self, e: &mut AssignExpr) {
{
let ctx = Ctx {
in_lhs_of_assign: true,
is_lhs_of_assign: true,
is_exact_lhs_of_assign: true,
..self.ctx
};
@ -1888,6 +1897,10 @@ where
}
}
}
if cfg!(feature = "debug") && cfg!(debug_assertions) {
n.visit_with(&Invalid { span: DUMMY_SP }, &mut AssertValid);
}
}
fn visit_mut_fn_decl(&mut self, f: &mut FnDecl) {
@ -1997,6 +2010,10 @@ where
}
self.ctx.in_asm = old_in_asm;
if cfg!(feature = "debug") && cfg!(debug_assertions) {
n.visit_with(&Invalid { span: DUMMY_SP }, &mut AssertValid);
}
}
fn visit_mut_if_stmt(&mut self, n: &mut IfStmt) {
@ -2041,6 +2058,7 @@ where
if n.computed {
let ctx = Ctx {
is_exact_lhs_of_assign: false,
is_lhs_of_assign: false,
..self.ctx
};
n.prop.visit_mut_with(&mut *self.with_ctx(ctx));
@ -2149,6 +2167,10 @@ where
}
_ => {}
}
if cfg!(feature = "debug") && cfg!(debug_assertions) {
n.visit_with(&Invalid { span: DUMMY_SP }, &mut AssertValid);
}
}
fn visit_mut_return_stmt(&mut self, n: &mut ReturnStmt) {
@ -2241,7 +2263,7 @@ where
is_callee: false,
is_delete_arg: false,
is_update_arg: false,
in_lhs_of_assign: false,
is_lhs_of_assign: false,
in_bang_arg: false,
is_exported: false,
in_obj_of_non_computed_member: false,
@ -2299,11 +2321,11 @@ where
_ => {}
}
self.optiimze_loops_if_cond_is_false(s);
self.optimize_loops_if_cond_is_false(s);
self.optimize_loops_with_break(s);
match s {
// We use var devl with no declarator to indicate we dropped an decl.
// We use var decl with no declarator to indicate we dropped an decl.
Stmt::Decl(Decl::Var(VarDecl { decls, .. })) if decls.is_empty() => {
*s = Stmt::Empty(EmptyStmt { span: DUMMY_SP });
return;
@ -2332,6 +2354,10 @@ where
tracing::debug!("after: visit_mut_stmt: {}", text);
}
}
if cfg!(feature = "debug") && cfg!(debug_assertions) {
s.visit_with(&Invalid { span: DUMMY_SP }, &mut AssertValid);
}
}
fn visit_mut_stmts(&mut self, stmts: &mut Vec<Stmt>) {
@ -2364,6 +2390,10 @@ where
_ => {}
}
}
if cfg!(feature = "debug") && cfg!(debug_assertions) {
stmts.visit_with(&Invalid { span: DUMMY_SP }, &mut AssertValid);
}
}
fn visit_mut_str(&mut self, s: &mut Str) {

View File

@ -695,17 +695,30 @@ where
let _ = self.merge_sequences_in_exprs(&mut exprs);
}
stmts.retain_mut(|stmt| match stmt.as_stmt_mut() {
Some(Stmt::Decl(Decl::Var(v))) => {
v.decls.retain(|decl| match decl.init.as_deref() {
Some(Expr::Invalid(..)) => false,
_ => true,
});
!v.decls.is_empty()
stmts.retain_mut(|stmt| {
match stmt.as_stmt_mut() {
Some(Stmt::Expr(es)) => match &mut *es.expr {
Expr::Seq(e) => {
e.exprs.retain(|e| !e.is_invalid());
}
_ => {}
},
_ => {}
}
match stmt.as_stmt_mut() {
Some(Stmt::Decl(Decl::Var(v))) => {
v.decls.retain(|decl| match decl.init.as_deref() {
Some(Expr::Invalid(..)) => false,
_ => true,
});
!v.decls.is_empty()
}
Some(Stmt::Expr(s)) if s.expr.is_invalid() => false,
_ => true,
}
Some(Stmt::Expr(s)) if s.expr.is_invalid() => false,
_ => true,
});
}

View File

@ -1,11 +1,32 @@
use super::Pure;
use crate::{compress::util::is_pure_undefined, mode::Mode};
use swc_common::util::take::Take;
use swc_ecma_ast::*;
impl<M> Pure<'_, M>
where
M: Mode,
{
pub(super) fn remove_invalid(&mut self, e: &mut Expr) {
match e {
Expr::Bin(BinExpr { left, right, .. }) => {
self.remove_invalid(left);
self.remove_invalid(right);
if left.is_invalid() {
*e = *right.take();
self.remove_invalid(e);
return;
} else if right.is_invalid() {
*e = *left.take();
self.remove_invalid(e);
return;
}
}
_ => {}
}
}
pub(super) fn drop_undefined_from_return_arg(&mut self, s: &mut ReturnStmt) {
match s.arg.as_deref() {
Some(e) => {

View File

@ -1,6 +1,10 @@
use self::ctx::Ctx;
use crate::{
debug::dump, marks::Marks, mode::Mode, option::CompressOptions, util::ModuleItemExt,
debug::{dump, AssertValid},
marks::Marks,
mode::Mode,
option::CompressOptions,
util::ModuleItemExt,
MAX_PAR_DEPTH,
};
use rayon::prelude::*;
@ -219,6 +223,8 @@ where
e.visit_mut_children_with(&mut *self.with_ctx(ctx));
}
self.remove_invalid(e);
match e {
Expr::Seq(seq) => {
if seq.exprs.is_empty() {
@ -386,6 +392,10 @@ where
p.visit_mut_children_with(self);
self.optimize_arrow_method_prop(p);
if cfg!(feature = "debug") && cfg!(debug_assertions) {
p.visit_with(&Invalid { span: DUMMY_SP }, &mut AssertValid);
}
}
fn visit_mut_prop_name(&mut self, p: &mut PropName) {
@ -408,6 +418,16 @@ where
fn visit_mut_seq_expr(&mut self, e: &mut SeqExpr) {
e.visit_mut_children_with(self);
e.exprs.retain(|e| {
if e.is_invalid() {
self.changed = true;
tracing::debug!("Removing invalid expr in seq");
return false;
}
true
});
if e.exprs.len() == 0 {
return;
}
@ -488,6 +508,10 @@ where
tracing::debug!("after: visit_mut_stmt: {}", text);
}
}
if cfg!(feature = "debug") && cfg!(debug_assertions) {
s.visit_with(&Invalid { span: DUMMY_SP }, &mut AssertValid);
}
}
fn visit_mut_stmts(&mut self, items: &mut Vec<Stmt>) {
@ -499,6 +523,10 @@ where
Stmt::Empty(..) => false,
_ => true,
});
if cfg!(feature = "debug") && cfg!(debug_assertions) {
items.visit_with(&Invalid { span: DUMMY_SP }, &mut AssertValid);
}
}
/// We don't optimize [Tpl] contained in [TaggedTpl].

View File

@ -14,14 +14,27 @@ where
pub(super) fn convert_tpl_to_str(&mut self, e: &mut Expr) {
match e {
Expr::Tpl(t) if t.quasis.len() == 1 && t.exprs.is_empty() => {
if let Some(c) = &t.quasis[0].cooked {
if c.value.chars().all(|c| match c {
'\u{0020}'..='\u{007e}' => true,
'\n' | '\r' => M::force_str_for_tpl(),
_ => false,
}) {
*e = Expr::Lit(Lit::Str(c.clone()));
}
let c = &t.quasis[0].raw;
if c.value.chars().all(|c| match c {
'\u{0020}'..='\u{007e}' => true,
'\n' | '\r' => M::force_str_for_tpl(),
_ => false,
}) && (M::force_str_for_tpl()
|| (!c.value.contains("\\n") && !c.value.contains("\\r")))
&& !c.value.contains("\\0")
{
*e = Expr::Lit(Lit::Str(Str {
value: c
.value
.replace("\\`", "`")
.replace("\\$", "$")
.replace("\\n", "\n")
.replace("\\r", "\r")
.replace("\\\\", "\\")
.into(),
..c.clone()
}));
}
}
_ => {}
@ -43,9 +56,12 @@ where
return;
}
if cfg!(feature = "debug") {
tracing::debug!("compress_tpl");
}
let mut quasis = vec![];
let mut exprs = vec![];
let mut cur = String::new();
let mut cur_raw = String::new();
for i in 0..(tpl.exprs.len() + tpl.quasis.len()) {
@ -53,7 +69,6 @@ where
let i = i / 2;
let q = tpl.quasis[i].take();
cur.push_str(&q.cooked.unwrap().value);
cur_raw.push_str(&q.raw.value);
} else {
let i = i / 2;
@ -61,19 +76,13 @@ where
match *e {
Expr::Lit(Lit::Str(s)) => {
cur.push_str(&s.value);
cur_raw.push_str(&s.value);
}
_ => {
quasis.push(TplElement {
span: DUMMY_SP,
tail: true,
cooked: Some(Str {
span: DUMMY_SP,
value: take(&mut cur).into(),
has_escape: false,
kind: Default::default(),
}),
cooked: None,
raw: Str {
span: DUMMY_SP,
value: take(&mut cur_raw).into(),
@ -91,12 +100,7 @@ where
quasis.push(TplElement {
span: DUMMY_SP,
tail: true,
cooked: Some(Str {
span: DUMMY_SP,
value: cur.into(),
has_escape: false,
kind: Default::default(),
}),
cooked: None,
raw: Str {
span: DUMMY_SP,
value: cur_raw.into(),
@ -123,9 +127,10 @@ where
"template: Concatted a string (`{}`) on rhs of `+` to a template literal",
rs.value
);
let l_str = l_last.cooked.as_mut().unwrap();
let l_str = &mut l_last.raw;
let new: JsWord = format!("{}{}", l_str.value, rs.value).into();
let new: JsWord =
format!("{}{}", l_str.value, rs.value.replace("\\", "\\\\")).into();
l_str.value = new.clone();
l_last.raw.value = new;
@ -143,9 +148,10 @@ where
"template: Prepended a string (`{}`) on lhs of `+` to a template literal",
ls.value
);
let r_str = r_first.cooked.as_mut().unwrap();
let r_str = &mut r_first.raw;
let new: JsWord = format!("{}{}", ls.value, r_str.value).into();
let new: JsWord =
format!("{}{}", ls.value.replace("\\", "\\\\"), r_str.value).into();
r_str.value = new.clone();
r_first.raw.value = new;
@ -162,10 +168,9 @@ where
let l_last = l.quasis.pop().unwrap();
let mut r_first = rt.quasis.first_mut().unwrap();
let r_str = r_first.cooked.as_mut().unwrap();
let r_str = &mut r_first.raw;
let new: JsWord =
format!("{}{}", l_last.cooked.unwrap().value, r_str.value).into();
let new: JsWord = format!("{}{}", l_last.raw.value, r_str.value).into();
r_str.value = new.clone();
r_first.raw.value = new;
}

View File

@ -1,11 +1,13 @@
use once_cell::sync::Lazy;
use std::{env, process::Command};
use swc_common::{sync::Lrc, SourceMap, SyntaxContext};
use swc_ecma_ast::{Ident, Module, StrKind};
use swc_common::{sync::Lrc, SourceMap, SyntaxContext, DUMMY_SP};
use swc_ecma_ast::*;
use swc_ecma_codegen::{text_writer::JsWriter, Emitter};
use swc_ecma_transforms::{fixer, hygiene};
use swc_ecma_utils::{drop_span, DropSpan};
use swc_ecma_visit::{noop_visit_mut_type, FoldWith, VisitMut, VisitMutWith};
use swc_ecma_visit::{
noop_visit_mut_type, noop_visit_type, FoldWith, Node, Visit, VisitMut, VisitMutWith, VisitWith,
};
pub(crate) struct Debugger;
@ -62,6 +64,10 @@ pub(crate) fn invoke(module: &Module) {
static ENABLED: Lazy<bool> =
Lazy::new(|| cfg!(feature = "debug") && env::var("SWC_RUN").unwrap_or_default() == "1");
if cfg!(debug_assertions) {
module.visit_with(&Invalid { span: DUMMY_SP }, &mut AssertValid);
}
if !*ENABLED {
return;
}
@ -108,3 +114,23 @@ pub(crate) fn invoke(module: &Module) {
String::from_utf8_lossy(&output.stdout)
)
}
pub(crate) struct AssertValid;
impl Visit for AssertValid {
noop_visit_type!();
fn visit_invalid(&mut self, _: &Invalid, _: &dyn Node) {
panic!("[SWC_RUN] Invalid node found");
}
fn visit_setter_prop(&mut self, p: &SetterProp, _: &dyn Node) {
p.body.visit_with(p, self);
}
fn visit_tpl(&mut self, l: &Tpl, _: &dyn Node) {
l.visit_children_with(self);
assert_eq!(l.exprs.len() + 1, l.quasis.len());
}
}

View File

@ -1,13 +1,18 @@
use crate::debug::dump;
use std::fmt::Debug;
use swc_common::Mark;
use swc_ecma_ast::*;
use swc_ecma_transforms::fixer;
use swc_ecma_utils::DropSpan;
use swc_ecma_visit::{FoldWith, VisitMut, VisitMutWith};
/// Inidicates a unit of minifaction.
/// Indicates a unit of minifaction.
pub(crate) trait CompileUnit:
swc_ecma_codegen::Node + Clone + VisitMutWith<DropSpan> + VisitMutWith<crate::debug::Debugger>
swc_ecma_codegen::Node
+ Clone
+ VisitMutWith<DropSpan>
+ VisitMutWith<crate::debug::Debugger>
+ Debug
{
fn is_module() -> bool;

View File

@ -326,6 +326,14 @@ fn base_exec(input: PathBuf) {
testing::run_test2(false, |cm, handler| {
let input_src = read_to_string(&input).expect("failed to read input.js as a string");
let expected_output = stdout_of(&input_src).unwrap();
eprintln!(
"---- {} -----\n{}",
Color::Green.paint("Expected"),
expected_output
);
let output = run(cm.clone(), &handler, &input, &config, None);
let output = output.expect("Parsing in base test should not fail");
let output = print(cm.clone(), &[output], false);
@ -338,7 +346,6 @@ fn base_exec(input: PathBuf) {
println!("{}", input.display());
let expected_output = stdout_of(&input_src).unwrap();
let actual_output = stdout_of(&output).expect("failed to execute the optimized code");
assert_ne!(actual_output, "");

View File

@ -0,0 +1,3 @@
{
"defaults": true
}

View File

@ -0,0 +1,9 @@
function compile(attributePattern, flags) {
return new RegExp(`(?:^|;)\\s*${attributePattern}\\s*=\\s*` + `(` + `[^";\\s][^;\\s]*` + `|` + `"(?:[^"\\\\]|\\\\"?)+"?` + `)`, flags);
}
console.log(compile("foo", "g"));
console.log(compile("bar", "g"));
console.log(compile("baz", "g"));

View File

@ -1,3 +1,3 @@
var foo = `<\/script>${content}`;
var bar = "\x3c!--";
var baz = "--\x3e";
var bar = `\x3c!--`;
var baz = `--\x3e`;

View File

@ -0,0 +1,6 @@
error: Expression expected
--> $DIR/tests/typescript-errors/parserSuperExpression2/input.ts:3:10
|
3 | super<T>(0);
| ^

View File

@ -1,146 +0,0 @@
{
"type": "Script",
"span": {
"start": 0,
"end": 40,
"ctxt": 0
},
"body": [
{
"type": "ClassDeclaration",
"identifier": {
"type": "Identifier",
"span": {
"start": 6,
"end": 7,
"ctxt": 0
},
"value": "C",
"optional": false
},
"declare": false,
"span": {
"start": 0,
"end": 40,
"ctxt": 0
},
"decorators": [],
"body": [
{
"type": "ClassMethod",
"span": {
"start": 12,
"end": 38,
"ctxt": 0
},
"key": {
"type": "Identifier",
"span": {
"start": 12,
"end": 13,
"ctxt": 0
},
"value": "M",
"optional": false
},
"function": {
"params": [],
"decorators": [],
"span": {
"start": 12,
"end": 38,
"ctxt": 0
},
"body": {
"type": "BlockStatement",
"span": {
"start": 16,
"end": 38,
"ctxt": 0
},
"stmts": [
{
"type": "ExpressionStatement",
"span": {
"start": 22,
"end": 34,
"ctxt": 0
},
"expression": {
"type": "BinaryExpression",
"span": {
"start": 27,
"end": 33,
"ctxt": 0
},
"operator": ">",
"left": {
"type": "BinaryExpression",
"span": {
"start": 27,
"end": 29,
"ctxt": 0
},
"operator": "<",
"left": {
"type": "Invalid",
"span": {
"start": 27,
"end": 28,
"ctxt": 0
}
},
"right": {
"type": "Identifier",
"span": {
"start": 28,
"end": 29,
"ctxt": 0
},
"value": "T",
"optional": false
}
},
"right": {
"type": "ParenthesisExpression",
"span": {
"start": 30,
"end": 33,
"ctxt": 0
},
"expression": {
"type": "NumericLiteral",
"span": {
"start": 31,
"end": 32,
"ctxt": 0
},
"value": 0.0
}
}
}
}
]
},
"generator": false,
"async": false,
"typeParameters": null,
"returnType": null
},
"kind": "method",
"isStatic": false,
"accessibility": null,
"isAbstract": false,
"isOptional": false,
"isOverride": false
}
],
"superClass": null,
"isAbstract": false,
"typeParams": null,
"superTypeParams": null,
"implements": []
}
],
"interpreter": null
}

View File

@ -1,6 +1,6 @@
{
"name": "@swc/core",
"version": "1.2.102",
"version": "1.2.103",
"description": "Super-fast alternative for babel",
"homepage": "https://swc.rs",
"main": "./index.js",

View File

@ -1,8 +1,8 @@
var obj, key;
key = 0, 0 in (obj = {
var obj;
0 in (obj = {
}) ? Object.defineProperty(obj, 0, {
value: 0,
enumerable: !0,
configurable: !0,
writable: !0
}) : obj[key] = 0;
}) : obj[0] = 0;

View File

@ -1,8 +1,8 @@
var obj, key;
key = 0, 0 in (obj = {
var obj;
0 in (obj = {
}) ? Object.defineProperty(obj, 0, {
value: 0,
enumerable: !0,
configurable: !0,
writable: !0
}) : obj[key] = 0;
}) : obj[0] = 0;

View File

@ -1 +1 @@
`\u0009\u000B\u000C\u0020\u00A0\uFEFF`;
"\\u0009\\u000B\\u000C\\u0020\\u00A0\\uFEFF";

View File

@ -1 +1 @@
`\u0009\u000B\u000C\u0020\u00A0\uFEFF`;
"\\u0009\\u000B\\u000C\\u0020\\u00A0\\uFEFF";

View File

@ -1,34 +0,0 @@
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
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 C = /*#__PURE__*/ function() {
"use strict";
function C() {
_classCallCheck(this, C);
}
_createClass(C, [
{
key: "M",
value: function M() {
<invalid> < T > 0;
}
}
]);
return C;
}();

View File

@ -1,22 +0,0 @@
function _defineProperties(target, props) {
for(var i = 0; i < props.length; i++){
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || !1, descriptor.configurable = !0, "value" in descriptor && (descriptor.writable = !0), Object.defineProperty(target, descriptor.key, descriptor);
}
}
var C = function() {
"use strict";
var Constructor, protoProps, staticProps;
function C() {
!function(instance, Constructor) {
if (!(instance instanceof Constructor)) throw new TypeError("Cannot call a class as a function");
}(this, C);
}
return protoProps = [
{
key: "M",
value: function() {
}
}
], _defineProperties((Constructor = C).prototype, protoProps), staticProps && _defineProperties(Constructor, staticProps), C;
}();

View File

@ -1,3 +1,3 @@
({
})["21EC2020-3AEA-4069-A2DD-08002B30309D"] = 123, ({
})[void 0] = "hello", 12345..toPrecision(0);
})[12345] = "hello", 12345..toPrecision(0);

View File

@ -1,4 +1,3 @@
var serialNo;
({
})["21EC2020-3AEA-4069-A2DD-08002B30309D"] = 123, ({
})[serialNo] = "hello", 12345..toPrecision(0);
})[12345] = "hello", 12345..toPrecision(0);

View File

@ -6,7 +6,7 @@ license = "Apache-2.0 AND MIT"
name = "wasm"
publish = false
repository = "https://github.com/swc-project/swc.git"
version = "1.2.102"
version = "1.2.103"
[lib]
crate-type = ["cdylib"]