Skip to main content

sema_stdlib/
lib.rs

1#![allow(clippy::mutable_key_type, clippy::cloned_ref_to_slice_refs)]
2mod arithmetic;
3mod bitwise;
4mod bytevector;
5mod comparison;
6mod context;
7mod crypto;
8mod csv_ops;
9mod datetime;
10#[cfg(not(target_arch = "wasm32"))]
11mod http;
12#[cfg(not(target_arch = "wasm32"))]
13mod io;
14pub(crate) mod json;
15#[cfg(not(target_arch = "wasm32"))]
16mod kv;
17mod list;
18mod map;
19mod math;
20mod meta;
21#[cfg(not(target_arch = "wasm32"))]
22mod pdf;
23mod predicates;
24mod regex_ops;
25#[cfg(not(target_arch = "wasm32"))]
26mod server;
27mod string;
28#[cfg(not(target_arch = "wasm32"))]
29mod system;
30#[cfg(not(target_arch = "wasm32"))]
31mod terminal;
32mod text;
33mod toml_ops;
34
35use sema_core::{Caps, Env, Sandbox, Value};
36
37pub fn register_stdlib(env: &Env, sandbox: &Sandbox) {
38    arithmetic::register(env);
39    comparison::register(env);
40    context::register(env);
41    list::register(env);
42    string::register(env);
43    predicates::register(env);
44    map::register(env);
45    #[cfg(not(target_arch = "wasm32"))]
46    io::register(env, sandbox);
47    math::register(env);
48    #[cfg(not(target_arch = "wasm32"))]
49    system::register(env, sandbox);
50    json::register(env);
51    toml_ops::register(env);
52    meta::register(env);
53    regex_ops::register(env);
54    #[cfg(not(target_arch = "wasm32"))]
55    http::register(env, sandbox);
56    #[cfg(not(target_arch = "wasm32"))]
57    server::register(env, sandbox);
58    bitwise::register(env);
59    crypto::register(env);
60    datetime::register(env);
61    csv_ops::register(env);
62    bytevector::register(env);
63    #[cfg(not(target_arch = "wasm32"))]
64    terminal::register(env);
65    text::register(env);
66    #[cfg(not(target_arch = "wasm32"))]
67    kv::register(env, sandbox);
68    #[cfg(not(target_arch = "wasm32"))]
69    pdf::register(env, sandbox);
70}
71
72fn register_fn_gated(
73    env: &Env,
74    sandbox: &Sandbox,
75    cap: Caps,
76    name: &str,
77    f: impl Fn(&[Value]) -> Result<Value, sema_core::SemaError> + 'static,
78) {
79    if sandbox.is_unrestricted() {
80        register_fn(env, name, f);
81    } else {
82        let sandbox = sandbox.clone();
83        let fn_name = name.to_string();
84        register_fn(env, name, move |args| {
85            sandbox.check(cap, &fn_name)?;
86            f(args)
87        });
88    }
89}
90
91fn register_fn_path_gated(
92    env: &Env,
93    sandbox: &Sandbox,
94    cap: Caps,
95    name: &str,
96    path_args: &[usize],
97    f: impl Fn(&[Value]) -> Result<Value, sema_core::SemaError> + 'static,
98) {
99    if sandbox.is_unrestricted() {
100        register_fn(env, name, f);
101    } else {
102        let sandbox = sandbox.clone();
103        let fn_name = name.to_string();
104        let path_indices: Vec<usize> = path_args.to_vec();
105        register_fn(env, name, move |args| {
106            sandbox.check(cap, &fn_name)?;
107            for &idx in &path_indices {
108                if let Some(val) = args.get(idx) {
109                    if let Some(p) = val.as_str() {
110                        sandbox.check_path(p, &fn_name)?;
111                    }
112                }
113            }
114            f(args)
115        });
116    }
117}
118
119fn register_fn(
120    env: &Env,
121    name: &str,
122    f: impl Fn(&[Value]) -> Result<Value, sema_core::SemaError> + 'static,
123) {
124    env.set(
125        sema_core::intern(name),
126        Value::native_fn(sema_core::NativeFn::simple(name, f)),
127    );
128}