1use std::cell::RefCell;
13use std::rc::Rc;
14
15use crate::consts::*;
16use crate::mini::*;
17use crate::ordered_map::OrderedMap;
18use crate::value::{js_string, js_to_int32, js_to_number, Value};
19use crate::StructError;
20
21pub type WalkClosure<'a> = dyn FnMut(&Value, &Value, &Value, &[String]) -> Value + 'a;
29
30pub type NativeFn = crate::value::NativeFn;
32
33pub type Modify = crate::value::ModifyFn;
35
36pub type Inj = Rc<RefCell<Injection>>;
37pub type SVec = Rc<RefCell<Vec<String>>>;
38
39pub fn walk(
44 val: Value,
45 before: Option<&mut WalkClosure>,
46 after: Option<&mut WalkClosure>,
47 maxdepth: Option<i64>,
48) -> Value {
49 let mut path: Vec<String> = Vec::new();
50 walk_impl(
51 val,
52 before,
53 after,
54 maxdepth,
55 &Value::Noval,
56 &Value::Noval,
57 &mut path,
58 )
59}
60
61fn walk_impl(
62 val: Value,
63 mut before: Option<&mut WalkClosure>,
64 mut after: Option<&mut WalkClosure>,
65 maxdepth: Option<i64>,
66 key: &Value,
67 parent: &Value,
68 path: &mut Vec<String>,
69) -> Value {
70 let depth = path.len() as i64;
71
72 let out = match before {
73 Some(ref mut f) => f(key, &val, parent, path),
74 None => val,
75 };
76
77 let md = match maxdepth {
78 Some(m) if m >= 0 => m,
79 _ => MAXDEPTH,
80 };
81 if md == 0 || (md > 0 && md <= depth) {
82 return out;
83 }
84
85 if is_node(&out) {
86 let entries = items_vec(&out);
87 for (ckey, child) in entries {
88 path.push(ckey.clone());
89 let res = walk_impl(
90 child,
91 before.as_deref_mut(),
92 after.as_deref_mut(),
93 maxdepth,
94 &Value::str(ckey.clone()),
95 &out,
96 path,
97 );
98 path.pop();
99 set_prop(out.clone(), &Value::str(ckey), res);
100 }
101 }
102
103 match after {
104 Some(ref mut f) => f(key, &out, parent, path),
105 None => out,
106 }
107}
108
109const T_INSTANCE_I: i64 = T_INSTANCE as i64;
114
115pub fn merge(val: &Value, maxdepth: Option<i64>) -> Value {
116 let md = match slice(
117 Value::Num(maxdepth.unwrap_or(MAXDEPTH) as f64),
118 Some(0),
119 None,
120 false,
121 ) {
122 Value::Num(n) => n as i64,
123 _ => MAXDEPTH,
124 };
125
126 let list: Vec<Value> = match val {
127 Value::List(l) => l.borrow().clone(),
128 other => return other.clone(),
129 };
130
131 if list.is_empty() {
132 return Value::Noval;
133 }
134 if list.len() == 1 {
135 return list[0].clone();
136 }
137
138 let mut out = match &list[0] {
139 Value::Noval => Value::empty_map(),
140 other => other.clone(),
141 };
142
143 for obj in list.iter().skip(1) {
144 let obj = obj.clone();
145 if !is_node(&obj) {
146 out = obj;
147 continue;
148 }
149
150 let cur: Rc<RefCell<Vec<Value>>> = Rc::new(RefCell::new(vec![out.clone()]));
151 let dst: Rc<RefCell<Vec<Value>>> = Rc::new(RefCell::new(vec![out.clone()]));
152
153 let cur_b = cur.clone();
154 let dst_b = dst.clone();
155 let mut before = move |key: &Value, v: &Value, _parent: &Value, path: &[String]| -> Value {
156 let pi = path.len() as i64;
157 let mut ret = v.clone();
158
159 if md <= pi {
160 let target = cur_b
161 .borrow()
162 .get((pi - 1) as usize)
163 .cloned()
164 .unwrap_or(Value::Noval);
165 set_prop(target, key, v.clone());
166 } else if !is_node(v) {
167 let mut cb = cur_b.borrow_mut();
168 grow(&mut cb, pi as usize);
169 cb[pi as usize] = v.clone();
170 } else {
171 let tval = {
172 let d = if pi > 0 {
173 let prev = dst_b
174 .borrow()
175 .get((pi - 1) as usize)
176 .cloned()
177 .unwrap_or(Value::Noval);
178 get_prop(&prev, key, Value::Noval)
179 } else {
180 dst_b
181 .borrow()
182 .get(pi as usize)
183 .cloned()
184 .unwrap_or(Value::Noval)
185 };
186 let mut db = dst_b.borrow_mut();
187 grow(&mut db, pi as usize);
188 db[pi as usize] = d.clone();
189 d
190 };
191 let mut cb = cur_b.borrow_mut();
192 grow(&mut cb, pi as usize);
193 if tval.is_noval() && (typify(v) & T_INSTANCE_I) == 0 {
194 cb[pi as usize] = if is_list(v) {
195 Value::empty_list()
196 } else {
197 Value::empty_map()
198 };
199 } else if typify(v) == typify(&tval) {
200 cb[pi as usize] = tval;
201 } else {
202 cb[pi as usize] = v.clone();
203 ret = Value::Noval;
204 }
205 }
206 ret
207 };
208
209 let cur_a = cur.clone();
210 let mut after = move |key: &Value, _v: &Value, _parent: &Value, path: &[String]| -> Value {
211 let ci = path.len() as i64;
212 let (target, value) = {
213 let cb = cur_a.borrow();
214 (
215 cb.get((ci - 1) as usize).cloned().unwrap_or(Value::Noval),
216 cb.get(ci as usize).cloned().unwrap_or(Value::Noval),
217 )
218 };
219 set_prop(target, key, value.clone());
220 value
221 };
222
223 out = walk(obj, Some(&mut before), Some(&mut after), maxdepth);
224 }
225
226 if md == 0 {
227 let last = get_elem(&Value::list(list.clone()), &Value::Num(-1.0), Value::Noval);
228 out = match &last {
229 Value::List(_) => Value::empty_list(),
230 Value::Map(_) => Value::empty_map(),
231 other => other.clone(),
232 };
233 }
234
235 out
236}
237
238fn grow(v: &mut Vec<Value>, idx: usize) {
239 while v.len() <= idx {
240 v.push(Value::Noval);
241 }
242}
243
244pub struct Injection {
249 pub mode: i64,
250 pub full: bool,
251 pub key_i: i64,
252 pub keys: SVec,
253 pub key: String,
254 pub val: Value,
255 pub parent: Value,
256 pub path: Vec<String>,
257 pub nodes: Vec<Value>,
258 pub handler: NativeFn,
259 pub errs: Value, pub meta: Value, pub dparent: Value,
262 pub dpath: Vec<String>,
263 pub base: Option<String>,
264 pub modify: Option<Modify>,
265 pub extra: Option<Value>,
266 pub prior: Option<Inj>,
267}
268
269#[derive(Default, Clone)]
271pub struct InjectDef {
272 pub base: Option<String>,
273 pub errs: Option<Value>,
274 pub meta: Option<Value>,
275 pub modify: Option<Modify>,
276 pub handler: Option<NativeFn>,
277 pub extra: Option<Value>,
278 pub dparent: Option<Value>,
279 pub dpath: Option<Vec<String>>,
280 pub key: Option<Value>,
281}
282
283impl Injection {
284 pub fn from_def(def: Option<&InjectDef>) -> Inj {
287 let inj = Injection {
288 mode: M_VAL,
289 full: false,
290 key_i: 0,
291 keys: Rc::new(RefCell::new(vec![S_DTOP.to_string()])),
292 key: S_DTOP.to_string(),
293 val: Value::Noval,
294 parent: Value::Noval,
295 path: vec![S_DTOP.to_string()],
296 nodes: vec![Value::Noval],
297 handler: inject_handler_fn(),
298 errs: Value::empty_list(),
299 meta: Value::empty_map(),
300 dparent: Value::Noval,
301 dpath: vec![S_DTOP.to_string()],
302 base: None,
303 modify: None,
304 extra: None,
305 prior: None,
306 };
307 let inj = Rc::new(RefCell::new(inj));
308 if let Some(d) = def {
309 let mut b = inj.borrow_mut();
310 if let Some(x) = &d.base {
311 b.base = Some(x.clone());
312 }
313 if let Some(x) = &d.errs {
314 b.errs = x.clone();
315 }
316 if let Some(x) = &d.meta {
317 b.meta = x.clone();
318 }
319 if let Some(x) = &d.modify {
320 b.modify = Some(x.clone());
321 }
322 if let Some(x) = &d.handler {
323 b.handler = x.clone();
324 }
325 if let Some(x) = &d.extra {
326 b.extra = Some(x.clone());
327 }
328 if let Some(x) = &d.dparent {
329 b.dparent = x.clone();
330 }
331 if let Some(x) = &d.dpath {
332 b.dpath = x.clone();
333 }
334 if let Some(x) = &d.key {
335 b.key = str_key(x.clone());
336 }
337 }
338 inj
339 }
340
341 fn has_handler(def: Option<&InjectDef>) -> bool {
342 def.map(|d| d.handler.is_some()).unwrap_or(false)
343 }
344
345 pub fn root(val: Value, parent: Value) -> Inj {
347 let parent_clone = parent.clone();
348 Rc::new(RefCell::new(Injection {
349 mode: M_VAL,
350 full: false,
351 key_i: 0,
352 keys: Rc::new(RefCell::new(vec![S_DTOP.to_string()])),
353 key: S_DTOP.to_string(),
354 val,
355 parent,
356 path: vec![S_DTOP.to_string()],
357 nodes: vec![parent_clone],
358 handler: inject_handler_fn(),
359 errs: Value::empty_list(),
360 meta: Value::empty_map(),
361 dparent: Value::Noval,
362 dpath: vec![S_DTOP.to_string()],
363 base: Some(S_DTOP.to_string()),
364 modify: None,
365 extra: None,
366 prior: None,
367 }))
368 }
369
370 pub fn descend(this: &Inj) {
371 {
373 let b = this.borrow();
374 if let Value::Map(m) = &b.meta {
375 let cur = m
376 .borrow()
377 .get("__d")
378 .and_then(|v| v.as_num())
379 .unwrap_or(0.0);
380 m.borrow_mut()
381 .insert("__d".to_string(), Value::Num(cur + 1.0));
382 }
383 }
384 let (parentkey, has_dparent, dpath_len, last_part) = {
385 let b = this.borrow();
386 let parentkey = if b.path.len() >= 2 {
387 Some(b.path[b.path.len() - 2].clone())
388 } else {
389 None
390 };
391 (
392 parentkey,
393 !b.dparent.is_noval(),
394 b.dpath.len(),
395 b.dpath.last().cloned(),
396 )
397 };
398
399 if !has_dparent {
400 if dpath_len > 1 {
401 if let Some(pk) = parentkey {
402 this.borrow_mut().dpath.push(pk);
403 }
404 }
405 } else if let Some(pk) = parentkey {
406 let newdparent = {
407 let b = this.borrow();
408 get_prop(&b.dparent, &Value::str(pk.clone()), Value::Noval)
409 };
410 let mut b = this.borrow_mut();
411 b.dparent = newdparent;
412 if last_part.as_deref() == Some(format!("$:{pk}").as_str()) {
413 let n = b.dpath.len();
414 b.dpath.truncate(n.saturating_sub(1));
415 } else {
416 b.dpath.push(pk);
417 }
418 }
419 }
420
421 pub fn child(this: &Inj, key_i: i64, keys: SVec) -> Inj {
422 let (
423 key,
424 parent_val,
425 cval,
426 path,
427 nodes,
428 mode,
429 handler,
430 modify,
431 base,
432 meta,
433 errs,
434 dpath,
435 dparent,
436 ) = {
437 let b = this.borrow();
438 let key = str_key(
439 keys.borrow()
440 .get(key_i.max(0) as usize)
441 .cloned()
442 .map(Value::Str)
443 .unwrap_or(Value::Noval),
444 );
445 let parent_val = b.val.clone();
446 let cval = get_prop(&parent_val, &Value::str(key.clone()), Value::Noval);
447 let mut path = b.path.clone();
448 path.push(key.clone());
449 let mut nodes = b.nodes.clone();
450 nodes.push(parent_val.clone());
451 (
452 key,
453 parent_val,
454 cval,
455 path,
456 nodes,
457 b.mode,
458 b.handler.clone(),
459 b.modify.clone(),
460 b.base.clone(),
461 b.meta.clone(),
462 b.errs.clone(),
463 b.dpath.clone(),
464 b.dparent.clone(),
465 )
466 };
467 Rc::new(RefCell::new(Injection {
468 mode,
469 full: false,
470 key_i,
471 keys,
472 key,
473 val: cval,
474 parent: parent_val,
475 path,
476 nodes,
477 handler,
478 errs,
479 meta,
480 dparent,
481 dpath,
482 base,
483 modify,
484 extra: None,
485 prior: Some(Rc::clone(this)),
486 }))
487 }
488
489 pub fn setval(this: &Inj, val: Value, ancestor: Option<i64>) -> Value {
490 let anc = ancestor.unwrap_or(0);
491 if anc < 2 {
492 let (parent, key) = {
493 let b = this.borrow();
494 (b.parent.clone(), b.key.clone())
495 };
496 if val.is_noval() {
497 let np = del_prop(parent, &Value::str(key));
498 this.borrow_mut().parent = np.clone();
499 np
500 } else {
501 set_prop(parent, &Value::str(key), val)
502 }
503 } else {
504 let (aval, akey) = {
505 let b = this.borrow();
506 let n = b.nodes.len() as i64;
507 let aval = if n - anc >= 0 {
508 b.nodes[(n - anc) as usize].clone()
509 } else {
510 Value::Noval
511 };
512 let pn = b.path.len() as i64;
513 let akey = if pn - anc >= 0 {
514 b.path[(pn - anc) as usize].clone()
515 } else {
516 String::new()
517 };
518 (aval, akey)
519 };
520 if val.is_noval() {
521 del_prop(aval, &Value::str(akey))
522 } else {
523 set_prop(aval, &Value::str(akey), val)
524 }
525 }
526 }
527}
528
529pub fn get_path(store: &Value, path: &Value, injdef: Option<&InjectDef>) -> Value {
534 let inj: Option<Inj> = injdef.map(|_| Injection::from_def(injdef));
535 get_path_inj(store, path, inj.as_ref())
536}
537
538pub fn get_path_inj(store: &Value, path: &Value, injdef: Option<&Inj>) -> Value {
541 let mut parts: Vec<String> = match path {
542 Value::List(l) => l
543 .borrow()
544 .iter()
545 .map(|x| match x {
546 Value::Str(s) => s.clone(),
547 other => js_string(other),
548 })
549 .collect(),
550 Value::Str(s) => s.split('.').map(|p| p.to_string()).collect(),
551 Value::Num(n) => vec![str_key(Value::Num(*n))],
552 _ => return Value::Noval,
553 };
554
555 let base = injdef.and_then(|i| i.borrow().base.clone());
556 let src = match &base {
557 Some(b) => get_prop(store, &Value::str(b.clone()), store.clone()),
558 None => store.clone(),
559 };
560 let numparts = parts.len();
561 let dparent = injdef
562 .map(|i| i.borrow().dparent.clone())
563 .unwrap_or(Value::Noval);
564
565 let mut val = store.clone();
566
567 let path_nullish = matches!(path, Value::Noval | Value::Null);
568 if path_nullish
569 || matches!(store, Value::Noval | Value::Null)
570 || (numparts == 1 && parts[0].is_empty())
571 {
572 val = src.clone();
573 } else if numparts > 0 {
574 if numparts == 1 {
575 val = get_prop(store, &Value::str(parts[0].clone()), Value::Noval);
576 }
577
578 if !is_func(&val) {
579 val = src.clone();
580
581 if let Some(inj) = injdef {
583 let meta = inj.borrow().meta.clone();
584 let first = parts[0].clone();
585 if let Some(caps) = R_META_PATH.captures(&first) {
586 if !meta.is_noval() {
587 val = get_prop(&meta, &Value::str(caps[1].to_string()), Value::Noval);
588 parts[0] = caps[3].to_string();
589 }
590 }
591 }
592
593 let dpath: Vec<String> = injdef.map(|i| i.borrow().dpath.clone()).unwrap_or_default();
594
595 let mut p_i = 0usize;
596 while !val.is_noval() && p_i < numparts {
597 let mut part = parts[p_i].clone();
598
599 if let Some(inj) = injdef {
600 if part == S_DKEY {
601 part = inj.borrow().key.clone();
602 } else if let Some(rest) = part.strip_prefix("$GET:") {
603 part = js_string(&get_path_inj(&src, &Value::str(drop_last(rest)), None));
604 } else if let Some(rest) = part.strip_prefix("$REF:") {
605 let spec = get_prop(store, &Value::str(S_DSPEC), Value::Noval);
606 part = js_string(&get_path_inj(&spec, &Value::str(drop_last(rest)), None));
607 } else if let Some(rest) = part.strip_prefix("$META:") {
608 let meta = inj.borrow().meta.clone();
609 part = js_string(&get_path_inj(&meta, &Value::str(drop_last(rest)), None));
610 }
611 }
612
613 if part.contains("$$") {
616 part = part.replace("$$", "$");
617 }
618
619 if part.is_empty() {
620 let mut ascends = 0i64;
621 while parts.get(1 + p_i).map(|s| s.is_empty()).unwrap_or(false) {
622 ascends += 1;
623 p_i += 1;
624 }
625
626 if injdef.is_some() && ascends > 0 {
627 if p_i == parts.len() - 1 {
628 ascends -= 1;
629 }
630 if ascends == 0 {
631 val = dparent.clone();
632 } else {
633 let head = slice(
635 Value::list(dpath.iter().cloned().map(Value::Str).collect()),
636 Some(-ascends),
637 None,
638 false,
639 );
640 let mut fullpath: Vec<String> = match &head {
641 Value::List(l) => l
642 .borrow()
643 .iter()
644 .map(|x| x.as_str().map(|s| s.to_string()).unwrap_or_default())
645 .collect(),
646 _ => Vec::new(),
647 };
648 fullpath.extend_from_slice(&parts[p_i + 1..]);
649 if ascends <= dpath.len() as i64 {
650 val = get_path_inj(
651 store,
652 &Value::list(fullpath.into_iter().map(Value::Str).collect()),
653 None,
654 );
655 } else {
656 val = Value::Noval;
657 }
658 break;
659 }
660 } else {
661 val = dparent.clone();
662 }
663 } else {
664 val = get_prop(&val, &Value::str(part), Value::Noval);
665 }
666
667 p_i += 1;
668 }
669 }
670 }
671
672 if let Some(inj) = injdef {
673 let handler = inj.borrow().handler.clone();
674 let r = pathify(path, None, None);
675 val = handler(inj, &val, &r, store);
676 }
677
678 val
679}
680
681fn drop_last(s: &str) -> String {
682 let chars: Vec<char> = s.chars().collect();
683 if chars.is_empty() {
684 String::new()
685 } else {
686 chars[..chars.len() - 1].iter().collect()
687 }
688}
689
690pub fn set_path(store: &Value, path: &Value, val: Value, injdef: Option<&InjectDef>) -> Value {
695 let parts: Vec<Value> = match path {
698 Value::List(l) => l.borrow().clone(),
699 Value::Str(s) => s.split('.').map(Value::str).collect(),
700 Value::Num(n) => vec![Value::Num(*n)],
701 _ => return Value::Noval,
702 };
703 if parts.is_empty() {
704 return Value::Noval;
705 }
706
707 let base = injdef.and_then(|d| d.base.clone());
708 let numparts = parts.len();
709 let mut parent = match &base {
710 Some(b) => get_prop(store, &Value::str(b.clone()), store.clone()),
711 None => store.clone(),
712 };
713
714 for p_i in 0..numparts - 1 {
715 let part_key = parts[p_i].clone();
716 let next_parent = get_prop(&parent, &part_key, Value::Noval);
717 let next_parent = if !is_node(&next_parent) {
718 let next_is_num = parts
719 .get(p_i + 1)
720 .map(|p| typify(p) & (T_NUMBER as i64) != 0)
721 .unwrap_or(false);
722 let np = if next_is_num {
723 Value::empty_list()
724 } else {
725 Value::empty_map()
726 };
727 set_prop(parent.clone(), &part_key, np.clone());
728 np
729 } else {
730 next_parent
731 };
732 parent = next_parent;
733 }
734
735 let last = parts[numparts - 1].clone();
736 if val.is_delete() {
737 del_prop(parent.clone(), &last);
738 } else {
739 set_prop(parent.clone(), &last, val);
740 }
741
742 parent
743}
744
745pub fn inject_handler_fn() -> NativeFn {
753 Rc::new(inject_handler)
754}
755
756fn inject_handler(inj: &Inj, val: &Value, r: &str, store: &Value) -> Value {
757 let iscmd = is_func(val) && (r.is_empty() || r.starts_with('$'));
758 if iscmd {
759 if let Value::Func(f) = val {
760 return f(inj, val, r, store);
761 }
762 }
763 let (mode, full) = {
764 let b = inj.borrow();
765 (b.mode, b.full)
766 };
767 if mode == M_VAL && full {
768 Injection::setval(inj, val.clone(), None);
769 }
770 val.clone()
771}
772
773fn injectstr(val: &str, store: &Value, inj: Option<&Inj>) -> Value {
775 if val.is_empty() {
776 return Value::str("");
777 }
778
779 if let Some(caps) = R_INJECTION_FULL.captures(val) {
780 if let Some(i) = inj {
781 i.borrow_mut().full = true;
782 }
783 let mut pathref = caps[1].to_string();
784 if pathref.chars().count() > 3 {
785 pathref = pathref.replace("$BT", S_BT).replace("$DS", S_DS);
786 }
787 return get_path_inj(store, &Value::str(pathref), inj);
788 }
789
790 let out_str = R_INJECTION_PARTIAL
792 .replace_all(val, |caps: &crate::re::Captures<'_>| -> String {
793 let mut r = caps[1].to_string();
794 if r.chars().count() > 3 {
795 r = r.replace("$BT", S_BT).replace("$DS", S_DS);
796 }
797 if let Some(i) = inj {
798 i.borrow_mut().full = false;
799 }
800 let found = get_path_inj(store, &Value::str(r), inj);
801 match &found {
802 Value::Noval => String::new(),
803 Value::Str(s) => s.clone(),
804 other => jsonify(
805 other,
806 Some(&JsonFlags {
807 indent: 0,
808 offset: 0,
809 }),
810 ),
811 }
812 })
813 .to_string();
814
815 if let Some(i) = inj {
816 let handler = {
817 i.borrow_mut().full = true;
818 i.borrow().handler.clone()
819 };
820 return handler(i, &Value::str(out_str), val, store);
821 }
822 Value::str(out_str)
823}
824
825pub fn inject(val: Value, store: &Value, injdef: Option<&InjectDef>) -> Value {
826 let inj = make_root_injection(val.clone(), store, injdef);
827 inject_inj(val, store, &inj)
828}
829
830fn make_root_injection(val: Value, store: &Value, injdef: Option<&InjectDef>) -> Inj {
833 let mut top = OrderedMap::new();
834 top.insert(S_DTOP.to_string(), val.clone());
835 let inj = Injection::root(val, Value::map(top));
836 {
837 let mut b = inj.borrow_mut();
838 b.dparent = store.clone();
839 let store_errs = get_prop(store, &Value::str(S_DERRS), Value::Noval);
840 if !store_errs.is_noval() {
841 b.errs = store_errs;
842 }
843 if let Value::Map(m) = &b.meta {
844 m.borrow_mut().insert("__d".to_string(), Value::Num(0.0));
845 }
846 if let Some(d) = injdef {
847 if let Some(x) = &d.modify {
848 b.modify = Some(x.clone());
849 }
850 if let Some(x) = &d.extra {
851 b.extra = Some(x.clone());
852 }
853 if let Some(x) = &d.meta {
854 b.meta = x.clone();
855 }
856 if let Some(x) = &d.handler {
857 b.handler = x.clone();
858 }
859 }
860 }
861 inj
862}
863
864#[allow(unused_assignments)]
868fn inject_inj(mut val: Value, store: &Value, inj: &Inj) -> Value {
869 Injection::descend(inj);
870
871 if is_node(&val) {
872 let nodekeys: SVec = {
874 let ks = keysof_vec(&val);
875 if is_map(&val) {
876 let (mut plain, dollar): (Vec<String>, Vec<String>) =
877 ks.into_iter().partition(|k| !k.contains(S_DS));
878 plain.extend(dollar);
879 Rc::new(RefCell::new(plain))
880 } else {
881 Rc::new(RefCell::new(ks))
882 }
883 };
884
885 let mut nk_i: i64 = 0;
886 loop {
887 if nk_i < 0 {
888 nk_i += 1;
889 continue;
890 }
891 if nk_i as usize >= nodekeys.borrow().len() {
892 break;
893 }
894
895 let childinj = Injection::child(inj, nk_i, nodekeys.clone());
896 let nodekey = childinj.borrow().key.clone();
897 childinj.borrow_mut().mode = M_KEYPRE;
898
899 let prekey = injectstr(&nodekey, store, Some(&childinj));
900 nk_i = childinj.borrow().key_i;
901 if !prekey.is_noval() {
905 let cval = get_prop(&val, &prekey, Value::Noval);
906 {
907 let mut b = childinj.borrow_mut();
908 b.val = cval.clone();
909 b.mode = M_VAL;
910 }
911 inject_inj(cval, store, &childinj);
912 nk_i = childinj.borrow().key_i;
913
914 childinj.borrow_mut().mode = M_KEYPOST;
915 injectstr(&nodekey, store, Some(&childinj));
916 nk_i = childinj.borrow().key_i;
917 }
918
919 nk_i += 1;
920 }
921 } else if let Value::Str(s) = val.clone() {
922 inj.borrow_mut().mode = M_VAL;
923 let r = injectstr(&s, store, Some(inj));
924 val = r.clone();
925 if !val.is_skip() {
926 Injection::setval(inj, val.clone(), None);
927 }
928 }
929
930 let modify = inj.borrow().modify.clone();
932 if let Some(m) = modify {
933 if !val.is_skip() {
934 let (mkey, mparent) = {
935 let b = inj.borrow();
936 (b.key.clone(), b.parent.clone())
937 };
938 let mval = get_prop(&mparent, &Value::str(mkey.clone()), Value::Noval);
939 m(&mval, &Value::str(mkey), &mparent, inj, store);
940 }
941 }
942
943 inj.borrow_mut().val = val;
944 let parent = inj.borrow().parent.clone();
945 lookup(&parent, &Value::str(S_DTOP))
948}
949
950const T_ANY_I: i64 = T_ANY as i64;
953
954fn errs_push(inj: &Inj, msg: String) {
955 let errs = inj.borrow().errs.clone();
956 if let Value::List(l) = &errs {
957 l.borrow_mut().push(Value::Str(msg));
958 }
959}
960
961fn placement_str(mode: i64) -> &'static str {
962 match mode {
963 M_VAL => "value",
964 M_KEYPRE | M_KEYPOST => "key",
965 _ => "",
966 }
967}
968
969pub fn check_placement(modes: i64, ijname: &str, parent_types: i64, inj: &Inj) -> bool {
970 let (mode, parent) = {
971 let b = inj.borrow();
972 (b.mode, b.parent.clone())
973 };
974 if modes & mode == 0 {
975 let expected: Vec<&str> = [M_KEYPRE, M_KEYPOST, M_VAL]
976 .iter()
977 .filter(|m| modes & **m != 0)
978 .map(|m| placement_str(*m))
979 .collect();
980 errs_push(
981 inj,
982 format!(
983 "${ijname}: invalid placement as {}, expected: {}.",
984 placement_str(mode),
985 expected.join(",")
986 ),
987 );
988 return false;
989 }
990 if !is_empty(&Value::Num(parent_types as f64)) {
991 let ptype = typify(&parent);
992 if parent_types & ptype == 0 {
993 errs_push(
994 inj,
995 format!(
996 "${ijname}: invalid placement in parent {}, expected: {}.",
997 type_name(ptype),
998 type_name(parent_types)
999 ),
1000 );
1001 return false;
1002 }
1003 }
1004 true
1005}
1006
1007pub fn injector_args(arg_types: &[i64], args: &[Value]) -> Vec<Value> {
1008 let mut found: Vec<Value> = Vec::with_capacity(1 + arg_types.len());
1009 found.push(Value::Noval);
1010 for (i, at) in arg_types.iter().enumerate() {
1011 let arg = args.get(i).cloned().unwrap_or(Value::Noval);
1012 let argtype = typify(&arg);
1013 if at & argtype == 0 {
1014 found[0] = Value::str(format!(
1015 "invalid argument: {} ({} at position {}) is not of type: {}.",
1016 stringify(&arg, Some(22), false),
1017 type_name(argtype),
1018 1 + i,
1019 type_name(*at)
1020 ));
1021 return found;
1022 }
1023 found.push(arg);
1024 }
1025 found
1026}
1027
1028pub fn inject_child(child: Value, store: &Value, inj: &Inj) -> Inj {
1029 let prior = inj.borrow().prior.clone();
1030 let cinj: Inj = match prior {
1031 None => Rc::clone(inj),
1032 Some(p) => {
1033 let pprior = p.borrow().prior.clone();
1034 match pprior {
1035 Some(pp) => {
1036 let (pki, pkeys, pkey) = {
1037 let b = p.borrow();
1038 (b.key_i, b.keys.clone(), b.key.clone())
1039 };
1040 let c = Injection::child(&pp, pki, pkeys);
1041 c.borrow_mut().val = child.clone();
1042 let cparent = c.borrow().parent.clone();
1043 set_prop(cparent, &Value::str(pkey), child.clone());
1044 c
1045 }
1046 None => {
1047 let (ki, keys, key) = {
1048 let b = inj.borrow();
1049 (b.key_i, b.keys.clone(), b.key.clone())
1050 };
1051 let c = Injection::child(&p, ki, keys);
1052 c.borrow_mut().val = child.clone();
1053 let cparent = c.borrow().parent.clone();
1054 set_prop(cparent, &Value::str(key), child.clone());
1055 c
1056 }
1057 }
1058 }
1059 };
1060 let _ = inject_inj(child, store, &cinj);
1061 cinj
1062}
1063
1064const FORMATTER_NAMES: [&str; 7] = [
1065 "identity", "upper", "lower", "string", "number", "integer", "concat",
1066];
1067
1068fn apply_formatter(name: &str, k: &Value, v: &Value) -> Value {
1069 match name {
1070 "identity" => v.clone(),
1071 "upper" => {
1072 if is_node(v) {
1073 v.clone()
1074 } else {
1075 Value::str(js_string(v).to_uppercase())
1076 }
1077 }
1078 "lower" => {
1079 if is_node(v) {
1080 v.clone()
1081 } else {
1082 Value::str(js_string(v).to_lowercase())
1083 }
1084 }
1085 "string" => {
1086 if is_node(v) {
1087 v.clone()
1088 } else {
1089 Value::str(js_string(v))
1090 }
1091 }
1092 "number" => {
1093 if is_node(v) {
1094 v.clone()
1095 } else {
1096 let n = js_to_number(v);
1097 Value::Num(if n.is_nan() { 0.0 } else { n })
1098 }
1099 }
1100 "integer" => {
1101 if is_node(v) {
1102 v.clone()
1103 } else {
1104 let n = js_to_number(v);
1105 let n = if n.is_nan() { 0.0 } else { n };
1106 Value::Num(js_to_int32(n) as f64)
1107 }
1108 }
1109 "concat" => {
1110 if k.is_noval() && is_list(v) {
1111 Value::str(
1112 items_vec(v)
1113 .iter()
1114 .map(|(_, n)| {
1115 if is_node(n) {
1116 String::new()
1117 } else {
1118 js_string(n)
1119 }
1120 })
1121 .collect::<Vec<_>>()
1122 .join(""),
1123 )
1124 } else {
1125 v.clone()
1126 }
1127 }
1128 _ => v.clone(),
1129 }
1130}
1131
1132fn transform_format(inj: &Inj, _val: &Value, _r: &str, store: &Value) -> Value {
1134 inj.borrow().keys.borrow_mut().truncate(1);
1135 if inj.borrow().mode != M_VAL {
1136 return Value::Noval;
1137 }
1138 let (parent, path, nodes) = {
1139 let b = inj.borrow();
1140 (b.parent.clone(), b.path.clone(), b.nodes.clone())
1141 };
1142 let name = lookup(&parent, &Value::Num(1.0));
1143 let child = lookup(&parent, &Value::Num(2.0));
1144 let tkey = path
1145 .get(path.len().saturating_sub(2))
1146 .cloned()
1147 .unwrap_or_default();
1148 let nlen = nodes.len();
1149 let target = if nlen >= 2 {
1150 nodes[nlen - 2].clone()
1151 } else if nlen >= 1 {
1152 nodes[nlen - 1].clone()
1153 } else {
1154 Value::Noval
1155 };
1156
1157 let cinj = inject_child(child, store, inj);
1158 let resolved = cinj.borrow().val.clone();
1159
1160 let fname: Option<String> = name
1161 .as_str()
1162 .filter(|n| FORMATTER_NAMES.contains(n))
1163 .map(|s| s.to_string());
1164 if fname.is_none() && !is_func(&name) {
1165 errs_push(
1166 inj,
1167 format!("$FORMAT: unknown format: {}.", js_string(&name)),
1168 );
1169 return Value::Noval;
1170 }
1171
1172 let out = if let Some(fn_name) = &fname {
1173 let mut fmt = |k: &Value, v: &Value, _p: &Value, _t: &[String]| -> Value {
1174 apply_formatter(fn_name, k, v)
1175 };
1176 walk(resolved, Some(&mut fmt), None, None)
1177 } else if let Value::Func(f) = &name {
1178 let f = f.clone();
1179 let mut fmt =
1180 |_k: &Value, v: &Value, _p: &Value, _t: &[String]| -> Value { f(inj, v, "", store) };
1181 walk(resolved, Some(&mut fmt), None, None)
1182 } else {
1183 resolved
1184 };
1185
1186 set_prop(target, &Value::str(tkey), out.clone());
1187 out
1188}
1189
1190fn transform_apply(inj: &Inj, _val: &Value, _r: &str, store: &Value) -> Value {
1192 if !check_placement(M_VAL, "APPLY", T_LIST as i64, inj) {
1193 return Value::Noval;
1194 }
1195 let (parent, path, nodes) = {
1196 let b = inj.borrow();
1197 (b.parent.clone(), b.path.clone(), b.nodes.clone())
1198 };
1199 let args: Vec<Value> = slice(parent.clone(), Some(1), None, false)
1200 .as_list()
1201 .map(|l| l.borrow().clone())
1202 .unwrap_or_default();
1203 let ia = injector_args(&[T_FUNCTION as i64, T_ANY as i64], &args);
1204 if let Value::Str(e) = &ia[0] {
1205 errs_push(inj, format!("$APPLY: {e}"));
1206 return Value::Noval;
1207 }
1208 let apply = ia.get(1).cloned().unwrap_or(Value::Noval);
1209 let child = ia.get(2).cloned().unwrap_or(Value::Noval);
1210 let tkey = path
1211 .get(path.len().saturating_sub(2))
1212 .cloned()
1213 .unwrap_or_default();
1214 let nlen = nodes.len();
1215 let target = if nlen >= 2 {
1216 nodes[nlen - 2].clone()
1217 } else if nlen >= 1 {
1218 nodes[nlen - 1].clone()
1219 } else {
1220 Value::Noval
1221 };
1222 let cinj = inject_child(child, store, inj);
1223 let resolved = cinj.borrow().val.clone();
1224 let out = if let Value::Func(f) = &apply {
1227 f(&cinj, &resolved, "", store)
1228 } else {
1229 resolved
1230 };
1231 set_prop(target, &Value::str(tkey), out.clone());
1232 out
1233}
1234
1235fn transform_delete(inj: &Inj, _v: &Value, _r: &str, _store: &Value) -> Value {
1236 Injection::setval(inj, Value::Noval, None);
1237 Value::Noval
1238}
1239
1240fn transform_copy(inj: &Inj, _v: &Value, _r: &str, _store: &Value) -> Value {
1241 if !check_placement(M_VAL, "COPY", T_ANY_I, inj) {
1242 return Value::Noval;
1243 }
1244 let (dparent, key) = {
1245 let b = inj.borrow();
1246 (b.dparent.clone(), b.key.clone())
1247 };
1248 let out = lookup(&dparent, &Value::str(key));
1250 Injection::setval(inj, out.clone(), None);
1251 out
1252}
1253
1254fn transform_key(inj: &Inj, _v: &Value, _r: &str, _store: &Value) -> Value {
1255 let (mode, parent, dparent, anno_key) = {
1256 let b = inj.borrow();
1257 let anno_key = b.path.get(b.path.len().saturating_sub(2)).cloned();
1258 (b.mode, b.parent.clone(), b.dparent.clone(), anno_key)
1259 };
1260 if mode != M_VAL {
1261 return Value::Noval;
1262 }
1263 let keyspec = lookup(&parent, &Value::str(S_BKEY));
1266 if !keyspec.is_noval() {
1267 del_prop(parent.clone(), &Value::str(S_BKEY));
1268 return get_prop(&dparent, &keyspec, Value::Noval);
1269 }
1270 let anno = get_prop(&parent, &Value::str(S_BANNO), Value::Noval);
1271 get_prop(
1272 &anno,
1273 &Value::str(S_KEY),
1274 anno_key.map(Value::Str).unwrap_or(Value::Noval),
1275 )
1276}
1277
1278fn transform_anno(inj: &Inj, _v: &Value, _r: &str, _store: &Value) -> Value {
1279 let parent = inj.borrow().parent.clone();
1280 del_prop(parent, &Value::str(S_BANNO));
1281 Value::Noval
1282}
1283
1284fn transform_merge(inj: &Inj, _v: &Value, _r: &str, _store: &Value) -> Value {
1285 let (mode, key, parent) = {
1286 let b = inj.borrow();
1287 (b.mode, b.key.clone(), b.parent.clone())
1288 };
1289 let mut out = Value::Noval;
1290 if mode == M_KEYPRE {
1291 out = Value::str(key);
1292 } else if mode == M_KEYPOST {
1293 out = Value::str(key.clone());
1294 let mut args = get_prop(&parent, &Value::str(key.clone()), Value::Noval);
1295 if !is_list(&args) {
1296 args = Value::list(vec![args]);
1297 }
1298 Injection::setval(inj, Value::Noval, None); let args_vec: Vec<Value> = args
1300 .as_list()
1301 .map(|l| l.borrow().clone())
1302 .unwrap_or_default();
1303 let mut mergelist: Vec<Value> = vec![parent.clone()];
1304 mergelist.extend(args_vec);
1305 mergelist.push(clone(&parent));
1306 merge(&Value::list(mergelist), Some(1));
1307 }
1308 out
1309}
1310
1311fn slice_str_vec(v: &[String], start: Option<i64>, end: Option<i64>) -> Vec<String> {
1312 match slice(path_value(v), start, end, false) {
1313 Value::List(l) => l
1314 .borrow()
1315 .iter()
1316 .map(|x| x.as_str().map(|s| s.to_string()).unwrap_or_default())
1317 .collect(),
1318 _ => Vec::new(),
1319 }
1320}
1321
1322fn transform_ref(inj: &Inj, val: &Value, _r: &str, store: &Value) -> Value {
1324 let (mode, parent, path, nodes) = {
1325 let b = inj.borrow();
1326 (b.mode, b.parent.clone(), b.path.clone(), b.nodes.clone())
1327 };
1328 if mode != M_VAL {
1329 return Value::Noval;
1330 }
1331 let refpath = lookup(&parent, &Value::Num(1.0));
1333 {
1334 let keylen = inj.borrow().keys.borrow().len() as i64;
1335 inj.borrow_mut().key_i = keylen;
1336 }
1337 let spec = {
1339 let sf = get_prop(store, &Value::str(S_DSPEC), Value::Noval);
1340 match &sf {
1341 Value::Func(f) => f(inj, &Value::Noval, "", store),
1342 _ => Value::Noval,
1343 }
1344 };
1345 let dpath = slice_str_vec(&path, Some(1), None);
1346 let dparent_for_ref = get_path_inj(&spec, &path_value(&dpath), None);
1347 let ref_def = InjectDef {
1348 dpath: Some(dpath.clone()),
1349 dparent: Some(dparent_for_ref),
1350 ..Default::default()
1351 };
1352 let refval = get_path(&spec, &refpath, Some(&ref_def));
1353
1354 let mut has_sub_ref = false;
1355 if is_node(&refval) {
1356 let mut probe = |_k: &Value, v: &Value, _p: &Value, _t: &[String]| -> Value {
1357 if matches!(v, Value::Str(s) if s == "`$REF`") {
1358 has_sub_ref = true;
1359 }
1360 v.clone()
1361 };
1362 walk(refval.clone(), Some(&mut probe), None, None);
1363 }
1364
1365 let tref = clone(&refval);
1366 let cpath = slice_str_vec(&path, Some(-3), None);
1367 let tpath = slice_str_vec(&path, Some(-1), None);
1368 let tcur = get_path_inj(store, &path_value(&cpath), None);
1369 let tval_at = get_path_inj(store, &path_value(&tpath), None);
1370
1371 let rval = if !has_sub_ref || !tval_at.is_noval() {
1372 let tinj = Injection::child(
1373 inj,
1374 0,
1375 Rc::new(RefCell::new(vec![tpath
1376 .last()
1377 .cloned()
1378 .unwrap_or_default()])),
1379 );
1380 {
1381 let mut b = tinj.borrow_mut();
1382 b.path = tpath.clone();
1383 let nlen = nodes.len();
1384 b.nodes = if nlen >= 1 {
1385 nodes[..nlen - 1].to_vec()
1386 } else {
1387 Vec::new()
1388 };
1389 b.parent = if nlen >= 2 {
1390 nodes[nlen - 2].clone()
1391 } else {
1392 Value::Noval
1393 };
1394 b.val = tref.clone();
1395 b.dpath = cpath.clone();
1396 b.dparent = tcur.clone();
1397 }
1398 let _ = inject_inj(tref.clone(), store, &tinj);
1399 let v = tinj.borrow().val.clone();
1400 v
1401 } else {
1402 Value::Noval
1403 };
1404
1405 let grandparent = Injection::setval(inj, rval, Some(2));
1406 if is_list(&grandparent) {
1407 let prior = inj.borrow().prior.clone();
1408 if let Some(p) = prior {
1409 p.borrow_mut().key_i -= 1;
1410 }
1411 }
1412 val.clone()
1413}
1414
1415fn srcpath_split(srcpath: &str) -> Vec<String> {
1416 srcpath.split('.').map(|s| s.to_string()).collect()
1417}
1418
1419fn transform_each(inj: &Inj, _val: &Value, _r: &str, store: &Value) -> Value {
1422 if !check_placement(M_VAL, "EACH", T_LIST as i64, inj) {
1423 return Value::Noval;
1424 }
1425 inj.borrow().keys.borrow_mut().truncate(1);
1427
1428 let (parent, path, nodes, base) = {
1429 let b = inj.borrow();
1430 (
1431 b.parent.clone(),
1432 b.path.clone(),
1433 b.nodes.clone(),
1434 b.base.clone(),
1435 )
1436 };
1437 let args: Vec<Value> = slice(parent.clone(), Some(1), None, false)
1438 .as_list()
1439 .map(|l| l.borrow().clone())
1440 .unwrap_or_default();
1441 let ia = injector_args(&[T_STRING as i64, T_ANY as i64], &args);
1442 if let Value::Str(e) = &ia[0] {
1443 errs_push(inj, format!("$EACH: {e}"));
1444 return Value::Noval;
1445 }
1446 let srcpath = ia.get(1).cloned().unwrap_or(Value::Noval);
1447 let child = ia.get(2).cloned().unwrap_or(Value::Noval);
1448 let srcpath_str = srcpath.as_str().unwrap_or("").to_string();
1449
1450 let srcstore = get_prop(
1451 store,
1452 &Value::str(base.clone().unwrap_or_default()),
1453 store.clone(),
1454 );
1455 let src = get_path_inj(&srcstore, &srcpath, Some(inj));
1456 let srctype = typify(&src);
1457
1458 let tkey = path
1459 .get(path.len().saturating_sub(2))
1460 .cloned()
1461 .unwrap_or_default();
1462 let nlen = nodes.len();
1463 let target = if nlen >= 2 {
1464 nodes[nlen - 2].clone()
1465 } else if nlen >= 1 {
1466 nodes[nlen - 1].clone()
1467 } else {
1468 Value::Noval
1469 };
1470
1471 let tval: Vec<Value> = if srctype & (T_LIST as i64) != 0 {
1472 items_vec(&src).iter().map(|_| clone(&child)).collect()
1473 } else if srctype & (T_MAP as i64) != 0 {
1474 items_vec(&src)
1475 .iter()
1476 .map(|(k, _)| {
1477 merge(
1478 &Value::list(vec![
1479 clone(&child),
1480 Value::map_of([(
1481 S_BANNO.to_string(),
1482 Value::map_of([(S_KEY.to_string(), Value::str(k.clone()))]),
1483 )]),
1484 ]),
1485 Some(1),
1486 )
1487 })
1488 .collect()
1489 } else {
1490 Vec::new()
1491 };
1492
1493 let mut rval = Value::empty_list();
1494 if !tval.is_empty() {
1495 let tcur_inner: Value = if src.is_nullish() {
1496 Value::Noval
1497 } else {
1498 Value::list(items_vec(&src).into_iter().map(|(_, v)| v).collect())
1499 };
1500 let ckey = path
1501 .get(path.len().saturating_sub(2))
1502 .cloned()
1503 .unwrap_or_default();
1504 let tpath = slice_str_vec(&path, Some(-1), None);
1505 let mut dpath: Vec<String> = vec![S_DTOP.to_string()];
1506 dpath.extend(srcpath_split(&srcpath_str));
1507 dpath.push(format!("$:{ckey}"));
1508
1509 let mut tcur = Value::map_of([(ckey.clone(), tcur_inner)]);
1510 if tpath.len() > 1 {
1511 let pkey = path
1512 .get(path.len().saturating_sub(3))
1513 .cloned()
1514 .unwrap_or_else(|| S_DTOP.to_string());
1515 tcur = Value::map_of([(pkey.clone(), tcur)]);
1516 dpath.push(format!("$:{pkey}"));
1517 }
1518
1519 let tval_v = Value::list(tval);
1520 let tinj = Injection::child(inj, 0, Rc::new(RefCell::new(vec![ckey.clone()])));
1521 {
1522 let mut b = tinj.borrow_mut();
1523 b.path = tpath;
1524 b.nodes = if nlen >= 1 {
1525 nodes[..nlen - 1].to_vec()
1526 } else {
1527 Vec::new()
1528 };
1529 b.parent = b.nodes.last().cloned().unwrap_or(Value::Noval);
1530 b.val = tval_v.clone();
1531 b.dpath = dpath;
1532 b.dparent = tcur;
1533 }
1534 let pclone = tinj.borrow().parent.clone();
1535 set_prop(pclone, &Value::str(ckey), tval_v.clone());
1536 let _ = inject_inj(tval_v.clone(), store, &tinj);
1537 rval = tinj.borrow().val.clone();
1538 }
1539
1540 set_prop(target, &Value::str(tkey), rval.clone());
1541 get_prop(&rval, &Value::Num(0.0), Value::Noval)
1542}
1543
1544fn transform_pack(inj: &Inj, _val: &Value, _r: &str, store: &Value) -> Value {
1547 if !check_placement(M_KEYPRE, "EACH", T_MAP as i64, inj) {
1548 return Value::Noval;
1549 }
1550 let (key, parent, path, nodes, base) = {
1551 let b = inj.borrow();
1552 (
1553 b.key.clone(),
1554 b.parent.clone(),
1555 b.path.clone(),
1556 b.nodes.clone(),
1557 b.base.clone(),
1558 )
1559 };
1560 let args = get_prop(&parent, &Value::str(key), Value::Noval);
1561 let args_vec: Vec<Value> = args
1562 .as_list()
1563 .map(|l| l.borrow().clone())
1564 .unwrap_or_default();
1565 let ia = injector_args(&[T_STRING as i64, T_ANY as i64], &args_vec);
1566 if let Value::Str(e) = &ia[0] {
1567 errs_push(inj, format!("$EACH: {e}"));
1568 return Value::Noval;
1569 }
1570 let srcpath = ia.get(1).cloned().unwrap_or(Value::Noval);
1571 let origchildspec = ia.get(2).cloned().unwrap_or(Value::Noval);
1572 let srcpath_str = srcpath.as_str().unwrap_or("").to_string();
1573
1574 let tkey = path
1575 .get(path.len().saturating_sub(2))
1576 .cloned()
1577 .unwrap_or_default();
1578 let pathsize = path.len();
1579 let nlen = nodes.len();
1580 let target = if pathsize >= 2 {
1581 nodes.get(pathsize - 2).cloned().unwrap_or(Value::Noval)
1582 } else {
1583 nodes
1584 .get(pathsize.saturating_sub(1))
1585 .cloned()
1586 .unwrap_or(Value::Noval)
1587 };
1588 let target = if target.is_noval() {
1589 nodes
1590 .get(pathsize.saturating_sub(1))
1591 .cloned()
1592 .unwrap_or(Value::Noval)
1593 } else {
1594 target
1595 };
1596
1597 let srcstore = get_prop(
1598 store,
1599 &Value::str(base.clone().unwrap_or_default()),
1600 store.clone(),
1601 );
1602 let src_raw = get_path_inj(&srcstore, &srcpath, Some(inj));
1603 let src: Value = if is_list(&src_raw) {
1604 src_raw
1605 } else if is_map(&src_raw) {
1606 Value::list(
1607 items_vec(&src_raw)
1608 .into_iter()
1609 .map(|(k, v)| {
1610 set_prop(
1611 v.clone(),
1612 &Value::str(S_BANNO),
1613 Value::map_of([(S_KEY.to_string(), Value::str(k))]),
1614 );
1615 v
1616 })
1617 .collect(),
1618 )
1619 } else {
1620 return Value::Noval;
1621 };
1622 if src.is_nullish() {
1623 return Value::Noval;
1624 }
1625
1626 let keypath = get_prop(&origchildspec, &Value::str(S_BKEY), Value::Noval);
1627 let childspec = del_prop(origchildspec.clone(), &Value::str(S_BKEY));
1628 let child = get_prop(&childspec, &Value::str(S_BVAL), childspec.clone());
1629
1630 let resolve_key = |srckey: &str, srcnode: &Value| -> Value {
1631 if keypath.is_noval() {
1632 Value::str(srckey)
1633 } else if let Value::Str(kp) = &keypath {
1634 if kp.starts_with('`') {
1635 let m = merge(
1636 &Value::list(vec![
1637 Value::empty_map(),
1638 store.clone(),
1639 Value::map_of([(S_DTOP.to_string(), srcnode.clone())]),
1640 ]),
1641 Some(1),
1642 );
1643 inject(Value::str(kp.clone()), &m, None)
1644 } else {
1645 get_path_inj(srcnode, &Value::str(kp.clone()), Some(inj))
1646 }
1647 } else {
1648 Value::str(srckey)
1649 }
1650 };
1651
1652 let tval = Value::empty_map();
1653 for (srckey, srcnode) in items_vec(&src) {
1654 let k = resolve_key(&srckey, &srcnode);
1655 let tchild = clone(&child);
1656 set_prop(tval.clone(), &k, tchild.clone());
1657 let anno = get_prop(&srcnode, &Value::str(S_BANNO), Value::Noval);
1658 if anno.is_noval() {
1659 del_prop(tchild, &Value::str(S_BANNO));
1660 } else {
1661 set_prop(tchild, &Value::str(S_BANNO), anno);
1662 }
1663 }
1664
1665 let mut rval = Value::empty_map();
1666 if !is_empty(&tval) {
1667 let tsrc = Value::empty_map();
1668 for (i, (_, n)) in items_vec(&src).into_iter().enumerate() {
1669 let kn = if keypath.is_noval() {
1670 Value::Num(i as f64)
1671 } else {
1672 resolve_key("", &n)
1673 };
1674 set_prop(tsrc.clone(), &kn, n);
1675 }
1676 let tpath = slice_str_vec(&path, Some(-1), None);
1677 let ckey = path
1678 .get(path.len().saturating_sub(2))
1679 .cloned()
1680 .unwrap_or_default();
1681 let mut dpath: Vec<String> = vec![S_DTOP.to_string()];
1682 dpath.extend(srcpath_split(&srcpath_str));
1683 dpath.push(format!("$:{ckey}"));
1684 let mut tcur = Value::map_of([(ckey.clone(), tsrc)]);
1685 if tpath.len() > 1 {
1686 let pkey = path
1687 .get(path.len().saturating_sub(3))
1688 .cloned()
1689 .unwrap_or_else(|| S_DTOP.to_string());
1690 tcur = Value::map_of([(pkey.clone(), tcur)]);
1691 dpath.push(format!("$:{pkey}"));
1692 }
1693 let tinj = Injection::child(inj, 0, Rc::new(RefCell::new(vec![ckey.clone()])));
1694 {
1695 let mut b = tinj.borrow_mut();
1696 b.path = tpath;
1697 b.nodes = if nlen >= 1 {
1698 nodes[..nlen - 1].to_vec()
1699 } else {
1700 Vec::new()
1701 };
1702 b.parent = b.nodes.last().cloned().unwrap_or(Value::Noval);
1703 b.val = tval.clone();
1704 b.dpath = dpath;
1705 b.dparent = tcur;
1706 }
1707 let _ = inject_inj(tval.clone(), store, &tinj);
1708 rval = tinj.borrow().val.clone();
1709 }
1710
1711 set_prop(target, &Value::str(tkey), rval);
1712 Value::Noval
1713}
1714
1715pub fn transform(
1716 data: &Value,
1717 spec: &Value,
1718 injdef: Option<&InjectDef>,
1719) -> Result<Value, StructError> {
1720 let origspec = spec.clone();
1721 let spec_clone = clone(&origspec);
1722
1723 let extra = injdef.and_then(|d| d.extra.clone());
1724 let collect = injdef.map(|d| d.errs.is_some()).unwrap_or(false);
1725 let errs = injdef
1726 .and_then(|d| d.errs.clone())
1727 .unwrap_or_else(Value::empty_list);
1728
1729 let mut extra_transforms = OrderedMap::new();
1731 let extra_data: Value = match &extra {
1732 None => Value::Noval,
1733 Some(e) => {
1734 let mut a = OrderedMap::new();
1735 for (k, v) in items_vec(e) {
1736 if k.starts_with(S_DS) {
1737 extra_transforms.insert(k, v);
1738 } else {
1739 a.insert(k, v);
1740 }
1741 }
1742 Value::map(a)
1743 }
1744 };
1745
1746 let data_clone = merge(
1747 &Value::list(vec![
1748 if is_empty(&extra_data) {
1749 Value::Noval
1750 } else {
1751 clone(&extra_data)
1752 },
1753 clone(data),
1754 ]),
1755 None,
1756 );
1757
1758 let origspec_for_thunk = origspec.clone();
1760 let mut store_base: OrderedMap<Value> = OrderedMap::new();
1761 store_base.insert(S_DTOP.to_string(), data_clone);
1762 store_base.insert(
1763 "$SPEC".to_string(),
1764 Value::func(move |_i: &Inj, _v: &Value, _r: &str, _s: &Value| origspec_for_thunk.clone()),
1765 );
1766 store_base.insert(
1767 "$BT".to_string(),
1768 Value::func(|_i: &Inj, _v: &Value, _r: &str, _s: &Value| Value::str(S_BT)),
1769 );
1770 store_base.insert(
1771 "$DS".to_string(),
1772 Value::func(|_i: &Inj, _v: &Value, _r: &str, _s: &Value| Value::str(S_DS)),
1773 );
1774 store_base.insert(
1775 "$WHEN".to_string(),
1776 Value::func(|_i: &Inj, _v: &Value, _r: &str, _s: &Value| Value::str(iso_now())),
1777 );
1778 store_base.insert("$DELETE".to_string(), Value::func(transform_delete));
1779 store_base.insert("$COPY".to_string(), Value::func(transform_copy));
1780 store_base.insert("$KEY".to_string(), Value::func(transform_key));
1781 store_base.insert("$ANNO".to_string(), Value::func(transform_anno));
1782 store_base.insert("$MERGE".to_string(), Value::func(transform_merge));
1783 store_base.insert("$EACH".to_string(), Value::func(transform_each));
1784 store_base.insert("$PACK".to_string(), Value::func(transform_pack));
1785 store_base.insert("$REF".to_string(), Value::func(transform_ref));
1786 store_base.insert("$FORMAT".to_string(), Value::func(transform_format));
1787 store_base.insert("$APPLY".to_string(), Value::func(transform_apply));
1788
1789 let store = merge(
1790 &Value::list(vec![
1791 Value::map(store_base),
1792 Value::map(extra_transforms),
1793 Value::map_of([(S_DERRS.to_string(), errs.clone())]),
1794 ]),
1795 Some(1),
1796 );
1797
1798 let out = inject(spec_clone, &store, injdef);
1799
1800 let errlen = errs.as_list().map(|l| l.borrow().len()).unwrap_or(0);
1801 if errlen > 0 && !collect {
1802 let msgs: Vec<String> = errs
1803 .as_list()
1804 .map(|l| l.borrow().iter().map(js_string).collect())
1805 .unwrap_or_default();
1806 return Err(StructError {
1807 message: msgs.join(" | "),
1808 });
1809 }
1810
1811 Ok(out)
1812}
1813
1814fn iso_now() -> String {
1815 use std::time::{SystemTime, UNIX_EPOCH};
1818 let dur = SystemTime::now()
1819 .duration_since(UNIX_EPOCH)
1820 .unwrap_or_default();
1821 let secs = dur.as_secs() as i64;
1822 let millis = dur.subsec_millis();
1823 let days = secs.div_euclid(86_400);
1825 let tod = secs.rem_euclid(86_400);
1826 let (h, m, s) = (tod / 3600, (tod % 3600) / 60, tod % 60);
1827 let (y, mo, d) = civil_from_days(days);
1828 format!("{y:04}-{mo:02}-{d:02}T{h:02}:{m:02}:{s:02}.{millis:03}Z")
1829}
1830
1831fn civil_from_days(z: i64) -> (i64, i64, i64) {
1832 let z = z + 719_468;
1834 let era = if z >= 0 { z } else { z - 146_096 } / 146_097;
1835 let doe = z - era * 146_097;
1836 let yoe = (doe - doe / 1460 + doe / 36_524 - doe / 146_096) / 365;
1837 let y = yoe + era * 400;
1838 let doy = doe - (365 * yoe + yoe / 4 - yoe / 100);
1839 let mp = (5 * doy + 2) / 153;
1840 let d = doy - (153 * mp + 2) / 5 + 1;
1841 let m = if mp < 10 { mp + 3 } else { mp - 9 };
1842 (if m <= 2 { y + 1 } else { y }, m, d)
1843}
1844
1845fn path_value(path: &[String]) -> Value {
1848 Value::list(path.iter().cloned().map(Value::Str).collect())
1849}
1850
1851fn invalid_type_msg(path: &[String], needtype: &str, vt: i64, v: &Value) -> String {
1852 let vs = if v.is_nullish() {
1853 "no value".to_string()
1854 } else {
1855 stringify(v, None, false)
1856 };
1857 let field_part = if path.len() > 1 {
1858 format!("field {} to be ", pathify(&path_value(path), Some(1), None))
1859 } else {
1860 String::new()
1861 };
1862 let type_part = if !v.is_nullish() {
1863 format!("{}{}", type_name(vt), S_VIZ)
1864 } else {
1865 String::new()
1866 };
1867 format!("Expected {field_part}{needtype}, but found {type_part}{vs}.")
1868}
1869
1870fn validate_string(inj: &Inj, _v: &Value, _r: &str, _store: &Value) -> Value {
1871 let (dparent, key, path) = {
1872 let b = inj.borrow();
1873 (b.dparent.clone(), b.key.clone(), b.path.clone())
1874 };
1875 let out = lookup(&dparent, &Value::str(key));
1876 let t = typify(&out);
1877 if t & (T_STRING as i64) == 0 {
1878 errs_push(inj, invalid_type_msg(&path, "string", t, &out));
1879 return Value::Noval;
1880 }
1881 if matches!(&out, Value::Str(s) if s.is_empty()) {
1882 errs_push(
1883 inj,
1884 format!(
1885 "Empty string at {}",
1886 pathify(&path_value(&path), Some(1), None)
1887 ),
1888 );
1889 return Value::Noval;
1890 }
1891 out
1892}
1893
1894fn validate_type(inj: &Inj, _v: &Value, r: &str, _store: &Value) -> Value {
1895 let tname: String = r.chars().skip(1).collect::<String>().to_lowercase();
1896 let typev: i64 = match TYPENAME.iter().position(|x| *x == tname) {
1897 Some(idx) => 1i64 << (31 - idx as i64),
1898 None => 0,
1899 };
1900 let (dparent, key, path) = {
1901 let b = inj.borrow();
1902 (b.dparent.clone(), b.key.clone(), b.path.clone())
1903 };
1904 let out = lookup(&dparent, &Value::str(key));
1905 let t = typify(&out);
1906 if t & typev == 0 {
1907 errs_push(inj, invalid_type_msg(&path, &tname, t, &out));
1908 return Value::Noval;
1909 }
1910 out
1911}
1912
1913fn validate_any(inj: &Inj, _v: &Value, _r: &str, _store: &Value) -> Value {
1914 let (dparent, key) = {
1915 let b = inj.borrow();
1916 (b.dparent.clone(), b.key.clone())
1917 };
1918 lookup(&dparent, &Value::str(key))
1919}
1920
1921fn tvals_desc(tvals: &[Value]) -> String {
1923 let joined = tvals
1924 .iter()
1925 .map(|v| stringify(v, None, false))
1926 .collect::<Vec<_>>()
1927 .join(", ");
1928 R_TRANSFORM_NAME
1929 .replace_all(&joined, |caps: &crate::re::Captures<'_>| {
1930 caps[1].to_lowercase()
1931 })
1932 .to_string()
1933}
1934
1935fn validate_child(inj: &Inj, _v: &Value, _r: &str, _store: &Value) -> Value {
1937 let (mode, key, parent, path, dparent) = {
1938 let b = inj.borrow();
1939 (
1940 b.mode,
1941 b.key.clone(),
1942 b.parent.clone(),
1943 b.path.clone(),
1944 b.dparent.clone(),
1945 )
1946 };
1947
1948 if mode == M_KEYPRE {
1949 let childtm = get_prop(&parent, &Value::str(key), Value::Noval);
1950 let pkey = path
1951 .get(path.len().saturating_sub(2))
1952 .cloned()
1953 .unwrap_or_default();
1954 let mut tval = get_prop(&dparent, &Value::str(pkey), Value::Noval);
1955 if tval.is_noval() {
1956 tval = Value::empty_map();
1957 } else if !is_map(&tval) {
1958 errs_push(
1959 inj,
1960 invalid_type_msg(
1961 &path[..path.len().saturating_sub(1)],
1962 S_object,
1963 typify(&tval),
1964 &tval,
1965 ),
1966 );
1967 return Value::Noval;
1968 }
1969 let ckeys = keysof_vec(&tval);
1970 for ck in ckeys {
1971 set_prop(parent.clone(), &Value::str(ck.clone()), clone(&childtm));
1972 inj.borrow().keys.borrow_mut().push(ck);
1973 }
1974 Injection::setval(inj, Value::Noval, None);
1975 return Value::Noval;
1976 }
1977
1978 if mode == M_VAL {
1979 if !is_list(&parent) {
1980 errs_push(inj, "Invalid $CHILD as value".to_string());
1981 return Value::Noval;
1982 }
1983 let childtm = lookup(&parent, &Value::Num(1.0));
1986 if dparent.is_noval() {
1987 slice(parent.clone(), Some(0), Some(0), true); return Value::Noval;
1989 }
1990 if !is_list(&dparent) {
1991 errs_push(
1992 inj,
1993 invalid_type_msg(
1994 &path[..path.len().saturating_sub(1)],
1995 S_list,
1996 typify(&dparent),
1997 &dparent,
1998 ),
1999 );
2000 let plen = parent.as_list().map(|l| l.borrow().len()).unwrap_or(0) as i64;
2001 inj.borrow_mut().key_i = plen;
2002 return dparent;
2003 }
2004 let dlen = dparent.as_list().map(|l| l.borrow().len()).unwrap_or(0);
2005 for n in 0..dlen {
2006 set_prop(parent.clone(), &Value::Num(n as f64), clone(&childtm));
2007 }
2008 slice(parent.clone(), Some(0), Some(dlen as i64), true);
2009
2010 {
2013 let keys = inj.borrow().keys.clone();
2014 let plen = parent.as_list().map(|l| l.borrow().len()).unwrap_or(0);
2015 let mut ks = keys.borrow_mut();
2016 for ckey_i in ks.len()..plen {
2017 ks.push(str_key(Value::Num(ckey_i as f64)));
2018 }
2019 }
2020
2021 inj.borrow_mut().key_i = -1;
2025
2026 return Value::skip();
2029 }
2030
2031 Value::Noval
2032}
2033
2034fn validate_one(inj: &Inj, _v: &Value, _r: &str, store: &Value) -> Value {
2036 let (mode, parent, key_i) = {
2037 let b = inj.borrow();
2038 (b.mode, b.parent.clone(), b.key_i)
2039 };
2040 if mode != M_VAL {
2041 return Value::Noval;
2042 }
2043 if !is_list(&parent) || key_i != 0 {
2044 let path = inj.borrow().path.clone();
2045 errs_push(
2046 inj,
2047 format!(
2048 "The $ONE validator at field {} must be the first element of an array.",
2049 pathify(&path_value(&path), Some(1), Some(1))
2050 ),
2051 );
2052 return Value::Noval;
2053 }
2054 let keylen = inj.borrow().keys.borrow().len() as i64;
2055 inj.borrow_mut().key_i = keylen;
2056 let dparent = inj.borrow().dparent.clone();
2057 Injection::setval(inj, dparent.clone(), Some(2));
2058 {
2059 let mut b = inj.borrow_mut();
2060 let n = b.path.len();
2061 b.path.truncate(n.saturating_sub(1));
2062 b.key = b.path.last().cloned().unwrap_or_default();
2063 }
2064 let path_after = inj.borrow().path.clone();
2065 let meta = inj.borrow().meta.clone();
2066 let tvals: Vec<Value> = slice(parent.clone(), Some(1), None, false)
2067 .as_list()
2068 .map(|l| l.borrow().clone())
2069 .unwrap_or_default();
2070 if tvals.is_empty() {
2071 errs_push(
2072 inj,
2073 format!(
2074 "The $ONE validator at field {} must have at least one argument.",
2075 pathify(&path_value(&path_after), Some(1), Some(1))
2076 ),
2077 );
2078 return Value::Noval;
2079 }
2080 for tval in &tvals {
2081 let terrs = Value::empty_list();
2082 let mut vstore = match merge(
2083 &Value::list(vec![Value::empty_map(), store.clone()]),
2084 Some(1),
2085 ) {
2086 v @ Value::Map(_) => v,
2087 _ => Value::empty_map(),
2088 };
2089 set_prop(vstore.clone(), &Value::str(S_DTOP), dparent.clone());
2090 let _ = &mut vstore;
2091 let vd = InjectDef {
2092 extra: Some(vstore.clone()),
2093 errs: Some(terrs.clone()),
2094 meta: Some(meta.clone()),
2095 ..Default::default()
2096 };
2097 let vcur = validate(&dparent, tval, Some(&vd)).unwrap_or(Value::Noval);
2098 Injection::setval(inj, vcur, Some(-2)); let terrlen = terrs.as_list().map(|l| l.borrow().len()).unwrap_or(0);
2100 if terrlen == 0 {
2101 return Value::Noval;
2102 }
2103 }
2104 let valdesc = tvals_desc(&tvals);
2105 errs_push(
2106 inj,
2107 invalid_type_msg(
2108 &path_after,
2109 &format!(
2110 "{}{}",
2111 if tvals.len() > 1 { "one of " } else { "" },
2112 valdesc
2113 ),
2114 typify(&dparent),
2115 &dparent,
2116 ),
2117 );
2118 Value::Noval
2119}
2120
2121fn validate_exact(inj: &Inj, _v: &Value, _r: &str, _store: &Value) -> Value {
2123 let (mode, parent, key, key_i) = {
2124 let b = inj.borrow();
2125 (b.mode, b.parent.clone(), b.key.clone(), b.key_i)
2126 };
2127 if mode != M_VAL {
2128 del_prop(parent, &Value::str(key));
2129 return Value::Noval;
2130 }
2131 if !is_list(&parent) || key_i != 0 {
2132 let path = inj.borrow().path.clone();
2133 errs_push(
2134 inj,
2135 format!(
2136 "The $EXACT validator at field {} must be the first element of an array.",
2137 pathify(&path_value(&path), Some(1), Some(1))
2138 ),
2139 );
2140 return Value::Noval;
2141 }
2142 let keylen = inj.borrow().keys.borrow().len() as i64;
2143 inj.borrow_mut().key_i = keylen;
2144 let dparent = inj.borrow().dparent.clone();
2145 Injection::setval(inj, dparent.clone(), Some(2));
2146 {
2147 let mut b = inj.borrow_mut();
2148 let n = b.path.len();
2149 b.path.truncate(n.saturating_sub(1));
2150 b.key = b.path.last().cloned().unwrap_or_default();
2151 }
2152 let path_after = inj.borrow().path.clone();
2153 let tvals: Vec<Value> = slice(parent.clone(), Some(1), None, false)
2154 .as_list()
2155 .map(|l| l.borrow().clone())
2156 .unwrap_or_default();
2157 if tvals.is_empty() {
2158 errs_push(
2159 inj,
2160 format!(
2161 "The $EXACT validator at field {} must have at least one argument.",
2162 pathify(&path_value(&path_after), Some(1), Some(1))
2163 ),
2164 );
2165 return Value::Noval;
2166 }
2167 let mut currentstr: Option<String> = None;
2168 for tval in &tvals {
2169 let mut exactmatch = tval == &dparent;
2170 if !exactmatch && is_node(tval) {
2171 let cs = currentstr
2172 .get_or_insert_with(|| stringify(&dparent, None, false))
2173 .clone();
2174 exactmatch = stringify(tval, None, false) == cs;
2175 }
2176 if exactmatch {
2177 return Value::Noval;
2178 }
2179 }
2180 let valdesc = tvals_desc(&tvals);
2181 let need = format!(
2182 "{}exactly equal to {}{}",
2183 if path_after.len() > 1 { "" } else { "value " },
2184 if tvals.len() == 1 { "" } else { "one of " },
2185 valdesc
2186 );
2187 errs_push(
2188 inj,
2189 invalid_type_msg(&path_after, &need, typify(&dparent), &dparent),
2190 );
2191 Value::Noval
2192}
2193
2194fn validation_modify(pval: &Value, key: &Value, parent: &Value, inj: &Inj, _store: &Value) {
2197 if pval.is_skip() {
2198 return;
2199 }
2200 let (meta, dparent, path) = {
2201 let b = inj.borrow();
2202 (b.meta.clone(), b.dparent.clone(), b.path.clone())
2203 };
2204 let exact = matches!(
2205 get_prop(&meta, &Value::str(S_BEXACT), Value::Bool(false)),
2206 Value::Bool(true)
2207 );
2208 let cval = get_prop(&dparent, key, Value::Noval);
2209 if !exact && cval.is_noval() {
2210 return;
2211 }
2212 let ptype = typify(pval);
2213 if ptype & (T_STRING as i64) != 0 {
2214 if let Value::Str(s) = pval {
2215 if s.contains(S_DS) {
2216 return; }
2218 }
2219 }
2220 let ctype = typify(&cval);
2221 if ptype != ctype && !pval.is_noval() {
2222 errs_push(
2223 inj,
2224 invalid_type_msg(&path, &type_name(ptype), ctype, &cval),
2225 );
2226 return;
2227 }
2228
2229 if is_map(&cval) {
2230 if !is_map(pval) {
2231 errs_push(
2232 inj,
2233 invalid_type_msg(&path, &type_name(ptype), ctype, &cval),
2234 );
2235 return;
2236 }
2237 let ckeys = keysof_vec(&cval);
2238 let pkeys = keysof_vec(pval);
2239 let open = matches!(
2240 get_prop(pval, &Value::str(S_BOPEN), Value::Noval),
2241 Value::Bool(true)
2242 );
2243 if !pkeys.is_empty() && !open {
2244 let badkeys: Vec<String> = ckeys
2248 .iter()
2249 .filter(|ck| lookup(pval, &Value::str((*ck).clone())).is_noval())
2250 .cloned()
2251 .collect();
2252 if !badkeys.is_empty() {
2253 errs_push(
2254 inj,
2255 format!(
2256 "Unexpected keys at field {}{}{}",
2257 pathify(&path_value(&path), Some(1), None),
2258 S_VIZ,
2259 badkeys.join(", ")
2260 ),
2261 );
2262 }
2263 } else {
2264 merge(&Value::list(vec![pval.clone(), cval.clone()]), None);
2265 if is_node(pval) {
2266 del_prop(pval.clone(), &Value::str(S_BOPEN));
2267 }
2268 }
2269 } else if is_list(&cval) {
2270 if !is_list(pval) {
2271 errs_push(
2272 inj,
2273 invalid_type_msg(&path, &type_name(ptype), ctype, &cval),
2274 );
2275 }
2276 } else if exact {
2277 if &cval != pval {
2278 let pathmsg = if path.len() > 1 {
2279 format!(
2280 "at field {}{}",
2281 pathify(&path_value(&path), Some(1), None),
2282 S_VIZ
2283 )
2284 } else {
2285 String::new()
2286 };
2287 errs_push(
2288 inj,
2289 format!(
2290 "Value {}{} should equal {}{}",
2291 pathmsg,
2292 js_string(&cval),
2293 js_string(pval),
2294 S_DT
2295 ),
2296 );
2297 }
2298 } else {
2299 set_prop(parent.clone(), key, cval.clone());
2300 }
2301}
2302
2303fn validatehandler(inj: &Inj, val: &Value, r: &str, store: &Value) -> Value {
2305 if let Some(caps) = R_META_PATH.captures(r) {
2306 if &caps[2] == "=" {
2307 Injection::setval(
2308 inj,
2309 Value::list(vec![Value::str(S_BEXACT), val.clone()]),
2310 None,
2311 );
2312 } else {
2313 Injection::setval(inj, val.clone(), None);
2314 }
2315 inj.borrow_mut().key_i = -1;
2316 return Value::skip();
2317 }
2318 inject_handler(inj, val, r, store)
2319}
2320
2321pub fn validate(
2322 data: &Value,
2323 spec: &Value,
2324 injdef: Option<&InjectDef>,
2325) -> Result<Value, StructError> {
2326 let extra = injdef.and_then(|d| d.extra.clone());
2327 let collect = injdef.map(|d| d.errs.is_some()).unwrap_or(false);
2328 let errs = injdef
2329 .and_then(|d| d.errs.clone())
2330 .unwrap_or_else(Value::empty_list);
2331
2332 let mut vmap: OrderedMap<Value> = OrderedMap::new();
2334 for k in [
2335 "$DELETE", "$COPY", "$KEY", "$META", "$MERGE", "$EACH", "$PACK",
2336 ] {
2337 vmap.insert(k.to_string(), Value::Null);
2338 }
2339 vmap.insert("$STRING".to_string(), Value::func(validate_string));
2340 for k in [
2341 "$NUMBER",
2342 "$INTEGER",
2343 "$DECIMAL",
2344 "$BOOLEAN",
2345 "$NULL",
2346 "$NIL",
2347 "$MAP",
2348 "$LIST",
2349 "$FUNCTION",
2350 "$INSTANCE",
2351 ] {
2352 vmap.insert(k.to_string(), Value::func(validate_type));
2353 }
2354 vmap.insert("$ANY".to_string(), Value::func(validate_any));
2355 vmap.insert("$CHILD".to_string(), Value::func(validate_child));
2356 vmap.insert("$ONE".to_string(), Value::func(validate_one));
2357 vmap.insert("$EXACT".to_string(), Value::func(validate_exact));
2358
2359 let extra_or_empty = match &extra {
2360 Some(e) => e.clone(),
2361 None => Value::empty_map(),
2362 };
2363 let store = merge(
2364 &Value::list(vec![
2365 Value::map(vmap),
2366 extra_or_empty,
2367 Value::map_of([(S_DERRS.to_string(), errs.clone())]),
2368 ]),
2369 Some(1),
2370 );
2371
2372 let meta = match injdef.and_then(|d| d.meta.clone()) {
2373 Some(m) => m,
2374 None => Value::empty_map(),
2375 };
2376 let exact_cur = get_prop(&meta, &Value::str(S_BEXACT), Value::Bool(false));
2377 set_prop(meta.clone(), &Value::str(S_BEXACT), exact_cur);
2378
2379 let td = InjectDef {
2380 meta: Some(meta),
2381 extra: Some(store),
2382 modify: Some(Rc::new(validation_modify) as Modify),
2383 handler: Some(Rc::new(validatehandler) as NativeFn),
2384 errs: Some(errs.clone()),
2385 ..Default::default()
2386 };
2387
2388 let out = transform(data, spec, Some(&td)).unwrap_or(Value::Noval);
2389
2390 let errlen = errs.as_list().map(|l| l.borrow().len()).unwrap_or(0);
2391 if errlen > 0 && !collect {
2392 let msgs: Vec<String> = errs
2393 .as_list()
2394 .map(|l| l.borrow().iter().map(js_string).collect())
2395 .unwrap_or_default();
2396 return Err(StructError {
2397 message: msgs.join(" | "),
2398 });
2399 }
2400
2401 Ok(out)
2402}
2403
2404fn js_lt(a: &Value, b: &Value) -> bool {
2407 match (a, b) {
2408 (Value::Str(x), Value::Str(y)) => x < y,
2409 _ => {
2410 let (x, y) = (js_to_number(a), js_to_number(b));
2411 x < y }
2413 }
2414}
2415fn js_gt(a: &Value, b: &Value) -> bool {
2416 match (a, b) {
2417 (Value::Str(x), Value::Str(y)) => x > y,
2418 _ => {
2419 let (x, y) = (js_to_number(a), js_to_number(b));
2420 x > y
2421 }
2422 }
2423}
2424
2425fn select_subvalidate(point: &Value, term: &Value, store: &Value, meta: &Value) -> bool {
2426 let vstore = match merge(
2427 &Value::list(vec![Value::empty_map(), store.clone()]),
2428 Some(1),
2429 ) {
2430 v @ Value::Map(_) => v,
2431 _ => Value::empty_map(),
2432 };
2433 set_prop(vstore.clone(), &Value::str(S_DTOP), point.clone());
2434 let terrs = Value::empty_list();
2435 let vd = InjectDef {
2436 extra: Some(vstore),
2437 errs: Some(terrs.clone()),
2438 meta: Some(meta.clone()),
2439 ..Default::default()
2440 };
2441 let _ = validate(point, term, Some(&vd));
2442 terrs
2443 .as_list()
2444 .map(|l| l.borrow().is_empty())
2445 .unwrap_or(true)
2446}
2447
2448fn select_and(inj: &Inj, _v: &Value, _r: &str, store: &Value) -> Value {
2449 if inj.borrow().mode != M_KEYPRE {
2450 return Value::Noval;
2451 }
2452 let (key, parent, path, nodes, meta) = {
2453 let b = inj.borrow();
2454 (
2455 b.key.clone(),
2456 b.parent.clone(),
2457 b.path.clone(),
2458 b.nodes.clone(),
2459 b.meta.clone(),
2460 )
2461 };
2462 let terms: Vec<Value> = lookup(&parent, &Value::str(key))
2463 .as_list()
2464 .map(|l| l.borrow().clone())
2465 .unwrap_or_default();
2466 let ppath = slice_str_vec(&path, Some(-1), None);
2467 let point = get_path_inj(store, &path_value(&ppath), None);
2468 for term in &terms {
2469 if !select_subvalidate(&point, term, store, &meta) {
2470 errs_push(
2471 inj,
2472 format!(
2473 "AND:{}{}{} fail:{}",
2474 pathify(&path_value(&ppath), None, None),
2475 S_VIZ,
2476 stringify(&point, None, false),
2477 stringify(&Value::list(terms.clone()), None, false)
2478 ),
2479 );
2480 }
2481 }
2482 let gkey = path
2483 .get(path.len().saturating_sub(2))
2484 .cloned()
2485 .unwrap_or_default();
2486 let nlen = nodes.len();
2487 if nlen >= 2 {
2488 set_prop(nodes[nlen - 2].clone(), &Value::str(gkey), point);
2489 }
2490 Value::Noval
2491}
2492
2493fn select_or(inj: &Inj, _v: &Value, _r: &str, store: &Value) -> Value {
2494 if inj.borrow().mode != M_KEYPRE {
2495 return Value::Noval;
2496 }
2497 let (key, parent, path, nodes, meta) = {
2498 let b = inj.borrow();
2499 (
2500 b.key.clone(),
2501 b.parent.clone(),
2502 b.path.clone(),
2503 b.nodes.clone(),
2504 b.meta.clone(),
2505 )
2506 };
2507 let terms: Vec<Value> = lookup(&parent, &Value::str(key))
2508 .as_list()
2509 .map(|l| l.borrow().clone())
2510 .unwrap_or_default();
2511 let ppath = slice_str_vec(&path, Some(-1), None);
2512 let point = get_path_inj(store, &path_value(&ppath), None);
2513 for term in &terms {
2514 if select_subvalidate(&point, term, store, &meta) {
2515 let gkey = path
2516 .get(path.len().saturating_sub(2))
2517 .cloned()
2518 .unwrap_or_default();
2519 let nlen = nodes.len();
2520 if nlen >= 2 {
2521 set_prop(nodes[nlen - 2].clone(), &Value::str(gkey), point);
2522 }
2523 return Value::Noval;
2524 }
2525 }
2526 errs_push(
2527 inj,
2528 format!(
2529 "OR:{}{}{} fail:{}",
2530 pathify(&path_value(&ppath), None, None),
2531 S_VIZ,
2532 stringify(&point, None, false),
2533 stringify(&Value::list(terms.clone()), None, false)
2534 ),
2535 );
2536 Value::Noval
2537}
2538
2539fn select_not(inj: &Inj, _v: &Value, _r: &str, store: &Value) -> Value {
2540 if inj.borrow().mode != M_KEYPRE {
2541 return Value::Noval;
2542 }
2543 let (key, parent, path, nodes, meta) = {
2544 let b = inj.borrow();
2545 (
2546 b.key.clone(),
2547 b.parent.clone(),
2548 b.path.clone(),
2549 b.nodes.clone(),
2550 b.meta.clone(),
2551 )
2552 };
2553 let term = lookup(&parent, &Value::str(key));
2554 let ppath = slice_str_vec(&path, Some(-1), None);
2555 let point = get_path_inj(store, &path_value(&ppath), None);
2556 if select_subvalidate(&point, &term, store, &meta) {
2557 errs_push(
2558 inj,
2559 format!(
2560 "NOT:{}{}{} fail:{}",
2561 pathify(&path_value(&ppath), None, None),
2562 S_VIZ,
2563 stringify(&point, None, false),
2564 stringify(&term, None, false)
2565 ),
2566 );
2567 }
2568 let gkey = path
2569 .get(path.len().saturating_sub(2))
2570 .cloned()
2571 .unwrap_or_default();
2572 let nlen = nodes.len();
2573 if nlen >= 2 {
2574 set_prop(nodes[nlen - 2].clone(), &Value::str(gkey), point);
2575 }
2576 Value::Noval
2577}
2578
2579fn select_cmp(inj: &Inj, _v: &Value, r: &str, store: &Value) -> Value {
2580 if inj.borrow().mode != M_KEYPRE {
2581 return Value::Noval;
2582 }
2583 let (key, parent, path, nodes) = {
2584 let b = inj.borrow();
2585 (
2586 b.key.clone(),
2587 b.parent.clone(),
2588 b.path.clone(),
2589 b.nodes.clone(),
2590 )
2591 };
2592 let term = lookup(&parent, &Value::str(key));
2593 let gkey = path
2594 .get(path.len().saturating_sub(2))
2595 .cloned()
2596 .unwrap_or_default();
2597 let ppath = slice_str_vec(&path, Some(-1), None);
2598 let point = get_path_inj(store, &path_value(&ppath), None);
2599
2600 let pass = match r {
2601 "$GT" => js_gt(&point, &term),
2602 "$LT" => js_lt(&point, &term),
2603 "$GTE" => js_gt(&point, &term) || point == term,
2604 "$LTE" => js_lt(&point, &term) || point == term,
2605 "$LIKE" => {
2606 let pat = term.as_str().unwrap_or("").to_string();
2607 crate::re::Regex::new(&pat)
2608 .map(|re| re.is_match(&stringify(&point, None, false)))
2609 .unwrap_or(false)
2610 }
2611 _ => false,
2612 };
2613
2614 if pass {
2615 let nlen = nodes.len();
2616 if nlen >= 2 {
2617 set_prop(nodes[nlen - 2].clone(), &Value::str(gkey), point);
2618 }
2619 } else {
2620 errs_push(
2621 inj,
2622 format!(
2623 "CMP: {}{}{} fail:{} {}",
2624 pathify(&path_value(&ppath), None, None),
2625 S_VIZ,
2626 stringify(&point, None, false),
2627 r,
2628 stringify(&term, None, false)
2629 ),
2630 );
2631 }
2632 Value::Noval
2633}
2634
2635pub fn select(children: &Value, query: &Value) -> Value {
2636 if !is_node(children) {
2637 return Value::empty_list();
2638 }
2639
2640 let child_list: Vec<Value> = match children {
2641 Value::Map(_) => items_vec(children)
2642 .into_iter()
2643 .map(|(k, v)| {
2644 set_prop(v.clone(), &Value::str(S_DKEY), Value::str(k));
2645 v
2646 })
2647 .collect(),
2648 Value::List(_) => items_vec(children)
2649 .into_iter()
2650 .map(|(k, v)| {
2651 set_prop(
2652 v.clone(),
2653 &Value::str(S_DKEY),
2654 Value::Num(k.parse::<f64>().unwrap_or(f64::NAN)),
2655 );
2656 v
2657 })
2658 .collect(),
2659 _ => return Value::empty_list(),
2660 };
2661
2662 let extra = Value::map_of([
2663 ("$AND".to_string(), Value::func(select_and)),
2664 ("$OR".to_string(), Value::func(select_or)),
2665 ("$NOT".to_string(), Value::func(select_not)),
2666 ("$GT".to_string(), Value::func(select_cmp)),
2667 ("$LT".to_string(), Value::func(select_cmp)),
2668 ("$GTE".to_string(), Value::func(select_cmp)),
2669 ("$LTE".to_string(), Value::func(select_cmp)),
2670 ("$LIKE".to_string(), Value::func(select_cmp)),
2671 ]);
2672 let meta = Value::map_of([(S_BEXACT.to_string(), Value::Bool(true))]);
2673
2674 let q = clone(query);
2675 let mut open = |_k: &Value, v: &Value, _p: &Value, _t: &[String]| -> Value {
2676 if is_map(v) {
2677 let cur = get_prop(v, &Value::str(S_BOPEN), Value::Bool(true));
2678 set_prop(v.clone(), &Value::str(S_BOPEN), cur);
2679 }
2680 v.clone()
2681 };
2682 walk(q.clone(), Some(&mut open), None, None);
2683
2684 let mut results: Vec<Value> = Vec::new();
2685 for child in &child_list {
2686 let errs = Value::empty_list();
2687 let vd = InjectDef {
2688 errs: Some(errs.clone()),
2689 meta: Some(meta.clone()),
2690 extra: Some(extra.clone()),
2691 ..Default::default()
2692 };
2693 let _ = validate(child, &clone(&q), Some(&vd));
2694 if errs
2695 .as_list()
2696 .map(|l| l.borrow().is_empty())
2697 .unwrap_or(true)
2698 {
2699 results.push(child.clone());
2700 }
2701 }
2702 Value::list(results)
2703}
2704
2705#[allow(dead_code)]
2707fn _keepalive() {
2708 let _ = Injection::has_handler(None);
2709 let _ = inject_child as fn(Value, &Value, &Inj) -> Inj;
2710}