From 5bea4a6138424a3fc8650804aaa9b09bd6ddd9a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EB=8F=99=EC=9C=A4?= Date: Sat, 22 Dec 2018 17:41:01 +0900 Subject: [PATCH] Add index.d.ts and export inline globals pass (#90) --- ffi/lib/index.d.ts | 40 ++++++++++++++++++++++++ ffi/native/Cargo.toml | 1 + ffi/native/src/lib.rs | 73 ++++++++++++++++++++++++++++++++++++++----- ffi/package.json | 3 +- 4 files changed, 108 insertions(+), 9 deletions(-) create mode 100644 ffi/lib/index.d.ts diff --git a/ffi/lib/index.d.ts b/ffi/lib/index.d.ts new file mode 100644 index 00000000000..6113b9bb8cb --- /dev/null +++ b/ffi/lib/index.d.ts @@ -0,0 +1,40 @@ + +declare module "swc" { + /** + * Options for trasnform. + */ + export interface TransformOption { + /** + * + * Defaults to false. + */ + readonly optimize?: boolean; + + readonly globals?: GlobalPassOption; + } + /** + * Options for inline-global pass. + */ + export interface GlobalPassOption { + /** + * Global variables. + * + * e.g. { __DEBUG__: true } + */ + readonly vars?: { [key: string]: string }; + } + + export interface Output { + /** + * Transformed code + */ + readonly code: string; + /** + * Sourcemap (not base64 encoded) + */ + readonly map: string; + } + + export function transform(src: string, options?: TransformOption): Output; + export function transformFileSync(path: string, options?: TransformOption): Output; +} \ No newline at end of file diff --git a/ffi/native/Cargo.toml b/ffi/native/Cargo.toml index 058a46d63a2..63c0c08f262 100644 --- a/ffi/native/Cargo.toml +++ b/ffi/native/Cargo.toml @@ -21,6 +21,7 @@ serde_derive = "1" neon = "0.2.0" neon-serde = "0.1.1" sourcemap = "2" +fnv = "1" swc = { git = "https://github.com/swc-project/swc.git" } [profile.bench] diff --git a/ffi/native/src/lib.rs b/ffi/native/src/lib.rs index d67fbc07dd7..38038d092b2 100644 --- a/ffi/native/src/lib.rs +++ b/ffi/native/src/lib.rs @@ -1,5 +1,9 @@ +#![feature(box_syntax)] +#![feature(box_patterns)] + #[macro_use] extern crate neon; +extern crate fnv; extern crate neon_serde; extern crate serde; #[macro_use] @@ -7,16 +11,18 @@ extern crate serde_derive; extern crate sourcemap; extern crate swc; +use fnv::FnvHashMap; use neon::prelude::*; -use std::{path::Path, sync::Arc}; +use std::{collections::HashMap, env, path::Path, sync::Arc}; use swc::{ + atoms::JsWord, common::{ self, errors::Handler, sync::Lrc, FileName, FilePathMapping, Fold, FoldWith, SourceMap, }, ecmascript::{ - ast::Module, + ast::{Expr, Module, ModuleItem, Stmt}, codegen, - transforms::{compat, hygiene, simplifier}, + transforms::{compat, hygiene, simplifier, InlineGlobals}, }, Compiler, }; @@ -42,6 +48,48 @@ fn parse(mut cx: FunctionContext) -> JsResult { #[derive(Default, Deserialize)] struct TransformOption { optimize: bool, + globals: Option, +} + +#[derive(Default, Deserialize)] +struct GlobalPassOption { + vars: FnvHashMap, +} +impl GlobalPassOption { + fn build(self, c: &Compiler) -> InlineGlobals { + fn mk_map( + c: &Compiler, + values: impl Iterator, + is_env: bool, + ) -> HashMap { + 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)), &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), + } + } } fn transform(mut cx: FunctionContext) -> JsResult { @@ -64,7 +112,7 @@ fn transform(mut cx: FunctionContext) -> JsResult { let module = c .parse_js(FileName::Anon(0), &source.value()) .expect("failed to parse module"); - let module = c.run(|| transform_module(cm.clone(), module, options)); + let module = c.run(|| transform_module(&c, module, options)); let (code, map) = c .emit_module( @@ -110,7 +158,7 @@ fn transform_file(mut cx: FunctionContext) -> JsResult { let module = c .parse_js_file(Path::new(&path.value())) .expect("failed to parse module"); - let module = c.run(|| transform_module(cm.clone(), module, options)); + let module = c.run(|| transform_module(&c, module, options)); let (code, map) = c .emit_module( @@ -136,9 +184,18 @@ fn transform_file(mut cx: FunctionContext) -> JsResult { Ok(obj) } -fn transform_module(cm: Lrc, module: Module, options: TransformOption) -> Module { +fn transform_module(c: &Compiler, module: Module, options: TransformOption) -> Module { let helpers = Arc::new(compat::helpers::Helpers::default()); + let module = { + let opts = if let Some(opts) = options.globals { + opts + } else { + Default::default() + }; + module.fold_with(&mut opts.build(c)) + }; + let module = if options.optimize { module.fold_with(&mut simplifier()) } else { @@ -154,7 +211,7 @@ fn transform_module(cm: Lrc, module: Module, options: TransformOption .fold_with(&mut hygiene()); module.fold_with(&mut compat::helpers::InjectHelpers { - cm, + cm: c.cm.clone(), helpers: helpers.clone(), }) } @@ -162,6 +219,6 @@ fn transform_module(cm: Lrc, module: Module, options: TransformOption register_module!(mut cx, { cx.export_function("parse", parse)?; cx.export_function("transform", transform)?; - cx.export_function("transformFile", transform_file)?; + cx.export_function("transformFileSync", transform_file)?; Ok(()) }); diff --git a/ffi/package.json b/ffi/package.json index c30c12abcf7..803788a0676 100644 --- a/ffi/package.json +++ b/ffi/package.json @@ -1,6 +1,6 @@ { "name": "swc", - "version": "1.0.0-alpha.2", + "version": "1.0.0-alpha.3", "description": "Super-fast alternative for babel", "main": "lib/index.js", "author": "강동윤 ", @@ -8,6 +8,7 @@ "dependencies": { "neon-cli": "^0.2.0" }, + "types": "./lib/index.d.ts", "scripts": { "install": "neon build --release" },