difftreelog
feat wire jrsonnet-web for experimental features
in: master
11 files changed
Cargo.lockdiffbeforeafterboth--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2695,6 +2695,7 @@
"jrsonnet-stdlib",
"jrsonnet-types",
"js-sys",
+ "num-bigint",
"rustc-hash 2.1.2",
"url",
"wasm-bindgen",
bindings/jrsonnet-web/Cargo.tomldiffbeforeafterboth--- a/bindings/jrsonnet-web/Cargo.toml
+++ b/bindings/jrsonnet-web/Cargo.toml
@@ -9,6 +9,19 @@
repository.workspace = true
version.workspace = true
+[features]
+experimental = ["exp-preserve-order", "exp-bigint"]
+exp-preserve-order = [
+ "jrsonnet-evaluator/exp-preserve-order",
+ "jrsonnet-stdlib/exp-preserve-order",
+]
+exp-bigint = [
+ "dep:num-bigint",
+ "jrsonnet-evaluator/exp-bigint",
+ "jrsonnet-stdlib/exp-bigint",
+ "jrsonnet-types/exp-bigint",
+]
+
[dependencies]
console_error_panic_hook.workspace = true
getrandom = { workspace = true, features = ["wasm_js"] }
@@ -19,6 +32,7 @@
jrsonnet-stdlib.workspace = true
jrsonnet-types.workspace = true
js-sys.workspace = true
+num-bigint = { workspace = true, optional = true }
rustc-hash.workspace = true
url.workspace = true
wasm-bindgen.workspace = true
bindings/jrsonnet-web/src/lib.rsdiffbeforeafterboth1#![allow(clippy::future_not_send, reason = "we work with js promises anyway")]23use std::{cell::RefCell, result::Result};45use jrsonnet_evaluator::{6 IStr, NumValue, ObjValue, Result as JrResult, SourcePath, SourceUrl, State, StateBuilder, Val,7 async_import::{ResolvedImportResolver, async_import},8 error,9 function::builtin::{NativeCallback, NativeCallbackHandler},10 manifest::{JsonFormat, ManifestFormat, StringFormat, ToStringFormat, YamlStreamFormat},11 tla::{TlaArg, apply_tla},12 trace::PathResolver,13 val::ArrValue,14 with_state,15};16use jrsonnet_formatter::FormatOptions;17use jrsonnet_gcmodule::Trace;18use jrsonnet_stdlib::{IniFormat, TomlFormat, XmlJsonmlFormat, YamlFormat};19use jrsonnet_types::ValType;20use js_sys::Reflect::get;21use rustc_hash::FxHashMap;22use wasm_bindgen::{convert::RefFromWasmAbi, prelude::*};2324#[wasm_bindgen]25#[derive(Clone, Copy)]26pub enum ValKind {27 Null,28 Bool,29 Num,30 Str,31 Arr,32 Obj,33 Func,34}3536thread_local! {37 static ERR_FACTORY: RefCell<Option<js_sys::Function>> = const { RefCell::new(None) };38}39#[wasm_bindgen(js_name = setErrorFactory)]40pub fn set_error_factory(f: js_sys::Function) {41 ERR_FACTORY.with(|c| *c.borrow_mut() = Some(f));42}43fn make_jrsonnet_error(message: &str, frames: js_sys::Array, cause: &JsValue) -> JsValue {44 ERR_FACTORY.with(|c| {45 c.borrow().as_ref().map_or_else(46 || js_sys::Error::new(message).into(),47 |f| {48 let args = js_sys::Array::new();49 args.push(&JsValue::from_str(message));50 args.push(&frames);51 args.push(cause);52 f.apply(&JsValue::NULL, &args)53 .unwrap_or_else(|e| js_sys::Error::new(&format!("{e:?}")).into())54 },55 )56 })57}5859fn js_error_message(e: &JsValue) -> String {60 e.dyn_ref::<js_sys::Error>().map_or_else(61 || e.as_string().unwrap_or_else(|| format!("{e:?}")),62 |err| String::from(err.message()),63 )64}6566fn unwrap_val_ref(value: &JsValue) -> Result<<WasmVal as RefFromWasmAbi>::Anchor, JsValue> {67 let ptr = get(value, &JsValue::from_str("__wbg_ptr"))68 .ok()69 .and_then(|v| v.as_f64())70 .ok_or_else(|| JsValue::from_str("expected a Val instance"))? as u32;71 if ptr == 0 {72 return Err(JsValue::from_str("Val has been freed"));73 }74 Ok(unsafe { <WasmVal as RefFromWasmAbi>::ref_from_abi(ptr) })75}7677fn js_resolver_error(prefix: &str, e: JsValue) -> JsValue {78 let msg = format!("{prefix}: {}", js_error_message(&e));79 let frames = js_sys::Array::new();80 let frame = js_sys::Object::new();81 let _ = js_sys::Reflect::set(82 &frame,83 &JsValue::from_str("desc"),84 &JsValue::from_str(prefix),85 );86 frames.push(&frame);87 make_jrsonnet_error(&msg, frames, &e)88}8990fn jrsonnet_js_error(e: &jrsonnet_evaluator::Error) -> JsValue {91 let msg = e.error().to_string();92 // let msg = format.format(e).unwrap_or_else(|_| e.to_string());93 let frames = js_sys::Array::new();94 for el in &e.trace().0 {95 let frame = js_sys::Object::new();96 let _ = js_sys::Reflect::set(97 &frame,98 &JsValue::from_str("desc"),99 &JsValue::from_str(&el.desc),100 );101 if let Some(loc) = &el.location {102 let path = loc.0.source_path().to_string();103 let _ = js_sys::Reflect::set(104 &frame,105 &JsValue::from_str("path"),106 &JsValue::from_str(&path),107 );108 let mapped = loc.0.map_source_locations(&[loc.1, loc.2]);109 let _ = js_sys::Reflect::set(110 &frame,111 &JsValue::from_str("line"),112 &JsValue::from(mapped[0].line),113 );114 let _ = js_sys::Reflect::set(115 &frame,116 &JsValue::from_str("column"),117 &JsValue::from(mapped[0].column),118 );119 }120 frames.push(&frame);121 }122 make_jrsonnet_error(&msg, frames, &JsValue::UNDEFINED)123}124125impl From<ValType> for ValKind {126 fn from(v: ValType) -> Self {127 match v {128 ValType::Null => Self::Null,129 ValType::Bool => Self::Bool,130 ValType::Num => Self::Num,131 ValType::Str => Self::Str,132 ValType::Arr => Self::Arr,133 ValType::Obj => Self::Obj,134 ValType::Func => Self::Func,135 }136 }137}138139#[wasm_bindgen(js_name = Val)]140pub struct WasmVal {141 val: Val,142 state: Option<State>,143}144145impl WasmVal {146 fn new(val: Val) -> Self {147 Self { val, state: None }148 }149 fn with_state(val: Val, state: State) -> Self {150 Self {151 val,152 state: Some(state),153 }154 }155 fn run<R>(&self, f: impl FnOnce(&Val) -> R) -> R {156 if let Some(state) = &self.state {157 let _guard = state.try_enter();158 f(&self.val)159 } else {160 f(&self.val)161 }162 }163 fn manifest_with(&self, format: impl ManifestFormat) -> Result<String, JsValue> {164 self.run(|v| v.manifest(format))165 .map_err(|e| jrsonnet_js_error(&e))166 }167}168169#[wasm_bindgen(js_class = Val)]170impl WasmVal {171 pub fn null() -> Self {172 Self::new(Val::Null)173 }174 pub fn bool(b: bool) -> Self {175 Self::new(Val::Bool(b))176 }177 pub fn num(n: f64) -> Result<Self, JsError> {178 let n = NumValue::new(n)179 .ok_or_else(|| JsError::new("only finite numbers are supported by jsonnet"))?;180 Ok(Self::new(Val::num(n)))181 }182 pub fn string(s: String) -> Self {183 Self::new(Val::string(s))184 }185 pub fn arr(items: Vec<WasmVal>) -> Self {186 Self::new(Val::arr(187 items.into_iter().map(|v| v.val).collect::<Vec<_>>(),188 ))189 }190 pub fn func(191 params: Vec<String>,192193 #[wasm_bindgen(unchecked_param_type = "(...args: Val[]) => Val")]194 callback: js_sys::Function,195 ) -> Self {196 #[allow(deprecated)]197 Self::new(Val::function(NativeCallback::new(198 params,199 JsHandler { func: callback },200 )))201 }202203 #[wasm_bindgen(getter)]204 pub fn kind(&self) -> ValKind {205 self.val.value_type().into()206 }207 #[wasm_bindgen(js_name = asBool)]208 pub fn as_bool(&self) -> Option<bool> {209 self.val.as_bool()210 }211 #[wasm_bindgen(js_name = asNum)]212 pub fn as_num(&self) -> Option<f64> {213 self.val.as_num()214 }215 #[wasm_bindgen(js_name = asString)]216 pub fn as_string(&self) -> Option<String> {217 self.val.as_str().map(|s| s.to_string())218 }219 #[wasm_bindgen(js_name = asArr)]220 pub fn as_arr(&self) -> Option<WasmArrValue> {221 self.val.as_arr().map(|arr| WasmArrValue {222 arr,223 state: self.state.clone(),224 })225 }226 #[wasm_bindgen(js_name = asObj)]227 pub fn as_obj(&self) -> Option<WasmObjValue> {228 self.val.as_obj().map(|obj| WasmObjValue {229 obj,230 state: self.state.clone(),231 })232 }233234 #[wasm_bindgen(js_name = applyTla)]235 pub fn apply_tla(236 &self,237 #[wasm_bindgen(unchecked_param_type = "Record<string, Val>")] args: &js_sys::Object,238 ) -> Result<WasmVal, JsValue> {239 let mut map: FxHashMap<IStr, TlaArg> = FxHashMap::default();240 for entry in js_sys::Object::entries(args).iter() {241 let pair: js_sys::Array = entry242 .dyn_into()243 .map_err(|_| JsValue::from_str("expected [key, value] entry"))?;244 let key = pair245 .get(0)246 .as_string()247 .ok_or_else(|| JsValue::from_str("TLA arg key must be a string"))?;248 let value = unwrap_val_ref(&pair.get(1))?;249 map.insert(key.into(), TlaArg::Val(value.val.clone()));250 }251 let val = self.val.clone();252 self.run(|_| apply_tla(&map, val))253 .map(|v| WasmVal {254 val: v,255 state: self.state.clone(),256 })257 .map_err(|e| jrsonnet_js_error(&e))258 }259260 #[wasm_bindgen(js_name = manifestJson)]261 pub fn manifest_json(&self, indent: u32) -> Result<String, JsValue> {262 self.manifest_with(JsonFormat::cli(indent as usize))263 }264 #[wasm_bindgen(js_name = manifestToString)]265 pub fn manifest_to_string(&self) -> Result<String, JsValue> {266 self.manifest_with(ToStringFormat)267 }268 #[wasm_bindgen(js_name = manifestString)]269 pub fn manifest_string(&self) -> Result<String, JsValue> {270 self.manifest_with(StringFormat)271 }272 #[wasm_bindgen(js_name = manifestYaml)]273 pub fn manifest_yaml(&self, indent: u32, quote_keys: bool) -> Result<String, JsValue> {274 self.manifest_with(YamlFormat::std_to_yaml(indent != 0, quote_keys))275 }276 #[wasm_bindgen(js_name = manifestYamlStream)]277 pub fn manifest_yaml_stream(278 &self,279 indent: u32,280 quote_keys: bool,281 c_document_end: bool,282 ) -> Result<String, JsValue> {283 self.manifest_with(YamlStreamFormat::std_yaml_stream(284 YamlFormat::std_to_yaml(indent != 0, quote_keys),285 c_document_end,286 ))287 }288 #[wasm_bindgen(js_name = manifestXmlJsonml)]289 pub fn manifest_xml_jsonml(&self) -> Result<String, JsValue> {290 self.manifest_with(XmlJsonmlFormat::std_to_xml())291 }292 #[wasm_bindgen(js_name = manifestToml)]293 pub fn manifest_toml(&self, indent: u32) -> Result<String, JsValue> {294 self.manifest_with(TomlFormat::std_to_toml(" ".repeat(indent as usize)))295 }296 #[wasm_bindgen(js_name = manifestIni)]297 pub fn manifest_ini(&self) -> Result<String, JsValue> {298 self.manifest_with(IniFormat::std())299 }300}301302#[wasm_bindgen(js_name = ArrValue)]303pub struct WasmArrValue {304 arr: ArrValue,305 state: Option<State>,306}307308#[wasm_bindgen(js_class = ArrValue)]309impl WasmArrValue {310 #[wasm_bindgen(getter)]311 pub fn length(&self) -> u32 {312 self.arr.len()313 }314 pub fn at(&self, index: u32) -> Result<Option<WasmVal>, JsValue> {315 let result = self.state.as_ref().map_or_else(316 || self.arr.get(index),317 |state| {318 let _guard = state.try_enter();319 self.arr.get(index)320 },321 );322 result323 .map(|opt: Option<Val>| {324 opt.map(|v| WasmVal {325 val: v,326 state: self.state.clone(),327 })328 })329 .map_err(|e| jrsonnet_js_error(&e))330 }331}332333#[wasm_bindgen(js_name = ObjValue)]334pub struct WasmObjValue {335 obj: ObjValue,336 state: Option<State>,337}338339#[wasm_bindgen(js_class = ObjValue)]340impl WasmObjValue {341 pub fn keys(&self) -> Vec<String> {342 self.obj343 .fields()344 .into_iter()345 .map(|s| s.to_string())346 .collect()347 }348 pub fn get(&self, key: String) -> Result<Option<WasmVal>, JsValue> {349 let result = if let Some(state) = &self.state {350 let _guard = state.try_enter();351 self.obj.get(key.into())352 } else {353 self.obj.get(key.into())354 };355 result356 .map(|opt: Option<Val>| {357 opt.map(|v| WasmVal {358 val: v,359 state: self.state.clone(),360 })361 })362 .map_err(|e| jrsonnet_js_error(&e))363 }364}365366#[derive(Trace)]367struct JsHandler {368 #[trace(skip)]369 func: js_sys::Function,370}371372#[wasm_bindgen(inline_js = r"373export function js_invoke_val_callback(cb, args) {374 return cb.apply(null, args);375}376")]377extern "C" {378 #[wasm_bindgen(catch)]379 fn js_invoke_val_callback(380 cb: &js_sys::Function,381 args: &js_sys::Array,382 ) -> Result<WasmVal, JsValue>;383}384385impl NativeCallbackHandler for JsHandler {386 fn call(&self, args: &[Val]) -> JrResult<Val> {387 let js_args = js_sys::Array::new();388 let state = with_state(|s| s);389 for arg in args {390 js_args.push(&JsValue::from(WasmVal::with_state(391 arg.clone(),392 state.clone(),393 )));394 }395 let result = js_invoke_val_callback(&self.func, &js_args).map_err(|e| {396 let msg = e397 .as_string()398 .or_else(|| {399 e.dyn_ref::<js_sys::Error>()400 .map(|err| String::from(err.message()))401 })402 .unwrap_or_else(|| format!("{e:?}"));403 error!("js callback threw: {msg}")404 })?;405 Ok(result.val)406 }407}408409#[wasm_bindgen(js_name = State)]410pub struct WasmState {411 state: State,412 resolver: Option<JsAsyncResolver>,413}414#[wasm_bindgen(js_class = State)]415impl WasmState {416 #[wasm_bindgen(constructor)]417 pub fn new(resolver: Option<ImportResolverJs>) -> Self {418 console_error_panic_hook::set_once();419 let mut state = StateBuilder::default();420 state.import_resolver(ResolvedImportResolver::new());421 let std = jrsonnet_stdlib::ContextInitializer::new(PathResolver::Absolute);422 state.context_initializer(std);423 let state = state.build();424 Self {425 state,426 resolver: resolver.map(|js| JsAsyncResolver { js }),427 }428 }429430 #[wasm_bindgen(js_name = evaluateSnippet)]431 pub fn evaluate_snippet(&self, name: &str, snippet: &str) -> Result<WasmVal, JsValue> {432 let _guard = self.state.enter();433 self.state434 .evaluate_snippet(name, snippet)435 .map(|v| WasmVal::with_state(v, self.state.clone()))436 .map_err(|e| jrsonnet_js_error(&e))437 }438439 #[wasm_bindgen(js_name = evaluateFile)]440 pub async fn evaluate_file(&self, path: String) -> Result<WasmVal, JsValue> {441 self.evaluate_file_from_impl(None, path).await442 }443444 #[wasm_bindgen(js_name = evaluateFileFrom)]445 pub async fn evaluate_file_from(&self, from: String, path: String) -> Result<WasmVal, JsValue> {446 self.evaluate_file_from_impl(Some(from), path).await447 }448}449450impl WasmState {451 async fn evaluate_file_from_impl(452 &self,453 from: Option<String>,454 path: String,455 ) -> Result<WasmVal, JsValue> {456 let resolver = self457 .resolver458 .clone()459 .ok_or_else(|| JsValue::from_str("file evaluation requires an ImportResolver"))?;460 let from = match from {461 Some(s) => {462 let url = url::Url::parse(&s).map_err(|e| JsValue::from_str(&e.to_string()))?;463 SourcePath::new(SourceUrl::new(url))464 }465 None => SourcePath::default(),466 };467 let path = async_import(self.state.clone(), resolver, &from, &path.as_str()).await?;468 let _guard = self.state.enter();469 self.state470 .import_resolved(path)471 .map(|v| WasmVal::with_state(v, self.state.clone()))472 .map_err(|e| jrsonnet_js_error(&e))473 }474}475476#[wasm_bindgen]477extern "C" {478 #[wasm_bindgen(typescript_type = "ImportResolver")]479 #[derive(Clone)]480 pub type ImportResolverJs;481482 #[wasm_bindgen(catch, method, structural, js_name = resolveFrom)]483 fn resolve_from(484 this: &ImportResolverJs,485 from: Option<String>,486 path: &str,487 ) -> Result<js_sys::Promise, JsValue>;488489 #[wasm_bindgen(catch, method, structural, js_name = loadFileContents)]490 fn load_file_contents(491 this: &ImportResolverJs,492 resolved: &str,493 ) -> Result<js_sys::Promise, JsValue>;494}495496#[wasm_bindgen(typescript_custom_section)]497const TS_IMPORT_RESOLVER: &'static str = r"498export interface ImportResolver {499 resolveFrom(from: string | undefined, path: string): Promise<string>;500 loadFileContents(resolved: string): Promise<Uint8Array>;501}502";503504#[derive(Clone)]505struct JsAsyncResolver {506 js: ImportResolverJs,507}508509impl jrsonnet_evaluator::async_import::AsyncImportResolver for JsAsyncResolver {510 type Error = JsValue;511512 async fn resolve_from(513 &self,514 from: &SourcePath,515 path: &dyn jrsonnet_evaluator::AsPathLike,516 ) -> Result<SourcePath, JsValue> {517 let from_js = (!from.is_default()).then(|| from.to_string());518 let path_str = path.as_path().as_ref().to_string_lossy().into_owned();519 let promise = self520 .js521 .resolve_from(from_js, &path_str)522 .map_err(|e| js_resolver_error("resolveFrom", e))?;523 let resolved_js = wasm_bindgen_futures::JsFuture::from(promise)524 .await525 .map_err(|e| js_resolver_error("resolveFrom", e))?;526 let resolved_str = resolved_js527 .as_string()528 .ok_or_else(|| JsValue::from_str("resolveFrom must return string"))?;529 let url = url::Url::parse(&resolved_str).map_err(|e| JsValue::from_str(&e.to_string()))?;530 Ok(SourcePath::new(SourceUrl::new(url)))531 }532533 async fn load_file_contents(&self, resolved: &SourcePath) -> Result<Vec<u8>, JsValue> {534 let resolved_str = resolved.to_string();535 let promise = self536 .js537 .load_file_contents(&resolved_str)538 .map_err(|e| js_resolver_error("loadFileContents", e))?;539 let bytes_js = wasm_bindgen_futures::JsFuture::from(promise)540 .await541 .map_err(|e| js_resolver_error("loadFileContents", e))?;542 let arr = bytes_js543 .dyn_into::<js_sys::Uint8Array>()544 .map_err(|_| JsValue::from_str("loadFileContents must return Uint8Array"))?;545 Ok(arr.to_vec())546 }547}548549#[wasm_bindgen(js_name = FormatOptions)]550pub struct WasmFormatOptions {551 indent: u8,552}553#[wasm_bindgen(js_class = FormatOptions)]554impl WasmFormatOptions {555 #[wasm_bindgen(constructor)]556 pub fn new() -> Self {557 Self { indent: 0 }558 }559560 fn build(&self) -> FormatOptions {561 FormatOptions {562 indent: self.indent,563 }564 }565}566567impl Default for WasmFormatOptions {568 fn default() -> Self {569 Self::new()570 }571}572573#[wasm_bindgen]574pub fn format(src: &str, opts: &WasmFormatOptions) -> Result<String, String> {575 match jrsonnet_formatter::format(src, &opts.build()) {576 Ok(v) => Ok(v),577 Err(e) => {578 let e = e.build();579 Err(hi_doc::source_to_ansi(&e))580 }581 }582}crates/jrsonnet-cli/Cargo.tomldiffbeforeafterboth--- a/crates/jrsonnet-cli/Cargo.toml
+++ b/crates/jrsonnet-cli/Cargo.toml
@@ -13,6 +13,12 @@
workspace = true
[features]
+experimental = [
+ "exp-preserve-order",
+ "exp-bigint",
+ "exp-null-coaelse",
+ "exp-regex",
+]
exp-preserve-order = [
"jrsonnet-evaluator/exp-preserve-order",
"jrsonnet-stdlib/exp-preserve-order",
crates/jrsonnet-evaluator/Cargo.tomldiffbeforeafterboth--- a/crates/jrsonnet-evaluator/Cargo.toml
+++ b/crates/jrsonnet-evaluator/Cargo.toml
@@ -26,6 +26,13 @@
# Use PEG parser
peg-parser = ["dep:jrsonnet-peg-parser"]
+experimental = [
+ "exp-preserve-order",
+ "exp-destruct",
+ "exp-object-iteration",
+ "exp-bigint",
+ "exp-null-coaelse",
+]
# Allows to preserve field order in objects
exp-preserve-order = []
# Implements field destructuring
crates/jrsonnet-evaluator/src/lib.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/lib.rs
+++ b/crates/jrsonnet-evaluator/src/lib.rs
@@ -42,7 +42,9 @@
use jrsonnet_gcmodule::{Cc, Trace, cc_dyn};
pub use jrsonnet_interner::{IBytes, IStr};
use jrsonnet_ir::Expr;
-pub use jrsonnet_ir::{NumValue, Source, SourcePath, SourceUrl, SourceVirtual, Span};
+pub use jrsonnet_ir::{
+ NumValue, Source, SourceDefaultIgnoreJpath, SourcePath, SourceUrl, SourceVirtual, Span,
+};
#[doc(hidden)]
pub use jrsonnet_macros;
crates/jrsonnet-ir-parser/Cargo.tomldiffbeforeafterboth--- a/crates/jrsonnet-ir-parser/Cargo.toml
+++ b/crates/jrsonnet-ir-parser/Cargo.toml
@@ -10,6 +10,8 @@
version.workspace = true
[features]
+default = []
+experimental = ["exp-null-coaelse", "exp-destruct"]
exp-null-coaelse = ["jrsonnet-ir/exp-null-coaelse"]
exp-destruct = ["jrsonnet-ir/exp-destruct"]
crates/jrsonnet-ir/Cargo.tomldiffbeforeafterboth--- a/crates/jrsonnet-ir/Cargo.toml
+++ b/crates/jrsonnet-ir/Cargo.toml
@@ -12,6 +12,7 @@
[features]
default = []
+experimental = ["exp-destruct", "exp-null-coaelse"]
exp-destruct = []
exp-null-coaelse = []
crates/jrsonnet-peg-parser/Cargo.tomldiffbeforeafterboth--- a/crates/jrsonnet-peg-parser/Cargo.toml
+++ b/crates/jrsonnet-peg-parser/Cargo.toml
@@ -22,5 +22,6 @@
[features]
default = []
+experimental = ["exp-destruct", "exp-null-coaelse"]
exp-destruct = ["jrsonnet-ir/exp-destruct"]
exp-null-coaelse = ["jrsonnet-ir/exp-null-coaelse"]
crates/jrsonnet-stdlib/Cargo.tomldiffbeforeafterboth--- a/crates/jrsonnet-stdlib/Cargo.toml
+++ b/crates/jrsonnet-stdlib/Cargo.toml
@@ -13,6 +13,12 @@
workspace = true
[features]
+experimental = [
+ "exp-preserve-order",
+ "exp-bigint",
+ "exp-null-coaelse",
+ "exp-regex",
+]
# Add order preservation flag to some functions
exp-preserve-order = ["jrsonnet-evaluator/exp-preserve-order"]
# Bigint type
crates/jrsonnet-types/Cargo.tomldiffbeforeafterboth--- a/crates/jrsonnet-types/Cargo.toml
+++ b/crates/jrsonnet-types/Cargo.toml
@@ -18,4 +18,5 @@
peg.workspace = true
[features]
+experimental = ["exp-bigint"]
exp-bigint = []