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