feat(es/codegen): Add to_code (#8968)

**Description:**

This is a utility function for printing an AST node as a string
This commit is contained in:
Donny/강동윤 2024-05-23 11:23:32 +09:00 committed by GitHub
parent ea14fc8e59
commit e80fd41ea8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 40 additions and 73 deletions

View File

@ -13,7 +13,7 @@ use swc_atoms::Atom;
use swc_common::{ use swc_common::{
comments::{CommentKind, Comments}, comments::{CommentKind, Comments},
sync::Lrc, sync::Lrc,
BytePos, SourceMapper, Span, Spanned, DUMMY_SP, BytePos, SourceMap, SourceMapper, Span, Spanned, DUMMY_SP,
}; };
use swc_ecma_ast::*; use swc_ecma_ast::*;
use swc_ecma_codegen_macros::emitter; use swc_ecma_codegen_macros::emitter;
@ -38,6 +38,36 @@ pub mod util;
pub type Result = io::Result<()>; pub type Result = io::Result<()>;
/// Generate a code from a syntax node using default options.
pub fn to_code_default(
cm: Lrc<SourceMap>,
comments: Option<&dyn Comments>,
node: impl Node,
) -> String {
let mut buf = vec![];
{
let mut emitter = Emitter {
cfg: Default::default(),
cm: cm.clone(),
comments,
wr: text_writer::JsWriter::new(cm, "\n", &mut buf, None),
};
node.emit_with(&mut emitter).unwrap();
}
String::from_utf8(buf).expect("codegen generated non-utf8 output")
}
/// Generate a code from a syntax node using default options.
pub fn to_code_with_comments(comments: Option<&dyn Comments>, node: impl Node) -> String {
to_code_default(Default::default(), comments, node)
}
/// Generate a code from a syntax node using default options.
pub fn to_code(node: impl Node) -> String {
to_code_with_comments(None, node)
}
pub trait Node: Spanned { pub trait Node: Spanned {
fn emit_with<W, S>(&self, e: &mut Emitter<'_, W, S>) -> Result fn emit_with<W, S>(&self, e: &mut Emitter<'_, W, S>) -> Result
where where

View File

@ -28,7 +28,7 @@ use swc_common::{
FileName, Mark, SourceMap, DUMMY_SP, FileName, Mark, SourceMap, DUMMY_SP,
}; };
use swc_ecma_ast::*; use swc_ecma_ast::*;
use swc_ecma_codegen::Emitter; use swc_ecma_codegen::{to_code_default, Emitter};
use swc_ecma_parser::{lexer::Lexer, Parser, StringInput, Syntax}; use swc_ecma_parser::{lexer::Lexer, Parser, StringInput, Syntax};
use swc_ecma_testing::{exec_node_js, JsExecOptions}; use swc_ecma_testing::{exec_node_js, JsExecOptions};
use swc_ecma_transforms_base::{ use swc_ecma_transforms_base::{
@ -188,26 +188,7 @@ impl<'a> Tester<'a> {
} }
pub fn print(&mut self, module: &Module, comments: &Rc<SingleThreadedComments>) -> String { pub fn print(&mut self, module: &Module, comments: &Rc<SingleThreadedComments>) -> String {
let mut buf = vec![]; to_code_default(self.cm.clone(), Some(comments), module)
{
let mut emitter = Emitter {
cfg: Default::default(),
cm: self.cm.clone(),
wr: Box::new(swc_ecma_codegen::text_writer::JsWriter::new(
self.cm.clone(),
"\n",
&mut buf,
None,
)),
comments: Some(comments),
};
// println!("Emitting: {:?}", module);
emitter.emit_module(module).unwrap();
}
let s = String::from_utf8_lossy(&buf);
s.to_string()
} }
} }

View File

@ -10,7 +10,7 @@ use swc_common::{
sync::Lrc, sync::Lrc,
Globals, Mark, SourceMap, GLOBALS, Globals, Mark, SourceMap, GLOBALS,
}; };
use swc_ecma_codegen::{text_writer::JsWriter, Emitter}; use swc_ecma_codegen::to_code_default;
use swc_ecma_parser::{lexer::Lexer, Parser, StringInput, Syntax, TsConfig}; use swc_ecma_parser::{lexer::Lexer, Parser, StringInput, Syntax, TsConfig};
use swc_ecma_transforms_base::{fixer::fixer, hygiene::hygiene, resolver}; use swc_ecma_transforms_base::{fixer::fixer, hygiene::hygiene, resolver};
use swc_ecma_transforms_typescript::strip; use swc_ecma_transforms_typescript::strip;
@ -76,18 +76,6 @@ fn main() {
// Ensure that we have enough parenthesis. // Ensure that we have enough parenthesis.
let program = module.fold_with(&mut fixer(Some(&comments))); let program = module.fold_with(&mut fixer(Some(&comments)));
let mut buf = vec![]; println!("{}", to_code_default(cm, Some(&comments), program));
{
let mut emitter = Emitter {
cfg: swc_ecma_codegen::Config::default(),
cm: cm.clone(),
comments: Some(&comments),
wr: JsWriter::new(cm.clone(), "\n", &mut buf, None),
};
emitter.emit_program(&program).unwrap();
}
println!("{}", String::from_utf8(buf).expect("non-utf8?"));
}) })
} }

