Move config from libswc to node-swc

This commit is contained in:
강동윤 2019-01-09 18:40:14 +09:00
parent 0f0dc1451a
commit 9361e96d5b
3 changed files with 3 additions and 281 deletions

View File

@ -13,14 +13,10 @@ description = "Speedy web compiler"
name = "swc"
[dependencies]
rayon = "1.0.3"
swc_atoms = { version = "0.1", path ="./atoms" }
swc_common = { version = "0.1", path ="./common" }
swc_ecmascript = { version = "0.1", path ="./ecmascript" }
swc_atoms = { path ="./atoms" }
swc_common = { path ="./common" }
swc_ecmascript = { path ="./ecmascript" }
sourcemap = "2.2"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
fnv = "1"
[profile.bench]
lto = true

View File

@ -1,122 +0,0 @@
use crate::Compiler;
use atoms::JsWord;
use common::FileName;
use ecmascript::{
ast::{Expr, ModuleItem, Stmt},
parser::Syntax,
transforms::{react, InlineGlobals},
};
use fnv::FnvHashMap;
use serde::{Deserialize, Serialize};
use std::{collections::HashMap, env};
/// `.swcrc` file
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
pub struct Config {
#[serde(default)]
pub jsc: JscConfig,
}
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
pub struct JscConfig {
#[serde(rename = "parser", default)]
pub syntax: Syntax,
#[serde(default)]
pub transform: TrnasformConfig,
}
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
pub struct TrnasformConfig {
#[serde(default)]
pub react: react::Options,
#[serde(default)]
pub optimizer: Option<OptimizerConfig>,
}
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
pub struct OptimizerConfig {
#[serde(default)]
pub globals: Option<GlobalPassOption>,
}
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
pub struct GlobalPassOption {
#[serde(default)]
pub vars: FnvHashMap<String, String>,
}
impl GlobalPassOption {
pub fn build(self, c: &Compiler) -> InlineGlobals {
fn mk_map(
c: &Compiler,
values: impl Iterator<Item = (String, String)>,
is_env: bool,
) -> HashMap<JsWord, Expr> {
let mut m = HashMap::new();
for (k, v) in values {
let v = if is_env {
format!("'{}'", v)
} else {
(*v).into()
};
let mut module = c
.parse_js(
FileName::Custom(format!("GLOBAL_{}", k)),
Default::default(),
&v,
)
.unwrap_or_else(|err| panic!("failed to parse globals.{}: {:?}", k, err));
let expr = match module.body.pop().unwrap() {
ModuleItem::Stmt(Stmt::Expr(box expr)) => expr,
_ => panic!("{} is not a valid expression", v),
};
m.insert((*k).into(), expr);
}
m
}
InlineGlobals {
globals: mk_map(c, self.vars.into_iter(), false),
envs: mk_map(c, env::vars(), true),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use ecmascript::parser::TsConfig;
#[test]
fn test() {
println!(
"{}",
serde_json::to_string_pretty(&Config {
jsc: JscConfig {
syntax: Syntax::Typescript(TsConfig {
..Default::default()
}),
transform: TrnasformConfig {
react: react::Options {
..Default::default()
},
optimizer: Some(OptimizerConfig {
globals: Some(GlobalPassOption {
vars: {
let mut map = FnvHashMap::default();
map.insert("__DEBUG__".into(), "true".into());
map
}
}),
})
}
},
})
.unwrap()
);
}
}

View File

@ -1,157 +1,5 @@
#![feature(box_syntax)]
#![feature(box_patterns)]
extern crate fnv;
extern crate rayon;
extern crate serde;
extern crate serde_json;
pub extern crate sourcemap;
pub extern crate swc_atoms as atoms;
pub extern crate swc_common as common;
pub extern crate swc_ecmascript as ecmascript;
use self::{
common::{errors::Handler, sync::Lrc, FileName, Globals, SourceMap, GLOBALS},
config::Config,
ecmascript::{
ast::Module,
codegen::{self, Emitter},
parser::{Parser, Session as ParseSess, SourceFileInput, Syntax},
},
};
use sourcemap::SourceMapBuilder;
use std::{
cell::RefCell,
collections::HashMap,
fs::File,
io,
path::{Path, PathBuf},
sync::Arc,
};
pub mod config;
pub struct Compiler {
pub globals: Globals,
pub cm: Lrc<SourceMap>,
handler: Handler,
config_caches: RefCell<HashMap<PathBuf, Arc<Config>>>,
}
impl Compiler {
pub fn new(cm: Lrc<SourceMap>, handler: Handler) -> Self {
Compiler {
cm,
handler,
globals: Globals::new(),
config_caches: Default::default(),
}
}
pub fn config_for_file(&self, path: &Path) -> Result<Arc<Config>, io::Error> {
assert!(!path.is_file());
let mut parent = path.parent();
while let Some(dir) = parent {
let swcrc = dir.join(".swcrc");
if let Some(c) = self.config_caches.borrow().get(&swcrc) {
return Ok(c.clone());
}
if swcrc.exists() {
let mut r = File::open(&swcrc)?;
let config: Config = serde_json::from_reader(r)?;
let arc = Arc::new(config);
self.config_caches.borrow_mut().insert(swcrc, arc.clone());
return Ok(arc);
}
parent = dir.parent();
}
Ok(Default::default())
}
pub fn run<F, T>(&self, op: F) -> T
where
F: FnOnce() -> T,
{
GLOBALS.set(&self.globals, op)
}
pub fn parse_js(&self, name: FileName, syntax: Syntax, src: &str) -> Result<Module, ()> {
self.run(|| {
let fm = self.cm.new_source_file(name, src.into());
let session = ParseSess {
handler: &self.handler,
};
Parser::new(session, syntax, SourceFileInput::from(&*fm))
.parse_module()
.map_err(|e| {
e.emit();
()
})
})
}
/// TODO
pub fn parse_js_file(&self, syntax: Option<Syntax>, path: &Path) -> Result<Module, ()> {
self.run(|| {
let syntax = syntax.unwrap_or_else(|| {
self.config_for_file(path)
.map(|c| c.jsc.syntax)
.expect("failed to load config")
});
let fm = self.cm.load_file(path).expect("failed to load file");
let session = ParseSess {
handler: &self.handler,
};
Parser::new(session, syntax, SourceFileInput::from(&*fm))
.parse_module()
.map_err(|e| {
e.emit();
()
})
})
}
/// Returns code, sourcemap
pub fn emit_module(
&self,
module: &Module,
cfg: codegen::Config,
) -> io::Result<(String, sourcemap::SourceMap)> {
self.run(|| {
let mut src_map_builder = SourceMapBuilder::new(None);
let src = {
let mut buf = vec![];
{
let handlers = box MyHandlers;
let mut emitter = Emitter {
cfg,
cm: self.cm.clone(),
wr: box swc_ecmascript::codegen::text_writer::JsWriter::new(
self.cm.clone(),
"\n",
&mut buf,
&mut src_map_builder,
),
handlers,
pos_of_leading_comments: Default::default(),
};
emitter.emit_module(&module)?;
}
String::from_utf8(buf).unwrap()
};
Ok((src, src_map_builder.into_sourcemap()))
})
}
}
struct MyHandlers;
impl swc_ecmascript::codegen::Handlers for MyHandlers {}