summaryrefslogtreecommitdiff
path: root/cli/ast/mod.rs
diff options
context:
space:
mode:
authorDavid Sherret <dsherret@users.noreply.github.com>2021-08-06 10:36:16 -0400
committerGitHub <noreply@github.com>2021-08-06 10:36:16 -0400
commit466d3df9d1ff43e16e1a2c20b7792de664547b48 (patch)
tree170b2ab1097331d976ccee47671964b2ebdcc974 /cli/ast/mod.rs
parente9ddc7a41ad7ea02172d88e95c82d007d8d5df63 (diff)
refactor: make `ParsedModule` implement `Sync` (#11581)
Diffstat (limited to 'cli/ast/mod.rs')
-rw-r--r--cli/ast/mod.rs216
1 files changed, 76 insertions, 140 deletions
diff --git a/cli/ast/mod.rs b/cli/ast/mod.rs
index 428fe126d..15414ba8e 100644
--- a/cli/ast/mod.rs
+++ b/cli/ast/mod.rs
@@ -11,10 +11,13 @@ use std::error::Error;
use std::fmt;
use std::ops::Range;
use std::rc::Rc;
+use std::sync::Arc;
use swc_common::chain;
use swc_common::comments::Comment;
use swc_common::comments::CommentKind;
+use swc_common::comments::Comments;
use swc_common::comments::SingleThreadedComments;
+use swc_common::BytePos;
use swc_common::FileName;
use swc_common::Globals;
use swc_common::SourceFile;
@@ -43,13 +46,20 @@ use swc_ecmascript::transforms::react;
use swc_ecmascript::transforms::typescript;
use swc_ecmascript::visit::FoldWith;
+mod bundle_hook;
+mod comments;
+mod source_file_info;
mod transforms;
+pub use bundle_hook::BundleHook;
+use comments::MultiThreadedComments;
+use source_file_info::SourceFileInfo;
+
static TARGET: JscTarget = JscTarget::Es2020;
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Location {
- pub filename: String,
+ pub specifier: String,
pub line: usize,
pub col: usize,
}
@@ -65,7 +75,7 @@ impl From<swc_common::Loc> for Location {
};
Location {
- filename,
+ specifier: filename,
line: swc_loc.line,
col: swc_loc.col_display,
}
@@ -74,13 +84,13 @@ impl From<swc_common::Loc> for Location {
impl From<Location> for ModuleSpecifier {
fn from(loc: Location) -> Self {
- resolve_url_or_path(&loc.filename).unwrap()
+ resolve_url_or_path(&loc.specifier).unwrap()
}
}
impl std::fmt::Display for Location {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
- write!(f, "{}:{}:{}", self.filename, self.line, self.col)
+ write!(f, "{}:{}:{}", self.specifier, self.line, self.col)
}
}
@@ -239,18 +249,15 @@ fn strip_config_from_emit_options(
/// processing.
#[derive(Clone)]
pub struct ParsedModule {
- comments: SingleThreadedComments,
- leading_comments: Vec<Comment>,
+ info: Arc<SourceFileInfo>,
+ comments: MultiThreadedComments,
pub module: Module,
- pub source_map: Rc<SourceMap>,
- source_file: Rc<SourceFile>,
}
impl fmt::Debug for ParsedModule {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("ParsedModule")
.field("comments", &self.comments)
- .field("leading_comments", &self.leading_comments)
.field("module", &self.module)
.finish()
}
@@ -265,28 +272,20 @@ impl ParsedModule {
/// Get the module's leading comments, where triple slash directives might
/// be located.
pub fn get_leading_comments(&self) -> Vec<Comment> {
- self.leading_comments.clone()
+ self
+ .comments
+ .get_leading(self.module.span.lo)
+ .unwrap_or_else(Vec::new)
}
- /// Get the module's comments.
+ /// Get the module's comments sorted by position.
pub fn get_comments(&self) -> Vec<Comment> {
- let mut comments = Vec::new();
- let (leading_comments, trailing_comments) = self.comments.borrow_all();
-
- for value in leading_comments.values() {
- comments.append(&mut value.clone());
- }
-
- for value in trailing_comments.values() {
- comments.append(&mut value.clone());
- }
-
- comments
+ self.comments.get_vec()
}
- /// Get a location for a given span within the module.
- pub fn get_location(&self, span: &Span) -> Location {
- self.source_map.lookup_char_pos(span.lo).into()
+ /// Get a location for a given position within the module.
+ pub fn get_location(&self, pos: BytePos) -> Location {
+ self.info.get_location(pos)
}
/// Transform a TypeScript file into a JavaScript file, based on the supplied
@@ -298,10 +297,14 @@ impl ParsedModule {
options: &EmitOptions,
) -> Result<(String, Option<String>), AnyError> {
let program = Program::Module(self.module);
+ let source_map = Rc::new(SourceMap::default());
+ let file_name = FileName::Custom(self.info.specifier.clone());
+ source_map.new_source_file(file_name, self.info.text.clone());
+ let comments = self.comments.as_single_threaded(); // needs to be mutable
let jsx_pass = react::react(
- self.source_map.clone(),
- Some(&self.comments),
+ source_map.clone(),
+ Some(&comments),
react::Options {
pragma: options.jsx_factory.clone(),
pragma_frag: options.jsx_fragment_factory.clone(),
@@ -324,7 +327,7 @@ impl ParsedModule {
typescript::strip::strip_with_config(strip_config_from_emit_options(
options
)),
- fixer(Some(&self.comments)),
+ fixer(Some(&comments)),
hygiene(),
);
@@ -338,7 +341,7 @@ impl ParsedModule {
let mut buf = vec![];
{
let writer = Box::new(JsWriter::new(
- self.source_map.clone(),
+ source_map.clone(),
"\n",
&mut buf,
Some(&mut src_map_buf),
@@ -346,8 +349,8 @@ impl ParsedModule {
let config = swc_ecmascript::codegen::Config { minify: false };
let mut emitter = swc_ecmascript::codegen::Emitter {
cfg: config,
- comments: Some(&self.comments),
- cm: self.source_map.clone(),
+ comments: Some(&comments),
+ cm: source_map.clone(),
wr: writer,
};
program.emit_with(&mut emitter)?;
@@ -356,8 +359,7 @@ impl ParsedModule {
let mut map: Option<String> = None;
{
let mut buf = Vec::new();
- self
- .source_map
+ source_map
.build_source_map_from(&mut src_map_buf, None)
.to_writer(&mut buf)?;
@@ -373,41 +375,7 @@ impl ParsedModule {
}
}
-pub fn parse_with_source_map(
- specifier: &str,
- source: &str,
- media_type: &MediaType,
- source_map: Rc<SourceMap>,
-) -> Result<ParsedModule, AnyError> {
- let source_file = source_map.new_source_file(
- FileName::Custom(specifier.to_string()),
- source.to_string(),
- );
- let syntax = get_syntax(media_type);
- let input = StringInput::from(&*source_file);
- let comments = SingleThreadedComments::default();
-
- let lexer = Lexer::new(syntax, TARGET, input, Some(&comments));
- let mut parser = swc_ecmascript::parser::Parser::new_from(lexer);
-
- let sm = &source_map;
- let module = parser.parse_module().map_err(move |err| Diagnostic {
- location: sm.lookup_char_pos(err.span().lo).into(),
- message: err.into_kind().msg().to_string(),
- })?;
- let leading_comments =
- comments.with_leading(module.span.lo, |comments| comments.to_vec());
-
- Ok(ParsedModule {
- comments,
- leading_comments,
- module,
- source_map,
- source_file,
- })
-}
-
-/// For a given specifier, source, and media type, parse the source of the
+/// For a given specifier, source, and media type, parse the text of the
/// module and return a representation which can be further processed.
///
/// # Arguments
@@ -424,8 +392,16 @@ pub fn parse(
source: &str,
media_type: &MediaType,
) -> Result<ParsedModule, AnyError> {
- let source_map = Rc::new(SourceMap::default());
- parse_with_source_map(specifier, source, media_type, source_map)
+ let info = SourceFileInfo::new(specifier, source);
+ let input =
+ StringInput::new(source, BytePos(0), BytePos(source.len() as u32));
+ let (comments, module) = parse_string_input(&info, input, media_type)?;
+
+ Ok(ParsedModule {
+ info: Arc::new(info),
+ comments: MultiThreadedComments::from_single_threaded(comments),
+ module,
+ })
}
pub enum TokenOrComment {
@@ -453,21 +429,12 @@ fn flatten_comments(
comments.into_iter().flat_map(|el| el.1)
}
-pub fn lex(
- specifier: &str,
- source: &str,
- media_type: &MediaType,
-) -> Vec<LexedItem> {
- let source_map = SourceMap::default();
- let source_file = source_map.new_source_file(
- FileName::Custom(specifier.to_string()),
- source.to_string(),
- );
+pub fn lex(source: &str, media_type: &MediaType) -> Vec<LexedItem> {
let comments = SingleThreadedComments::default();
let lexer = Lexer::new(
get_syntax(media_type),
TARGET,
- StringInput::from(source_file.as_ref()),
+ StringInput::new(source, BytePos(0), BytePos(source.len() as u32)),
Some(&comments),
);
@@ -494,19 +461,24 @@ pub fn lex(
/// A low level function which transpiles a source module into an swc
/// SourceFile.
pub fn transpile_module(
- filename: &str,
- src: &str,
+ specifier: &str,
+ source: &str,
media_type: &MediaType,
emit_options: &EmitOptions,
globals: &Globals,
cm: Rc<SourceMap>,
) -> Result<(Rc<SourceFile>, Module), AnyError> {
- let parsed_module =
- parse_with_source_map(filename, src, media_type, cm.clone())?;
+ let info = SourceFileInfo::new(specifier, source);
+ let source_file = cm.new_source_file(
+ FileName::Custom(specifier.to_string()),
+ source.to_string(),
+ );
+ let input = StringInput::from(&*source_file);
+ let (comments, module) = parse_string_input(&info, input, media_type)?;
let jsx_pass = react::react(
cm,
- Some(&parsed_module.comments),
+ Some(&comments),
react::Options {
pragma: emit_options.jsx_factory.clone(),
pragma_frag: emit_options.jsx_fragment_factory.clone(),
@@ -526,12 +498,9 @@ pub fn transpile_module(
typescript::strip::strip_with_config(strip_config_from_emit_options(
emit_options
)),
- fixer(Some(&parsed_module.comments)),
+ fixer(Some(&comments)),
);
- let source_file = parsed_module.source_file.clone();
- let module = parsed_module.module;
-
let module = swc_common::GLOBALS.set(globals, || {
helpers::HELPERS.set(&helpers::Helpers::new(false), || {
module.fold_with(&mut passes)
@@ -541,55 +510,22 @@ pub fn transpile_module(
Ok((source_file, module))
}
-pub struct BundleHook;
-
-impl swc_bundler::Hook for BundleHook {
- fn get_import_meta_props(
- &self,
- span: swc_common::Span,
- module_record: &swc_bundler::ModuleRecord,
- ) -> Result<Vec<swc_ecmascript::ast::KeyValueProp>, AnyError> {
- use swc_ecmascript::ast;
-
- // we use custom file names, and swc "wraps" these in `<` and `>` so, we
- // want to strip those back out.
- let mut value = module_record.file_name.to_string();
- value.pop();
- value.remove(0);
-
- Ok(vec![
- ast::KeyValueProp {
- key: ast::PropName::Ident(ast::Ident::new("url".into(), span)),
- value: Box::new(ast::Expr::Lit(ast::Lit::Str(ast::Str {
- span,
- value: value.into(),
- kind: ast::StrKind::Synthesized,
- has_escape: false,
- }))),
- },
- ast::KeyValueProp {
- key: ast::PropName::Ident(ast::Ident::new("main".into(), span)),
- value: Box::new(if module_record.is_entry {
- ast::Expr::Member(ast::MemberExpr {
- span,
- obj: ast::ExprOrSuper::Expr(Box::new(ast::Expr::MetaProp(
- ast::MetaPropExpr {
- meta: ast::Ident::new("import".into(), span),
- prop: ast::Ident::new("meta".into(), span),
- },
- ))),
- prop: Box::new(ast::Expr::Ident(ast::Ident::new(
- "main".into(),
- span,
- ))),
- computed: false,
- })
- } else {
- ast::Expr::Lit(ast::Lit::Bool(ast::Bool { span, value: false }))
- }),
- },
- ])
- }
+fn parse_string_input(
+ info: &SourceFileInfo,
+ input: StringInput,
+ media_type: &MediaType,
+) -> Result<(SingleThreadedComments, Module), AnyError> {
+ let syntax = get_syntax(media_type);
+ let comments = SingleThreadedComments::default();
+ let lexer = Lexer::new(syntax, TARGET, input, Some(&comments));
+ let mut parser = swc_ecmascript::parser::Parser::new_from(lexer);
+
+ let module = parser.parse_module().map_err(|err| Diagnostic {
+ location: info.get_location(err.span().lo),
+ message: err.into_kind().msg().to_string(),
+ })?;
+
+ Ok((comments, module))
}
#[cfg(test)]