View File

@ -1,12 +1,8 @@
use std::{ use std::path::PathBuf;
io::{self, Write},
path::PathBuf,
sync::{Arc, RwLock},
};
use swc_common::{FileName, Mark}; use swc_common::{FileName, Mark};
use swc_ecma_ast::*; use swc_ecma_ast::*;
use swc_ecma_codegen::Emitter; use swc_ecma_codegen::to_code_default;
use swc_ecma_parser::{lexer::Lexer, EsConfig, Parser, Syntax, TsConfig}; use swc_ecma_parser::{lexer::Lexer, EsConfig, Parser, Syntax, TsConfig};
use swc_ecma_transforms_base::{fixer::fixer, hygiene::hygiene, resolver}; use swc_ecma_transforms_base::{fixer::fixer, hygiene::hygiene, resolver};
use swc_ecma_transforms_typescript::typescript; use swc_ecma_transforms_typescript::typescript;
@ -98,21 +94,7 @@ fn identity(entry: PathBuf) {
None, None,
); );
let mut wr = Buf(Arc::new(RwLock::new(vec![]))); let js_content = {
{
let mut emitter = Emitter {
cfg: swc_ecma_codegen::Config::default(),
cm: cm.clone(),
wr: Box::new(swc_ecma_codegen::text_writer::JsWriter::new(
cm.clone(),
"\n",
&mut wr,
None,
)),
comments: None,
};
// Parse source // Parse source
let program = parser let program = parser
.parse_typescript_module() .parse_typescript_module()
@ -142,10 +124,8 @@ fn identity(entry: PathBuf) {
Err(_) => return Ok(()), Err(_) => return Ok(()),
}; };
emitter.emit_program(&program).unwrap(); to_code_default(cm.clone(), None, program)
} };
let js_content = String::from_utf8_lossy(&wr.0.read().unwrap()).to_string();
println!("---------------- JS ----------------\n\n{}", js_content); println!("---------------- JS ----------------\n\n{}", js_content);
@ -182,15 +162,3 @@ fn identity(entry: PathBuf) {
}) })
.expect("failed to run test"); .expect("failed to run test");
} }
#[derive(Debug, Clone)]
struct Buf(Arc<RwLock<Vec<u8>>>);
impl Write for Buf {
fn write(&mut self, data: &[u8]) -> io::Result<usize> {
self.0.write().unwrap().write(data)
}
fn flush(&mut self) -> io::Result<()> {
self.0.write().unwrap().flush()
}
}