feat(es/testing): Improve comment testing story (#9150)

**Description:**

This PR makes `PluginCommentProxy` work by default in `test_fixture()`. This PR adds a scoped-local to `swc_common`, and uses it from `swc_ecma_transforms_testing`.

It can't be tested in the main repository, though. We cannot enable `plugin_mode` of `swc_common` in the main SWC repository.


**Related issue:**

 - Closes https://github.com/swc-project/swc/issues/9149.
This commit is contained in:
Donny/강동윤 2024-07-06 15:20:01 +09:00 committed by GitHub
parent 4a4d877561
commit 3638e97c80
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 102 additions and 32 deletions

View File

@ -690,3 +690,9 @@ pub trait CommentsExt: Comments {
#[allow(deprecated)]
impl<C> CommentsExt for C where C: Comments {}
better_scoped_tls::scoped_tls!(
/// **This is not a public API**. Used to handle comments while **testing**.
#[doc(hidden)]
pub static COMMENTS: Box<dyn Comments>
);

View File

@ -7,7 +7,7 @@ use std::{
env,
fs::{self, create_dir_all, read_to_string, OpenOptions},
io::Write,
mem::take,
mem::{take, transmute},
panic,
path::{Path, PathBuf},
process::Command,
@ -21,14 +21,14 @@ use serde::de::DeserializeOwned;
use sha2::{Digest, Sha256};
use swc_common::{
chain,
comments::SingleThreadedComments,
comments::{Comments, SingleThreadedComments},
errors::{Handler, HANDLER},
source_map::SourceMapGenConfig,
sync::Lrc,
FileName, Mark, SourceMap, DUMMY_SP,
};
use swc_ecma_ast::*;
use swc_ecma_codegen::{to_code_default, Emitter};
use swc_ecma_codegen::to_code_default;
use swc_ecma_parser::{lexer::Lexer, Parser, StringInput, Syntax};
use swc_ecma_testing::{exec_node_js, JsExecOptions};
use swc_ecma_transforms_base::{
@ -63,13 +63,22 @@ impl<'a> Tester<'a> {
where
F: FnOnce(&mut Tester<'_>) -> Result<Ret, ()>,
{
let comments = Rc::new(SingleThreadedComments::default());
let out = ::testing::run_test(false, |cm, handler| {
HANDLER.set(handler, || {
HELPERS.set(&Default::default(), || {
op(&mut Tester {
cm,
handler,
comments: Default::default(),
let cmts = comments.clone();
let c = Box::new(unsafe {
// Safety: This is unsafe but it's used only for testing.
transmute::<&dyn Comments, &'static dyn Comments>(&*cmts)
}) as Box<dyn Comments>;
swc_common::comments::COMMENTS.set(&c, || {
op(&mut Tester {
cm,
handler,
comments,
})
})
})
})
@ -863,14 +872,17 @@ fn test_fixture_inner<'a>(
let mut sourcemap = None;
let (actual_src, stderr) = Tester::run_captured(|tester| {
println!("----- {} -----\n{}", Color::Green.paint("Input"), input);
eprintln!("----- {} -----\n{}", Color::Green.paint("Input"), input);
let tr = tr(tester);
println!("----- {} -----", Color::Green.paint("Actual"));
eprintln!("----- {} -----", Color::Green.paint("Actual"));
let actual = tester.apply_transform(tr, "input.js", syntax, input)?;
eprintln!("----- {} -----", Color::Green.paint("Comments"));
eprintln!("{:?}", tester.comments);
match ::std::env::var("PRINT_HYGIENE") {
Ok(ref s) if s == "1" => {
let hygiene_src = tester.print(
@ -893,23 +905,6 @@ fn test_fixture_inner<'a>(
let actual_src = {
let module = &actual;
let comments: &Rc<SingleThreadedComments> = &tester.comments.clone();
let mut buf = vec![];
{
let mut emitter = Emitter {
cfg: Default::default(),
cm: tester.cm.clone(),
wr: Box::new(swc_ecma_codegen::text_writer::JsWriter::new(
tester.cm.clone(),
"\n",
&mut buf,
src_map.as_mut(),
)),
comments: Some(comments),
};
// println!("Emitting: {:?}", module);
emitter.emit_module(module).unwrap();
}
if let Some(src_map) = &mut src_map {
sourcemap = Some(tester.cm.build_source_map_with_config(
@ -919,8 +914,7 @@ fn test_fixture_inner<'a>(
));
}
let s = String::from_utf8_lossy(&buf);
s.to_string()
to_code_default(tester.cm.clone(), Some(comments), module)
};
Ok(actual_src)
@ -935,11 +929,11 @@ fn test_fixture_inner<'a>(
}
if let Some(actual_src) = actual_src {
println!("{}", actual_src);
eprintln!("{}", actual_src);
if let Some(sourcemap) = &sourcemap {
println!("----- ----- ----- ----- -----");
println!("SourceMap: {}", visualizer_url(&actual_src, sourcemap));
eprintln!("----- ----- ----- ----- -----");
eprintln!("SourceMap: {}", visualizer_url(&actual_src, sourcemap));
}
if actual_src != expected_src {

View File

@ -73,7 +73,77 @@ impl PluginCommentsProxy {
}
}
#[cfg(feature = "__plugin_mode")]
#[cfg(all(feature = "__plugin_mode", not(target_arch = "wasm32")))]
#[swc_trace]
impl Comments for PluginCommentsProxy {
fn add_leading(&self, pos: BytePos, cmt: Comment) {
swc_common::comments::COMMENTS.with(|comments| {
comments.add_leading(pos, cmt);
});
}
fn add_leading_comments(&self, pos: BytePos, comments: Vec<Comment>) {
swc_common::comments::COMMENTS.with(|comments| {
comments.add_leading_comments(pos, comments);
});
}
fn has_leading(&self, pos: BytePos) -> bool {
swc_common::comments::COMMENTS.with(|comments| comments.has_leading(pos))
}
fn move_leading(&self, from: BytePos, to: BytePos) {
swc_common::comments::COMMENTS.with(|comments| {
comments.move_leading(from, to);
});
}
fn take_leading(&self, pos: BytePos) -> Option<Vec<Comment>> {
swc_common::comments::COMMENTS.with(|comments| comments.take_leading(pos))
}
fn get_leading(&self, pos: BytePos) -> Option<Vec<Comment>> {
swc_common::comments::COMMENTS.with(|comments| comments.get_leading(pos))
}
fn add_trailing(&self, pos: BytePos, cmt: Comment) {
swc_common::comments::COMMENTS.with(|comments| {
comments.add_trailing(pos, cmt);
});
}
fn add_trailing_comments(&self, pos: BytePos, comments: Vec<Comment>) {
swc_common::comments::COMMENTS.with(|comments| {
comments.add_trailing_comments(pos, comments);
});
}
fn has_trailing(&self, pos: BytePos) -> bool {
swc_common::comments::COMMENTS.with(|comments| comments.has_trailing(pos))
}
fn move_trailing(&self, from: BytePos, to: BytePos) {
swc_common::comments::COMMENTS.with(|comments| {
comments.move_trailing(from, to);
});
}
fn take_trailing(&self, pos: BytePos) -> Option<Vec<Comment>> {
swc_common::comments::COMMENTS.with(|comments| comments.take_trailing(pos))
}
fn get_trailing(&self, pos: BytePos) -> Option<Vec<Comment>> {
swc_common::comments::COMMENTS.with(|comments| comments.get_trailing(pos))
}
fn add_pure_comment(&self, pos: BytePos) {
swc_common::comments::COMMENTS.with(|comments| {
comments.add_pure_comment(pos);
});
}
}
#[cfg(all(feature = "__plugin_mode", target_arch = "wasm32"))]
#[cfg_attr(not(target_arch = "wasm32"), allow(unused))]
#[swc_trace]
impl Comments for PluginCommentsProxy {