resast 0.5.0

Rusty-ECMAScript Abstract Syntax Tree
Documentation
#![cfg(feature = "esprima")]
use pretty_env_logger::try_init;
use ressa::*;

use resast::prelude::*;
use serde_json::{from_str, to_string_pretty, Value};
use std::{fs::read_to_string, path::Path};
#[test]
fn serde1() {
    let ast = Program::Script(vec![ProgramPart::Decl(Decl::Func(Func {
        id: Some(Ident::from("f")),
        body: FuncBody(vec![]),
        is_async: false,
        generator: false,
        params: vec![FuncArg::Expr(Expr::Ident(Ident::from("a")))],
    }))]);
    let json = to_string_pretty(&ast).expect("Failed to serialize ast");
    let expectation = r#"{
    "type": "Program",
    "body": [
        {
            "type": "FunctionDeclaration",
            "id": {
                "type": "Identifier",
                "name": "f"
            },
            "params": [
                {
                    "type": "Identifier",
                    "name": "a"
                }
            ],
            "body": {
                "type": "BlockStatement",
                "body": []
            },
            "generator": false,
            "expression": false,
            "async": false
        }
    ],
    "sourceType": "script"
}
"#;

    let r: serde_json::Value = serde_json::from_str(&json).expect("failed to deserialize json");
    let j: serde_json::Value =
        serde_json::from_str(&expectation).expect("failed to deserialize expectation");
    assert_eq!(r, j);
}

#[test]
fn serde_es5() {
    let json = run_rs_parse("node_modules/everything.js/es5.js");
    let esparsed = esparse("node_modules/everything.js/es5.js");
    check_jsons("es5", json, esparsed);
}
#[test]
fn serde_es2015_script() {
    let json = run_rs_parse("node_modules/everything.js/es2015-script.js");
    let esparsed = esparse("node_modules/everything.js/es2015-script.js");
    check_jsons("es2015-script", json, esparsed);
}
#[test]
fn serde_es2015_module() {
    let json = run_rs_parse("node_modules/everything.js/es2015-module.js");
    let esparsed = esparse("node_modules/everything.js/es2015-module.js");
    check_jsons("es2015-module", json, esparsed);
}

fn run_rs_parse(path: impl AsRef<Path>) -> Value {
    let module = path.as_ref().ends_with("es2015-module.js");
    eprintln!("working on {:?} -> {}", path.as_ref(), module);
    let js = get_js_file(path);
    let mut b = Builder::new();
    b.set_module(module);
    let mut parser = b.js(&js).build().expect("failed to create parser");
    let parsed = parser.parse().expect("failed to parse js");
    let raw = to_string_pretty(&parsed).expect("failed to convert to json string");
    from_str(&raw).expect("failed to revert to Value")
}

fn check_jsons(name: &str, lhs: Value, rhs: Value) {
    if lhs != rhs {
        let f1 =
            ::std::fs::File::create(&format!("{}.rs.json", name)).expect("failed to write rs.json");
        serde_json::to_writer_pretty(f1, &lhs).expect("");
        let f2 =
            ::std::fs::File::create(&format!("{}.js.json", name)).expect("failed to write js.json");
        serde_json::to_writer_pretty(f2, &rhs).expect("");
        panic!("json doesn't match");
    }
}

pub fn npm_install() {
    let mut c = ::std::process::Command::new("npm");
    c.arg("i");
    c.output().expect("failed to run npm install");
}

pub fn get_js_file(path: impl AsRef<::std::path::Path>) -> String {
    let path = path.as_ref();
    if !path.exists() {
        npm_install();
        if !path.exists() {
            panic!("npm install failed to make {:?} available", path);
        }
    }
    read_to_string(path).expect(&format!("failed to read {} to a string", path.display()))
}

pub fn esparse(path: impl AsRef<::std::path::Path>) -> Value {
    let path = path.as_ref();
    if !path.exists() {
        npm_install();
        if !path.exists() {
            panic!("npm install failed to make {:?} available", path);
        }
    }
    let esparse = ::std::process::Command::new("node")
        .arg("run_es_parse.js")
        .arg(path)
        .output()
        .expect("failed to execute run_es_parse.js");
    let json = String::from_utf8_lossy(&esparse.stdout).to_string();
    from_str(&json).expect(&format!("failed  to convert {} to Value", path.display()))
}

#[test]
fn func_args() {
    let js = "function f(a, b = 0, [c,, d = 0, ...e], {f, g: h, i = 0, i: j = 0}, ...k){}";
    let mut parser = Parser::new(&js).expect("");
    let parsed = parser.parse().expect("");
    let raw = to_string_pretty(&parsed).expect("failed to convert ron to string");
    let json: Value = from_str(&raw).expect("failed to convert string to json");
    ::std::fs::write("args.js", js).expect("failed to write args.js");
    let esparsed = esparse("args.js");
    let _ = ::std::fs::remove_file("args.js");
    if json != esparsed {
        let f1 = ::std::fs::File::create("func_args.rs.json").expect("failed to create rs.json");
        serde_json::to_writer_pretty(f1, &json).expect("failed to write rs.json");
        let f2 = ::std::fs::File::create("func_args.js.json").expect("failed to create js.json");
        serde_json::to_writer_pretty(f2, &esparsed).expect("failed to write js.json");
        panic!("json doesn't match");
    }
}

#[test]
fn arrow_func_args() {
    let _ = try_init();
    let js = "({i = 0}, ...k) => {;};";
    let mut parser = Parser::new(&js).expect("");
    let parsed = parser.parse().expect("");
    let raw = to_string_pretty(&parsed).expect("failed to convert ron to string");
    let json: Value = from_str(&raw).expect("failed to convert string to json");
    ::std::fs::write("arrow-args.js", js).expect("failed to write args.js");
    let esparsed = esparse("arrow-args.js");
    let _ = ::std::fs::remove_file("arrow-args.js");
    if json != esparsed {
        let f1 =
            ::std::fs::File::create("arrow_func_args.rs.json").expect("failed to create rs.json");
        serde_json::to_writer_pretty(f1, &json).expect("failed to write rs.json");
        let f2 =
            ::std::fs::File::create("arrow_func_args.js.json").expect("failed to create js.json");
        serde_json::to_writer_pretty(f2, &esparsed).expect("failed to write js.json");
        let _ = ::std::fs::write("arrow_func_args2.ron", &format!("{:#?}", parsed));
        panic!("json doesn't match");
    }
}