feat(es/minifier): Support script fully (#6455)

This commit is contained in:
Alexander Akait 2022-11-17 09:00:42 +03:00 committed by GitHub
parent 7716f58303
commit 4d7b920bd4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 308 additions and 63 deletions

View File

@ -1150,6 +1150,14 @@ where
n.visit_children_with(&mut *self.with_ctx(ctx)) n.visit_children_with(&mut *self.with_ctx(ctx))
} }
fn visit_script(&mut self, n: &Script) {
let ctx = Ctx {
skip_standalone: true,
..self.ctx
};
n.visit_children_with(&mut *self.with_ctx(ctx))
}
fn visit_named_export(&mut self, n: &NamedExport) { fn visit_named_export(&mut self, n: &NamedExport) {
if n.src.is_some() { if n.src.is_some() {
return; return;

View File

@ -336,6 +336,10 @@ where
{ {
noop_visit_mut_type!(); noop_visit_mut_type!();
fn visit_mut_script(&mut self, n: &mut Script) {
self.optimize_unit_repeatedly(n);
}
fn visit_mut_module(&mut self, n: &mut Module) { fn visit_mut_module(&mut self, n: &mut Module) {
self.optimize_unit_repeatedly(n); self.optimize_unit_repeatedly(n);
} }

View File

@ -66,7 +66,7 @@ where
/// ///
/// If the cargo feature `debug` is disabled or the environment variable /// If the cargo feature `debug` is disabled or the environment variable
/// `SWC_RUN` is not `1`, this function is noop. /// `SWC_RUN` is not `1`, this function is noop.
pub(crate) fn invoke(module: &Module) { pub(crate) fn invoke_module(module: &Module) {
debug_assert_valid(module); debug_assert_valid(module);
let _noop_sub = tracing::subscriber::set_default(tracing::subscriber::NoSubscriber::default()); let _noop_sub = tracing::subscriber::set_default(tracing::subscriber::NoSubscriber::default());
@ -153,3 +153,94 @@ pub(crate) fn invoke(module: &Module) {
) )
} }
} }
/// Invokes code using node.js.
///
/// If the cargo feature `debug` is disabled or the environment variable
/// `SWC_RUN` is not `1`, this function is noop.
pub(crate) fn invoke_script(script: &Script) {
debug_assert_valid(script);
let _noop_sub = tracing::subscriber::set_default(tracing::subscriber::NoSubscriber::default());
let should_run =
cfg!(debug_assertions) && cfg!(feature = "debug") && option_env!("SWC_RUN") == Some("1");
let should_check = cfg!(debug_assertions) && option_env!("SWC_CHECK") == Some("1");
if !should_run && !should_check {
return;
}
let script = script
.clone()
.fold_with(&mut hygiene())
.fold_with(&mut fixer(None));
let script = drop_span(script);
let mut buf = vec![];
let cm = Lrc::new(SourceMap::default());
{
let mut emitter = Emitter {
cfg: Default::default(),
cm: cm.clone(),
comments: None,
wr: Box::new(JsWriter::new(cm, "\n", &mut buf, None)),
};
emitter.emit_script(&script).unwrap();
}
let code = String::from_utf8(buf).unwrap();
debug!("Validating with node.js:\n{}", code);
if should_check {
let mut child = Command::new("node")
.arg("-")
.arg("--check")
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.expect("failed to spawn node");
{
let child_stdin = child.stdin.as_mut().unwrap();
child_stdin
.write_all(code.as_bytes())
.expect("failed to write");
}
let output = child.wait_with_output().expect("failed to check syntax");
if !output.status.success() {
panic!(
"[SWC_CHECK] Failed to validate code:\n{}\n===== ===== ===== ===== =====\n{}\n{}",
code,
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr),
);
}
} else {
let output = Command::new("node")
.arg("-e")
.arg(&code)
.output()
.expect("[SWC_RUN] failed to validate code using `node`");
if !output.status.success() {
panic!(
"[SWC_RUN] Failed to validate code:\n{}\n===== ===== ===== ===== =====\n{}\n{}",
code,
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr),
);
}
tracing::info!(
"[SWC_RUN]\n{}\n{}",
code,
String::from_utf8_lossy(&output.stdout)
)
}
}

View File

@ -87,7 +87,7 @@ pub(crate) static HEAVY_TASK_PARALLELS: Lazy<usize> = Lazy::new(|| *CPU_COUNT *
pub(crate) static LIGHT_TASK_PARALLELS: Lazy<usize> = Lazy::new(|| *CPU_COUNT * 100); pub(crate) static LIGHT_TASK_PARALLELS: Lazy<usize> = Lazy::new(|| *CPU_COUNT * 100);
pub fn optimize( pub fn optimize(
mut m: Program, mut n: Program,
_cm: Lrc<SourceMap>, _cm: Lrc<SourceMap>,
comments: Option<&dyn Comments>, comments: Option<&dyn Comments>,
mut timings: Option<&mut Timings>, mut timings: Option<&mut Timings>,
@ -99,7 +99,7 @@ pub fn optimize(
let mut marks = Marks::new(); let mut marks = Marks::new();
marks.unresolved_mark = extra.unresolved_mark; marks.unresolved_mark = extra.unresolved_mark;
debug_assert_valid(&m); debug_assert_valid(&n);
if let Some(defs) = options.compress.as_ref().map(|c| &c.global_defs) { if let Some(defs) = options.compress.as_ref().map(|c| &c.global_defs) {
let _timer = timer!("inline global defs"); let _timer = timer!("inline global defs");
@ -111,7 +111,7 @@ pub fn optimize(
if !defs.is_empty() { if !defs.is_empty() {
let defs = defs.iter().map(|(k, v)| (k.clone(), v.clone())).collect(); let defs = defs.iter().map(|(k, v)| (k.clone(), v.clone())).collect();
m.visit_mut_with(&mut global_defs::globals_defs( n.visit_mut_with(&mut global_defs::globals_defs(
defs, defs,
extra.unresolved_mark, extra.unresolved_mark,
extra.top_level_mark, extra.top_level_mark,
@ -119,7 +119,7 @@ pub fn optimize(
} }
} }
let module_info = match &m { let module_info = match &n {
Program::Script(_) => ModuleInfo::default(), Program::Script(_) => ModuleInfo::default(),
Program::Module(m) => ModuleInfo { Program::Module(m) => ModuleInfo {
blackbox_imports: m blackbox_imports: m
@ -162,20 +162,20 @@ pub fn optimize(
if let Some(_options) = &options.compress { if let Some(_options) = &options.compress {
let _timer = timer!("precompress"); let _timer = timer!("precompress");
m.visit_mut_with(&mut precompress_optimizer()); n.visit_mut_with(&mut precompress_optimizer());
debug_assert_valid(&m); debug_assert_valid(&n);
} }
if options.compress.is_some() { if options.compress.is_some() {
m.visit_mut_with(&mut info_marker( n.visit_mut_with(&mut info_marker(
options.compress.as_ref(), options.compress.as_ref(),
comments, comments,
marks, marks,
extra.unresolved_mark, extra.unresolved_mark,
)); ));
debug_assert_valid(&m); debug_assert_valid(&n);
} }
m.visit_mut_with(&mut unique_scope()); n.visit_mut_with(&mut unique_scope());
if options.wrap { if options.wrap {
// TODO: wrap_common_js // TODO: wrap_common_js
@ -191,8 +191,8 @@ pub fn optimize(
} }
if let Some(options) = &options.compress { if let Some(options) = &options.compress {
if options.unused { if options.unused {
perform_dce(&mut m, options, extra); perform_dce(&mut n, options, extra);
debug_assert_valid(&m); debug_assert_valid(&n);
} }
} }
@ -207,7 +207,7 @@ pub fn optimize(
if options.rename && DISABLE_BUGGY_PASSES { if options.rename && DISABLE_BUGGY_PASSES {
// toplevel.figure_out_scope(options.mangle); // toplevel.figure_out_scope(options.mangle);
// TODO: Pass `options.mangle` to name expander. // TODO: Pass `options.mangle` to name expander.
m.visit_mut_with(&mut name_expander()); n.visit_mut_with(&mut name_expander());
} }
if let Some(ref mut t) = timings { if let Some(ref mut t) = timings {
@ -217,14 +217,14 @@ pub fn optimize(
{ {
let _timer = timer!("compress ast"); let _timer = timer!("compress ast");
m.visit_mut_with(&mut compressor(&module_info, marks, options, &Minification)) n.visit_mut_with(&mut compressor(&module_info, marks, options, &Minification))
} }
// Again, we don't need to validate ast // Again, we don't need to validate ast
let _timer = timer!("postcompress"); let _timer = timer!("postcompress");
m.visit_mut_with(&mut postcompress_optimizer(options)); n.visit_mut_with(&mut postcompress_optimizer(options));
let mut pass = 0; let mut pass = 0;
loop { loop {
@ -241,7 +241,7 @@ pub fn optimize(
debug_infinite_loop: false, debug_infinite_loop: false,
}, },
); );
m.visit_mut_with(&mut v); n.visit_mut_with(&mut v);
if !v.changed() || options.passes <= pass { if !v.changed() || options.passes <= pass {
break; break;
} }
@ -263,30 +263,30 @@ pub fn optimize(
let _timer = timer!("mangle names"); let _timer = timer!("mangle names");
// TODO: base54.reset(); // TODO: base54.reset();
let preserved = idents_to_preserve(mangle.clone(), &m); let preserved = idents_to_preserve(mangle.clone(), &n);
let chars = CharFreq::compute( let chars = CharFreq::compute(
&m, &n,
&preserved, &preserved,
SyntaxContext::empty().apply_mark(marks.unresolved_mark), SyntaxContext::empty().apply_mark(marks.unresolved_mark),
) )
.compile(); .compile();
m.visit_mut_with(&mut name_mangler(mangle.clone(), preserved, chars)); n.visit_mut_with(&mut name_mangler(mangle.clone(), preserved, chars));
if let Some(property_mangle_options) = &mangle.props { if let Some(property_mangle_options) = &mangle.props {
mangle_properties(&mut m, &module_info, property_mangle_options.clone(), chars); mangle_properties(&mut n, &module_info, property_mangle_options.clone(), chars);
} }
} }
m.visit_mut_with(&mut merge_exports()); n.visit_mut_with(&mut merge_exports());
if let Some(ref mut t) = timings { if let Some(ref mut t) = timings {
t.section("hygiene"); t.section("hygiene");
t.end_section(); t.end_section();
} }
m n
} }
fn perform_dce(m: &mut Program, options: &CompressOptions, extra: &ExtraOptions) { fn perform_dce(m: &mut Program, options: &CompressOptions, extra: &ExtraOptions) {

View File

@ -191,12 +191,23 @@ impl VisitMut for InfoMarker<'_> {
fn visit_mut_lit(&mut self, _: &mut Lit) {} fn visit_mut_lit(&mut self, _: &mut Lit) {}
fn visit_mut_module(&mut self, m: &mut Module) { fn visit_mut_script(&mut self, n: &mut Script) {
m.visit_mut_children_with(self); n.visit_mut_children_with(self);
if self.state.is_bundle { if self.state.is_bundle {
tracing::info!("Running minifier in the bundle mode"); tracing::info!("Running minifier in the bundle mode");
m.span = m.span.apply_mark(self.marks.bundle_of_standalone); n.span = n.span.apply_mark(self.marks.bundle_of_standalone);
} else {
tracing::info!("Running minifier in the normal mode");
}
}
fn visit_mut_module(&mut self, n: &mut Module) {
n.visit_mut_children_with(self);
if self.state.is_bundle {
tracing::info!("Running minifier in the bundle mode");
n.span = n.span.apply_mark(self.marks.bundle_of_standalone);
} else { } else {
tracing::info!("Running minifier in the normal mode"); tracing::info!("Running minifier in the normal mode");
} }

View File

@ -121,6 +121,13 @@ impl Visit for Preserver {
fn visit_ident(&mut self, _: &Ident) {} fn visit_ident(&mut self, _: &Ident) {}
fn visit_script(&mut self, n: &Script) {
for n in n.body.iter() {
self.in_top_level = true;
n.visit_with(self);
}
}
fn visit_module_items(&mut self, n: &[ModuleItem]) { fn visit_module_items(&mut self, n: &[ModuleItem]) {
for n in n { for n in n {
self.in_top_level = true; self.in_top_level = true;

View File

@ -69,7 +69,42 @@ impl CompileUnit for Module {
{ {
self.visit_mut_with(&mut *visitor); self.visit_mut_with(&mut *visitor);
crate::debug::invoke(self); crate::debug::invoke_module(self);
}
fn remove_mark(&mut self) -> Mark {
Mark::root()
}
}
impl CompileUnit for Script {
fn is_module() -> bool {
false
}
fn force_dump(&self) -> String {
let _noop_sub =
tracing::subscriber::set_default(tracing::subscriber::NoSubscriber::default());
dump(
&self
.clone()
.fold_with(&mut fixer(None))
.fold_with(&mut hygiene())
.fold_with(&mut as_folder(DropSpan {
preserve_ctxt: false,
})),
true,
)
}
fn apply<V>(&mut self, visitor: &mut V)
where
V: VisitMut,
{
self.visit_mut_with(&mut *visitor);
crate::debug::invoke_script(self);
} }
fn remove_mark(&mut self) -> Mark { fn remove_mark(&mut self) -> Mark {

View File

@ -242,12 +242,11 @@ where
if contains_eval(s, true) { if contains_eval(s, true) {
s.visit_mut_children_with(self); s.visit_mut_children_with(self);
return; } else {
let map = self.get_map(s, false, true);
s.visit_mut_with(&mut rename_with_config(&map, self.config.clone()));
} }
let map = self.get_map(s, false, true);
s.visit_mut_with(&mut rename_with_config(&map, self.config.clone()));
} }
} }

View File

@ -8,5 +8,5 @@
<circle onmouseover='alert("test")' cx=50 cy=50 r=30 style=fill:url(#gradient) /> <circle onmouseover='alert("test")' cx=50 cy=50 r=30 style=fill:url(#gradient) />
</svg> </svg>
<div type=text onmouseover=myFunction()>test</div> <div type=text onmouseover=myFunction()>test</div>
<a href=https://datacadamia.com onclick="console.log(`Navigation to ${this.href} cancelled`);return false">Click me</a> <a href=https://datacadamia.com onclick="return console.log(`Navigation to ${this.href} cancelled`),!1">Click me</a>
<a href=https://datacadamia.com onclick="console.log(`Navigation to ${this.href} cancelled`);return false">Click me</a> <a href=https://datacadamia.com onclick="return console.log(`Navigation to ${this.href} cancelled`),!1">Click me</a>

View File

@ -1,6 +1,6 @@
<!doctype html><script defer>console.log()</script><script>console.log();console.log()</script><script type=module>console.log(),console.log()</script><script>window.jQuery||document.write('<script src="jquery.js"><\/script>')</script><script type=text/html> <!doctype html><script defer>console.log()</script><script>console.log(),console.log()</script><script type=module>console.log(),console.log()</script><script>window.jQuery||document.write('<script src="jquery.js"><\/script>')</script><script type=text/html>
<div> <div>
test test
</div> </div>
<!-- aa -->\n <!-- aa -->\n
</script><script type="">alert(1)</script><script type=modules>alert(1)</script><script>alert(1);alert(1)</script><script type=module src=app.mjs></script><script nomodule defer src=classic-app-bundle.js></script><script>alert(1)</script><script type=text/vbscript>MsgBox("foo bar")</script><script type="">MsgBox("foo bar")</script><script type=;;;;;>MsgBox("foo bar")</script><script>alert(1);alert(1);alert(1);alert(1);alert(1);alert(1);alert(1)</script> </script><script type="">alert(1)</script><script type=modules>alert(1)</script><script>alert(1),alert(1)</script><script type=module src=app.mjs></script><script nomodule defer src=classic-app-bundle.js></script><script>alert(1)</script><script type=text/vbscript>MsgBox("foo bar")</script><script type="">MsgBox("foo bar")</script><script type=;;;;;>MsgBox("foo bar")</script><script>alert(1),alert(1),alert(1),alert(1),alert(1),alert(1),alert(1)</script>

View File

@ -1,33 +1,33 @@
<!doctype html><html lang=en><title>Document</title><div>breaker</div> <!doctype html><html lang=en><title>Document</title><div>breaker</div>
<script>var o="test";console.log(o);var e="test";console.log(e)</script> <script>var a="test";console.log(a);var b="test";console.log(b)</script>
<div>breaker</div> <div>breaker</div>
<script>var o="test";console.log(o);var e="test";console.log(e)</script> <script>var a="test";console.log(a);var b="test";console.log(b)</script>
<div>breaker</div> <div>breaker</div>
<script>var o="test";console.log(o);var e="test";console.log(e)</script> <script>var a="test";console.log(a);var b="test";console.log(b)</script>
<div>breaker</div> <div>breaker</div>
<script>var o="test";console.log(o);var e="test";console.log(e)</script> <script>var a="test";console.log(a);var b="test";console.log(b)</script>
<div>breaker</div> <div>breaker</div>
<script>var o="test";console.log(o)</script><script crossorigin=use-credentials>var o="test";console.log(o)</script> <script>var a="test";console.log(a)</script><script crossorigin=use-credentials>var b="test";console.log(b)</script>
<div>breaker</div> <div>breaker</div>
<script crossorigin=use-credentials>var o="test";console.log(o);var e="test";console.log(e)</script> <script crossorigin=use-credentials>var a="test";console.log(a);var b="test";console.log(b)</script>
<div>breaker</div> <div>breaker</div>
<script>(function o(){let o="1";console.log(o)})();let o="1";console.log(o)</script> <script>console.log("1");let test="1";console.log(test)</script>
<div>breaker</div> <div>breaker</div>
<script type=module>var a="test";console.log(a)</script><script>var o="test";console.log(o)</script> <script type=module>var a="test";console.log(a)</script><script>var b="test";console.log(b)</script>
<div>breaker</div> <div>breaker</div>
@ -35,26 +35,26 @@
<div>breaker</div> <div>breaker</div>
<script>var o="test";console.log(o)</script><script type=unknown>var b = "test";console.log(b)</script> <script>var a="test";console.log(a)</script><script type=unknown>var b = "test";console.log(b)</script>
<div>breaker</div> <div>breaker</div>
<script src=test.js></script><script>var o="test";console.log(o)</script> <script src=test.js></script><script>var b="test";console.log(b)</script>
<div>breaker</div> <div>breaker</div>
<div>breaker</div> <div>breaker</div>
<script>var o="test";console.log(o);var e="test";console.log(e)</script> <script>var a="test";console.log(a);var b="test";console.log(b)</script>
<div>breaker</div> <div>breaker</div>
<script>var o="test";console.log(o);var e="test";console.log(e)</script> <script>var a="test";console.log(a);var b="test";console.log(b)</script>
<div>breaker</div> <div>breaker</div>
<script type=module>var a="test";console.log(a);var a1="test";console.log(a1)</script> <script type=module>var a="test";console.log(a);var a1="test";console.log(a1)</script>
<div>breaker</div> <div>breaker</div>
<script type=module>var a="test";console.log(a)</script><script>var o="test";console.log(o)</script> <script type=module>var a="test";console.log(a)</script><script>var a="test";console.log(a)</script>
<div>breaker</div> <div>breaker</div>
<script type=module>var a="test";console.log(a);var a1="test";console.log(a1)</script> <script type=module>var a="test";console.log(a);var a1="test";console.log(a1)</script>
@ -63,34 +63,34 @@
<script type=module>var a="test";console.log(a);var a1="test";console.log(a1)</script> <script type=module>var a="test";console.log(a);var a1="test";console.log(a1)</script>
<div>breaker</div> <div>breaker</div>
<script>let e="test";console.log(e);let l="test";console.log(l);let e="test";console.log(e);let l="test";console.log(l)</script> <script>let a="test";console.log(a);let b="test";console.log(b);let a="test";console.log(a);let b="test";console.log(b)</script>
<div>breaker</div> <div>breaker</div>
<script type=module>let a="test";console.log(a);const b="test";console.log("test");let a1="test";console.log(a1);const b1="test";console.log("test")</script> <script type=module>let a="test";console.log(a);const b="test";console.log("test");let a1="test";console.log(a1);const b1="test";console.log("test")</script>
<div>breaker</div> <div>breaker</div>
<script>let e=[1,2,3];[()=>{console.log("test")},2,3][0]()</script> <script>let foo=[1,2,3];[()=>{console.log("test")},2,3][0]()</script>
<div>breaker</div> <div>breaker</div>
<script type=module>let a="test";console.log(a),console.log(a),console.log(a);let a1="test";console.log(a1),console.log(a1),console.log(a1)</script> <script type=module>let a="test";console.log(a),console.log(a),console.log(a);let a1="test";console.log(a1),console.log(a1),console.log(a1)</script>
<div>breaker</div> <div>breaker</div>
<script>let o="test";console.log(o);console.log(o);console.log(o);let o="test";console.log(o);console.log(o);console.log(o)</script> <script>let a="test";console.log(a),console.log(a),console.log(a);let a="test";console.log(a),console.log(a),console.log(a)</script>
<div>breaker</div> <div>breaker</div>
<script>var o="test";console.log(o);console.log(o);console.log(o);var o="test";console.log(o);console.log(o);console.log(o)</script> <script>var a="test";console.log(a),console.log(a),console.log(a);var a="test";console.log(a),console.log(a),console.log(a)</script>
<div>breaker</div> <div>breaker</div>
<script>var o="test";console.log(o);console.log(o);console.log(o);var o="test";console.log(o);console.log(o);console.log(o);var o="test";console.log(o);console.log(o);console.log(o)</script> <script>var a="test";console.log(a),console.log(a),console.log(a);var a="test";console.log(a),console.log(a),console.log(a);var a="test";console.log(a),console.log(a),console.log(a)</script>
<div>breaker</div> <div>breaker</div>
<script type=module>var a="test";console.log(a),console.log(a),console.log(a);var a1="test";console.log(a1),console.log(a1),console.log(a1);var a2="test";console.log(a2),console.log(a2),console.log(a2)</script> <script type=module>var a="test";console.log(a),console.log(a),console.log(a);var a1="test";console.log(a1),console.log(a1),console.log(a1);var a2="test";console.log(a2),console.log(a2),console.log(a2)</script>
<div>breaker</div> <div>breaker</div>
<script type=module>var a="test";console.log(a),console.log(a),console.log(a)</script><script>var o="test";console.log(o);console.log(o);console.log(o)</script><script type=module>var a="test";console.log(a),console.log(a),console.log(a)</script> <script type=module>var a="test";console.log(a),console.log(a),console.log(a)</script><script>var a="test";console.log(a),console.log(a),console.log(a)</script><script type=module>var a="test";console.log(a),console.log(a),console.log(a)</script>
<div>breaker</div> <div>breaker</div>
<script>var o="test";console.log(o);console.log(o);console.log(o)</script><script type=module>var a="test";console.log(a),console.log(a),console.log(a)</script><script>var o="test";console.log(o);console.log(o);console.log(o)</script> <script>var a="test";console.log(a),console.log(a),console.log(a)</script><script type=module>var a="test";console.log(a),console.log(a),console.log(a)</script><script>var a="test";console.log(a),console.log(a),console.log(a)</script>
<div>breaker</div> <div>breaker</div>

View File

@ -0,0 +1,17 @@
{
"minifyJs": {
"parser": {
"comments": true,
"syntax": "ecmascript",
"target": "es2022"
},
"minifier": {
"mangle": {
"topLevel": true
}
},
"codegen": {
"asciiOnly": true
}
}
}

View File

@ -0,0 +1,36 @@
<!doctype html>
<html lang="en">
<head>
<title>Document</title>
</head>
<body>
<div>Script:</div>
<script>
/* Should mangle top level stuff */
var topLevel = function test() {
let foo = "bar";
if (foo) {
foo += "baz";
}
console.log(foo);
};
</script>
<div>Module:</div>
<script type="module">
/* Should mangle top level stuff */
var topLevel = function test() {
let foo = "bar";
if (foo) {
foo += "baz";
}
console.log(foo);
};
</script>
</body>
</html>

View File

@ -0,0 +1,5 @@
<!doctype html><html lang=en><title>Document</title><div>Script:</div>
<script>/* Should mangle top level stuff */ var o=function(){let o="bar";o&&(o+="baz"),console.log(o)}</script>
<div>Module:</div>
<script type=module>/* Should mangle top level stuff */ var o=function(){let o="bar";o&&(o+="baz"),console.log(o)}</script>

View File

@ -186,5 +186,32 @@
<script>window.jQuery || document.write('<script src="jquery.js"><\/script>')</script> <script>window.jQuery || document.write('<script src="jquery.js"><\/script>')</script>
<div>test</div> <div>test</div>
<script></script> <script></script>
<div>topLevel - script</div>
<script>
/* Should keep top level stuff */
var topLevel = function test() {
let foo = "bar";
if (foo) {
foo += "baz";
}
console.log(foo);
};
</script>
<div>topLevel - module</div>
<script type="module">
/* Should keep top level stuff */
var topLevel = function test() {
let foo = "bar";
if (foo) {
foo += "baz";
}
console.log(foo);
};
</script>
</body> </body>
</html> </html>

View File

@ -19,7 +19,7 @@
</script><script id=data type=application/json>{"foo":"bar"}</script><script> </script><script id=data type=application/json>{"foo":"bar"}</script><script>
broken broken broken broken
</script><script>var a=3,a=9</script><script type=module>import t from"foo.js";let test=58800,test1="testtest"</script><script>let e=new Date;alert("Today's date is "+e)</script><script src=javascript.js> </script><script>var a=3,a=9</script><script type=module>import t from"foo.js";let test=58800,test1="testtest"</script><script>let d=new Date;alert("Today's date is "+d)</script><script src=javascript.js>
@ -27,7 +27,7 @@
var q = "WRONG" ; var q = "WRONG" ;
</script><script>let t="testtest";alert("<!--");alert("<!-- foo -->");alert("-->");alert("testtest");function e(){var t=1,e=2;alert(t+" "+e)}</script><h2>Party coffee cake recipe</h2> </script><script>let foo="testtest";function test(){alert("1 2")}alert("<!--"),alert("<!-- foo -->"),alert("-->"),alert("testtest")</script><h2>Party coffee cake recipe</h2>
<p> <p>
<i>by Mary Stone, 2018-03-10</i> <i>by Mary Stone, 2018-03-10</i>
</p> </p>
@ -54,5 +54,10 @@
alert('test') alert('test')
</script> </script>
</math> </math>
<script blocking="a render">console.log("block")</script><script>(function(t){var t="test"+Math.random()+t,r=1,o=2+Math.random();alert(r+" "+o);console.log(Math.random())})("test");window.jQuery||document.write('<script src="jquery.js"><\/script>')</script> <script blocking="a render">console.log("block")</script><script>!function(t){var t="test"+Math.random()+t;alert("1 "+(2+Math.random())),console.log(Math.random())}("test"),window.jQuery||document.write('<script src="jquery.js"><\/script>')</script>
<div>test</div> <div>test</div>
<div>topLevel - script</div>
<script>var topLevel=function(){let o="bar";o&&(o+="baz"),console.log(o)}</script>
<div>topLevel - module</div>
<script type=module>var topLevel=function(){let o="bar";o&&(o+="baz"),console.log(o)}</script>

View File

@ -29,4 +29,4 @@
foo foo
baz baz
</pre> <div> a <input> c </div> <div>Empty </div> <!--[if lte IE 6]> <span>A</span> <span title=" sigificant whitespace ">blah blah</span> <![endif]--> <div> <a href=#> <span> <b> foo </b> <i> bar </i> </span> </a> </div> <div>a b</div> <div>a b c d</div> <div> text </div> <span> text </span> <span> text </span> <div> <style>a{color:red}</style> <span>test</span> <style>a{color:red}</style> </div> <div> <style>a{color:red}</style> </div> <div> <style>a{color:red}</style> <span>test</span> <span>test</span> <style>a{color:red}</style> </div> <div> <script>console.log("test");console.log("test")</script> </div> </pre> <div> a <input> c </div> <div>Empty </div> <!--[if lte IE 6]> <span>A</span> <span title=" sigificant whitespace ">blah blah</span> <![endif]--> <div> <a href=#> <span> <b> foo </b> <i> bar </i> </span> </a> </div> <div>a b</div> <div>a b c d</div> <div> text </div> <span> text </span> <span> text </span> <div> <style>a{color:red}</style> <span>test</span> <style>a{color:red}</style> </div> <div> <style>a{color:red}</style> </div> <div> <style>a{color:red}</style> <span>test</span> <span>test</span> <style>a{color:red}</style> </div> <div> <script>console.log("test"),console.log("test")</script> </div>

View File

@ -29,4 +29,4 @@
foo foo
baz baz
</pre><div>a <input> c</div><div>Empty</div><!--[if lte IE 6]> <span>A</span> <span title=" sigificant whitespace ">blah blah</span> <![endif]--><div><a href=#> <span><b>foo </b><i> bar </i></span></a></div><div>a b</div><div>a b c d</div><div>text</div><span> text </span><span> text </span><div><span>test</span> <span>test</span></div><div><span>test</span> <command>test</command><span>test</span></div><div><span>test</span><link rel=stylesheet href=""> <span>test</span></div><div><span>test</span><meta name=content> <span>test</span></div><div><span>test</span><script>console.log("test")</script> <span>test</span></div><div><span>test</span><style>a{color:red}</style> <span>test</span></div><div><span>test</span><title>test</title> <span>test</span></div><div><meta name=test><meta name=test></div><div><link rel=stylesheet href=""><link rel=stylesheet href=""></div><div><script>console.log("test");console.log("test")</script></div><div><script>console.log("test")</script> <span>test</span><script>console.log("test")</script></div><div><style>a{color:red}</style></div><div><script>console.log("test")</script><style>a{color:red}</style></div><div><span itemscope><meta itemprop=name content="The Castle">test</span> <span>test</span></div><div><meta name=test></div><div><style>a{color:red}</style></div><div><meta name=test><div>test</div><meta name=test></div><div><meta name=test> <span>test</span><meta name=test></div><svg> <title>test</title> <metadata>test</metadata> <desc>test</desc> </svg><svg> <a>test</a> <a>test</a> </svg><svg><text x=20 y=35><tspan font-weight=bold fill=red>This is bold and red</tspan> <tspan font-weight=bold fill=red>This is bold and red</tspan></text></svg><svg> <tspan>test</tspan><foreignObject>test</foreignObject></svg><svg><text x=20 y=35><tspan font-weight=bold fill=red>This is bold and red</tspan> <tspan font-weight=bold fill=red>This is bold and red</tspan></text></svg><svg viewBox="0 0 100 100" preserveAspectRatio="xMidYMid slice" style=width:100%;height:100%;position:absolute;top:0;left:0;z-index:-1> <linearGradient id=gradient><stop class=begin offset=0% /><stop class=end offset=100% /></linearGradient><rect width=100 height=100 style=fill:url(#gradient) /> <circle cx=50 cy=50 r=30 style=fill:url(#gradient) /> </svg><svg> <script>console.log("test")</script></svg><svg> <style>a{color:red}</style></svg><div><span>test</span> a b <span>test</span> <span>test</span> a b <span>test</span> <span>test</span> a b <span>test</span></div><div><foo-bar> <span>test</span> </foo-bar> <foo-bar> <span>test</span> </foo-bar></div><div><svg> <linearGradient id=gradient /> </svg><span>a</span></div> </pre><div>a <input> c</div><div>Empty</div><!--[if lte IE 6]> <span>A</span> <span title=" sigificant whitespace ">blah blah</span> <![endif]--><div><a href=#> <span><b>foo </b><i> bar </i></span></a></div><div>a b</div><div>a b c d</div><div>text</div><span> text </span><span> text </span><div><span>test</span> <span>test</span></div><div><span>test</span> <command>test</command><span>test</span></div><div><span>test</span><link rel=stylesheet href=""> <span>test</span></div><div><span>test</span><meta name=content> <span>test</span></div><div><span>test</span><script>console.log("test")</script> <span>test</span></div><div><span>test</span><style>a{color:red}</style> <span>test</span></div><div><span>test</span><title>test</title> <span>test</span></div><div><meta name=test><meta name=test></div><div><link rel=stylesheet href=""><link rel=stylesheet href=""></div><div><script>console.log("test"),console.log("test")</script></div><div><script>console.log("test")</script> <span>test</span><script>console.log("test")</script></div><div><style>a{color:red}</style></div><div><script>console.log("test")</script><style>a{color:red}</style></div><div><span itemscope><meta itemprop=name content="The Castle">test</span> <span>test</span></div><div><meta name=test></div><div><style>a{color:red}</style></div><div><meta name=test><div>test</div><meta name=test></div><div><meta name=test> <span>test</span><meta name=test></div><svg> <title>test</title> <metadata>test</metadata> <desc>test</desc> </svg><svg> <a>test</a> <a>test</a> </svg><svg><text x=20 y=35><tspan font-weight=bold fill=red>This is bold and red</tspan> <tspan font-weight=bold fill=red>This is bold and red</tspan></text></svg><svg> <tspan>test</tspan><foreignObject>test</foreignObject></svg><svg><text x=20 y=35><tspan font-weight=bold fill=red>This is bold and red</tspan> <tspan font-weight=bold fill=red>This is bold and red</tspan></text></svg><svg viewBox="0 0 100 100" preserveAspectRatio="xMidYMid slice" style=width:100%;height:100%;position:absolute;top:0;left:0;z-index:-1> <linearGradient id=gradient><stop class=begin offset=0% /><stop class=end offset=100% /></linearGradient><rect width=100 height=100 style=fill:url(#gradient) /> <circle cx=50 cy=50 r=30 style=fill:url(#gradient) /> </svg><svg> <script>console.log("test")</script></svg><svg> <style>a{color:red}</style></svg><div><span>test</span> a b <span>test</span> <span>test</span> a b <span>test</span> <span>test</span> a b <span>test</span></div><div><foo-bar> <span>test</span> </foo-bar> <foo-bar> <span>test</span> </foo-bar></div><div><svg> <linearGradient id=gradient /> </svg><span>a</span></div>

View File

@ -1 +1 @@
<!doctype html><meta charset=utf-8><title>element-details - web component using &lt;template> and &lt;slot></title><style>dl{margin-left:6px}dt{font-weight:700;color:#217ac0;font-size:110%;font-family:Consolas,"Liberation Mono",Courier}dd{margin-left:16px}</style><h1>element-details - web component using <code>&lt;template></code> and <code>&lt;slot></code></h1><template id=element-details-template-1> VALUE: !<slot>?</slot>! </template> <element-details> <span>test</span> <span>foo</span> </element-details> <script>customElements.define("element-details",class extends HTMLElement{constructor(){super();let e=document.getElementById("element-details-template-1").content;this.attachShadow({mode:"open"}).appendChild(e.cloneNode(true))}})</script> <!doctype html><meta charset=utf-8><title>element-details - web component using &lt;template> and &lt;slot></title><style>dl{margin-left:6px}dt{font-weight:700;color:#217ac0;font-size:110%;font-family:Consolas,"Liberation Mono",Courier}dd{margin-left:16px}</style><h1>element-details - web component using <code>&lt;template></code> and <code>&lt;slot></code></h1><template id=element-details-template-1> VALUE: !<slot>?</slot>! </template> <element-details> <span>test</span> <span>foo</span> </element-details> <script>customElements.define("element-details",class extends HTMLElement{constructor(){super();let e=document.getElementById("element-details-template-1").content;this.attachShadow({mode:"open"}).appendChild(e.cloneNode(!0))}})</script>

View File

@ -1 +1 @@
<!doctype html><meta charset=utf-8><title>element-details - web component using &lt;template> and &lt;slot></title><style>dl{margin-left:6px}dt{font-weight:700;color:#217ac0;font-size:110%;font-family:Consolas,"Liberation Mono",Courier}dd{margin-left:16px}</style><h1>element-details - web component using <code>&lt;template></code> and <code>&lt;slot></code></h1><template id=element-details-template-1> VALUE: <slot name=q>?</slot> </template><template id=element-details-template-2> VALUE:<slot name=q>?</slot> </template><template id=element-details-template-3><div>VALUE:</div><slot name=q>?</slot> </template> <element-details> <span slot=q>1</span> </element-details> <element-details> <span slot=q>2</span> </element-details> <element-details-more> <span slot=q>3</span> </element-details-more> <element-details-more> <span slot=q>4</span> </element-details-more> <script>customElements.define("element-details",class extends HTMLElement{constructor(){super();let e=document.getElementById("element-details-template-1").content;this.attachShadow({mode:"open"}).appendChild(e.cloneNode(true))}});customElements.define("element-details-more",class extends HTMLElement{constructor(){super();let e=document.getElementById("element-details-template-2").content;this.attachShadow({mode:"open"}).appendChild(e.cloneNode(true))}})</script> <!doctype html><meta charset=utf-8><title>element-details - web component using &lt;template> and &lt;slot></title><style>dl{margin-left:6px}dt{font-weight:700;color:#217ac0;font-size:110%;font-family:Consolas,"Liberation Mono",Courier}dd{margin-left:16px}</style><h1>element-details - web component using <code>&lt;template></code> and <code>&lt;slot></code></h1><template id=element-details-template-1> VALUE: <slot name=q>?</slot> </template><template id=element-details-template-2> VALUE:<slot name=q>?</slot> </template><template id=element-details-template-3><div>VALUE:</div><slot name=q>?</slot> </template> <element-details> <span slot=q>1</span> </element-details> <element-details> <span slot=q>2</span> </element-details> <element-details-more> <span slot=q>3</span> </element-details-more> <element-details-more> <span slot=q>4</span> </element-details-more> <script>customElements.define("element-details",class extends HTMLElement{constructor(){super();let e=document.getElementById("element-details-template-1").content;this.attachShadow({mode:"open"}).appendChild(e.cloneNode(!0))}}),customElements.define("element-details-more",class extends HTMLElement{constructor(){super();let e=document.getElementById("element-details-template-2").content;this.attachShadow({mode:"open"}).appendChild(e.cloneNode(!0))}})</script>