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}