Rune
Rune
DDeno
Created by Rune on 6/21/2024 in #help
Parsing Typescript with deno_core and deno_ast fails on type annotations
Hey all, i'm trying to embed deno into my app so that users can write config file in typescript. I got inspired by the "Roll your own JavaScript runtime" blog series, but they seem to be a bit outdated... The examples in the deno_core repo are not perfect either. I'm trying to write the following code:
((globalThis) => {
globalThis.Math = {
sum: (numbers: number[]): number => Deno.core.ops.op_sum(numbers),
min: (numbers: number[]): number => Deno.core.ops.op_min(numbers)
}
})(globalThis);
((globalThis) => {
globalThis.Math = {
sum: (numbers: number[]): number => Deno.core.ops.op_sum(numbers),
min: (numbers: number[]): number => Deno.core.ops.op_min(numbers)
}
})(globalThis);
When running this as javascript, without type annotations, it works just fine. However, when i try to add the ts loader from the example (with some slight modifications), it errors on the type annotations:
called `Result::unwrap()` on an `Err` value: Uncaught SyntaxError: Unexpected token ':'
at [runjs:runtime.ts]:3:22
called `Result::unwrap()` on an `Err` value: Uncaught SyntaxError: Unexpected token ':'
at [runjs:runtime.ts]:3:22
These are my dependencies:
deno_core = { version = "0.291", features = ["include_icu_data"] }
deno_ast = { version = "0.39", features = ["emit", "transpiling", "sourcemap", "typescript", "transforms", "compat"] }
anyhow = "1"
deno_core = { version = "0.291", features = ["include_icu_data"] }
deno_ast = { version = "0.39", features = ["emit", "transpiling", "sourcemap", "typescript", "transforms", "compat"] }
anyhow = "1"
This is my main file
mod ts_loader;

use deno_core::error::AnyError;
use deno_core::*;
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;

const RUNTIME_SETUP: &str = include_str!("runtime.ts");
const EXAMPLE_SCRIPT: &str = include_str!("../example.ts");

#[op2]
fn op_sum(#[serde] nums: Vec<f64>) -> Result<f64, AnyError> {
// Sum inputs
let sum = nums.iter().fold(0.0, |a, v| a + v);
// return as a Result<f64, AnyError>
Ok(sum)
}

#[op2]
fn op_min(#[serde] nums: Vec<f64>) -> Result<f64, AnyError> {
// Sum inputs
let sum = nums.iter().min_by(|a, b| a.total_cmp(b));
match sum {
Some(x) => Ok(*x),
None => Ok(f64::NAN),
}
}

async fn run_js(script: String) -> Result<(), AnyError> {
const SUM_EXT: OpDecl = op_sum();
let sum_ext = Extension {
name: "sum_ext",
ops: std::borrow::Cow::Borrowed(&[SUM_EXT]),
..Default::default()
};

const MIN_EXT: OpDecl = op_min();
let min_ext = Extension {
name: "min_ext",
ops: std::borrow::Cow::Borrowed(&[MIN_EXT]),
..Default::default()
};

let source_map_store = ts_loader::SourceMapStore(Rc::new(RefCell::new(HashMap::new())));

// Initialize a runtime instance
let mut runtime = JsRuntime::new(RuntimeOptions {
extensions: vec![sum_ext, min_ext],
module_loader: Some(Rc::new(ts_loader::TypescriptModuleLoader {
source_maps: source_map_store.clone(),
})),
source_map_getter: Some(Rc::new(source_map_store)),
..Default::default()
});

runtime
.execute_script("[runjs:runtime.ts]", RUNTIME_SETUP)
.unwrap();
runtime
.execute_script("[evaluate_manifest]", script)
.unwrap();

Ok(())
}

#[cfg(test)]
mod tests {
use super::*;

#[tokio::test]
async fn it_works() {
match run_js(EXAMPLE_SCRIPT.to_string()).await {
Ok(_) => assert!(true),
Err(reason) => assert!(false, "{}", reason),
}
}
}
mod ts_loader;

use deno_core::error::AnyError;
use deno_core::*;
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;

const RUNTIME_SETUP: &str = include_str!("runtime.ts");
const EXAMPLE_SCRIPT: &str = include_str!("../example.ts");

#[op2]
fn op_sum(#[serde] nums: Vec<f64>) -> Result<f64, AnyError> {
// Sum inputs
let sum = nums.iter().fold(0.0, |a, v| a + v);
// return as a Result<f64, AnyError>
Ok(sum)
}

#[op2]
fn op_min(#[serde] nums: Vec<f64>) -> Result<f64, AnyError> {
// Sum inputs
let sum = nums.iter().min_by(|a, b| a.total_cmp(b));
match sum {
Some(x) => Ok(*x),
None => Ok(f64::NAN),
}
}

async fn run_js(script: String) -> Result<(), AnyError> {
const SUM_EXT: OpDecl = op_sum();
let sum_ext = Extension {
name: "sum_ext",
ops: std::borrow::Cow::Borrowed(&[SUM_EXT]),
..Default::default()
};

const MIN_EXT: OpDecl = op_min();
let min_ext = Extension {
name: "min_ext",
ops: std::borrow::Cow::Borrowed(&[MIN_EXT]),
..Default::default()
};

let source_map_store = ts_loader::SourceMapStore(Rc::new(RefCell::new(HashMap::new())));

// Initialize a runtime instance
let mut runtime = JsRuntime::new(RuntimeOptions {
extensions: vec![sum_ext, min_ext],
module_loader: Some(Rc::new(ts_loader::TypescriptModuleLoader {
source_maps: source_map_store.clone(),
})),
source_map_getter: Some(Rc::new(source_map_store)),
..Default::default()
});

runtime
.execute_script("[runjs:runtime.ts]", RUNTIME_SETUP)
.unwrap();
runtime
.execute_script("[evaluate_manifest]", script)
.unwrap();

Ok(())
}

#[cfg(test)]
mod tests {
use super::*;

#[tokio::test]
async fn it_works() {
match run_js(EXAMPLE_SCRIPT.to_string()).await {
Ok(_) => assert!(true),
Err(reason) => assert!(false, "{}", reason),
}
}
}
The loader:
3 replies