Skip to content

Commit

Permalink
Merge pull request #2 from esamattis/esamattis/better-jakefile-parsing
Browse files Browse the repository at this point in the history
Better jakefile parsing
  • Loading branch information
esamattis authored Sep 2, 2024
2 parents 70bfadd + 1b9e313 commit 9c44516
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 66 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ jobs:
~/.cargo/git/db/
target/
key: ${{ runner.os }}-cargo-${{ hashFiles('Cargo.lock') }}
- name: Run tests
run: cargo test
- name: Build release
run: cargo build --release
- name: Archive as .tar.gz (Linux)
Expand Down
29 changes: 29 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: Run tests

on:
push:
branches:
- "*"

jobs:
release:
permissions:
contents: write
runs-on: "macos-latest"
steps:
- uses: actions/checkout@v4
- uses: actions-rs/toolchain@v1
with:
toolchain: 1.80.0
override: true
- uses: actions/cache@v2
with:
key: ${{ runner.os }}-cargo-${{ hashFiles('Cargo.lock') }}
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
target/
- name: Run tests
run: cargo test
17 changes: 1 addition & 16 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ edition = "2018"
[dependencies]
serde_json = "1.0"
swc_common = "0.37.5"
swc_ecma_ast = "0.118.2"
swc_ecma_parser = "0.149.1"
swc_ecma_visit = "0.104.8"

#swc_ecmascript = { version = "0.84.1", features = ["parser", "transforms", "module", "optimization", "react", "typescript", "utils", "visit", "codegen", "utils"] }
#swc_ecma_preset_env = "0.63.1"
Expand Down
129 changes: 80 additions & 49 deletions src/jakefile.rs
Original file line number Diff line number Diff line change
@@ -1,56 +1,14 @@
use std::borrow::Borrow;
use std::io::ErrorKind;
use std::path::Path;
use std::process::{Command, ExitStatus};
use swc_common::{sync::Lrc, SourceMap};
use swc_ecma_ast::{Callee, Expr, Lit, Module, ModuleItem, Stmt};
use swc_ecma_parser::{lexer::Lexer, Parser, StringInput, Syntax};
use swc_ecma_visit::swc_ecma_ast::{CallExpr, Callee, Expr, Lit, Module};
use swc_ecma_visit::Visit;

use super::runner::Runner;
use super::utils::run_command;

struct TaskVisitor {
tasks: Vec<String>,
}

impl TaskVisitor {
fn tasks_from_module(module: &Module) -> Vec<String> {
let mut visitor: TaskVisitor = TaskVisitor { tasks: Vec::new() };
visitor.visit_module(module);
return visitor.tasks;
}
}

impl Visit for TaskVisitor {
fn visit_call_expr(&mut self, n: &CallExpr) {
let Callee::Expr(e) = &n.callee else { return };

let Expr::Ident(ident) = *e.clone() else {
return;
};

if ident.sym.to_string() != "task" {
return;
}

let arg = n
.args
.get(0)
.and_then(|a| (*a.expr.clone()).lit())
.and_then(|literal| {
if let Lit::Str(s) = literal {
return Some(s.value.to_string());
} else {
return None;
}
});

if let Some(value) = arg {
self.tasks.push(value);
}
}
}

fn parse_as_swc_module(path: &str) -> Result<Option<Module>, String> {
let cm: Lrc<SourceMap> = Default::default();

Expand All @@ -66,8 +24,6 @@ fn parse_as_swc_module(path: &str) -> Result<Option<Module>, String> {
}
};

// let code = "task('myarg'); hehe('joopa');";
// let fm = cm.new_source_file(FileName::Custom("test.js".into()), code.into());
let lexer = Lexer::new(
// We want to parse ecmascript
Syntax::Es(Default::default()),
Expand All @@ -93,6 +49,61 @@ fn parse_as_swc_module(path: &str) -> Result<Option<Module>, String> {
return Ok(Some(module));
}

fn get_task_fn_calls(module: &Module) -> Vec<String> {
let mut tasks: Vec<String> = Vec::new();

for item in module.body.iter() {
// Is statement, eg. not an export declaration etc.
let ModuleItem::Stmt(stmt) = item else {
continue;
};

// Is expression statament, eg. not a variable declaration etc.
let Stmt::Expr(expr) = stmt else {
continue;
};

// is call experssion
let Expr::Call(call) = expr.expr.borrow() else {
continue;
};

// Is regular function call, eg. not super() or dynamic import() call
let Callee::Expr(expr) = &call.callee else {
continue;
};

// get the caller identifier eg. "fn" from fn()
let Expr::Ident(ident) = expr.borrow() else {
continue;
};

// is task();
if ident.sym.to_string() != "task" {
continue;
}

// get the first argument
let Some(arg) = call.args.get(0) else {
continue;
};

// The first must be a literal. Eg. not a task(ding)
let Expr::Lit(literal) = arg.expr.borrow() else {
continue;
};

// It must the a string literal
let Lit::Str(string_literal) = literal else {
continue;
};

tasks.push(string_literal.value.to_string());
}

return tasks;
}

pub struct JakeRunner {
tasks: Vec<String>,
}
Expand All @@ -116,8 +127,8 @@ impl Runner for JakeRunner {
let maybe_module = parse_as_swc_module("jakefile.js")?;

if let Some(module) = maybe_module {
self.tasks = TaskVisitor::tasks_from_module(&module);
}
self.tasks = get_task_fn_calls(&module);
};

return Ok(());
}
Expand Down Expand Up @@ -148,7 +159,8 @@ mod tests {
);
let mut parser = Parser::new_from(lexer);
let module = parser.parse_module().unwrap();
return TaskVisitor::tasks_from_module(&module);

return get_task_fn_calls(&module);
}

#[test]
Expand All @@ -159,6 +171,17 @@ mod tests {
assert_eq!(tasks, vec!["ding".to_string()]);
}

#[test]
fn test_parse_multiple_tasks() {
let code = r#"
task("ding", () => {});
task("dong", () => {});
"#;
let tasks = parse_tasks(code);

assert_eq!(tasks, vec!["ding".to_string(), "dong".to_string()]);
}

#[test]
fn test_parse_task_with_function2() {
let code = r#"task ( "ding", aFunction);"#;
Expand All @@ -167,6 +190,14 @@ mod tests {
assert_eq!(tasks, vec!["ding".to_string()]);
}

#[test]
fn test_parse_task_with_async_function() {
let code = r#"task("ding", async ()=>{});"#;
let tasks = parse_tasks(code);

assert_eq!(tasks, vec!["ding".to_string()]);
}

#[test]
fn test_does_not_parse_wrong_functions() {
let code = r#"wrong( "ding", aFunction);"#;
Expand Down

0 comments on commit 9c44516

Please sign in to comment.