From 698f8c2f01ea549d77d7dc3338a12e04c11057b9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 14:02:58 +0200 Subject: Adding upstream version 1.64.0+dfsg1. Signed-off-by: Daniel Baumann --- vendor/handlebars/src/json/mod.rs | 2 + vendor/handlebars/src/json/path.rs | 138 ++++++++++++++++++++++++ vendor/handlebars/src/json/value.rs | 202 ++++++++++++++++++++++++++++++++++++ 3 files changed, 342 insertions(+) create mode 100644 vendor/handlebars/src/json/mod.rs create mode 100644 vendor/handlebars/src/json/path.rs create mode 100644 vendor/handlebars/src/json/value.rs (limited to 'vendor/handlebars/src/json') diff --git a/vendor/handlebars/src/json/mod.rs b/vendor/handlebars/src/json/mod.rs new file mode 100644 index 000000000..85f783d0c --- /dev/null +++ b/vendor/handlebars/src/json/mod.rs @@ -0,0 +1,2 @@ +pub(crate) mod path; +pub(crate) mod value; diff --git a/vendor/handlebars/src/json/path.rs b/vendor/handlebars/src/json/path.rs new file mode 100644 index 000000000..8270371b2 --- /dev/null +++ b/vendor/handlebars/src/json/path.rs @@ -0,0 +1,138 @@ +use std::iter::Peekable; + +use pest::iterators::Pair; +use pest::Parser; + +use crate::error::RenderError; +use crate::grammar::{HandlebarsParser, Rule}; + +#[derive(PartialEq, Clone, Debug)] +pub enum PathSeg { + Named(String), + Ruled(Rule), +} + +/// Represents the Json path in templates. +/// +/// It can be either a local variable like `@first`, `../@index`, +/// or a normal relative path like `a/b/c`. +#[derive(PartialEq, Clone, Debug)] +pub enum Path { + Relative((Vec, String)), + Local((usize, String, String)), +} + +impl Path { + pub(crate) fn new(raw: &str, segs: Vec) -> Path { + if let Some((level, name)) = get_local_path_and_level(&segs) { + Path::Local((level, name, raw.to_owned())) + } else { + Path::Relative((segs, raw.to_owned())) + } + } + + pub fn parse(raw: &str) -> Result { + HandlebarsParser::parse(Rule::path, raw) + .map(|p| { + let parsed = p.flatten(); + let segs = parse_json_path_from_iter(&mut parsed.peekable(), raw.len()); + Ok(Path::new(raw, segs)) + }) + .map_err(|_| RenderError::new("Invalid JSON path"))? + } + + pub(crate) fn raw(&self) -> &str { + match self { + Path::Relative((_, ref raw)) => raw, + Path::Local((_, _, ref raw)) => raw, + } + } + + pub(crate) fn current() -> Path { + Path::Relative((Vec::with_capacity(0), "".to_owned())) + } + + // for test only + pub(crate) fn with_named_paths(name_segs: &[&str]) -> Path { + let segs = name_segs + .iter() + .map(|n| PathSeg::Named((*n).to_string())) + .collect(); + Path::Relative((segs, name_segs.join("/"))) + } + + // for test only + pub(crate) fn segs(&self) -> Option<&[PathSeg]> { + match self { + Path::Relative((segs, _)) => Some(segs), + _ => None, + } + } +} + +fn get_local_path_and_level(paths: &[PathSeg]) -> Option<(usize, String)> { + paths.get(0).and_then(|seg| { + if seg == &PathSeg::Ruled(Rule::path_local) { + let mut level = 0; + while paths.get(level + 1)? == &PathSeg::Ruled(Rule::path_up) { + level += 1; + } + if let Some(PathSeg::Named(name)) = paths.get(level + 1) { + Some((level, name.clone())) + } else { + None + } + } else { + None + } + }) +} + +pub(crate) fn parse_json_path_from_iter<'a, I>(it: &mut Peekable, limit: usize) -> Vec +where + I: Iterator>, +{ + let mut path_stack = Vec::with_capacity(5); + while let Some(n) = it.peek() { + let span = n.as_span(); + if span.end() > limit { + break; + } + + match n.as_rule() { + Rule::path_root => { + path_stack.push(PathSeg::Ruled(Rule::path_root)); + } + Rule::path_local => { + path_stack.push(PathSeg::Ruled(Rule::path_local)); + } + Rule::path_up => { + path_stack.push(PathSeg::Ruled(Rule::path_up)); + } + Rule::path_id | Rule::path_raw_id => { + let name = n.as_str(); + if name != "this" { + path_stack.push(PathSeg::Named(name.to_string())); + } + } + _ => {} + } + + it.next(); + } + + path_stack +} + +pub(crate) fn merge_json_path(path_stack: &mut Vec, relative_path: &[PathSeg]) { + for seg in relative_path { + match seg { + PathSeg::Named(ref s) => { + path_stack.push(s.to_owned()); + } + PathSeg::Ruled(Rule::path_root) => {} + PathSeg::Ruled(Rule::path_up) => {} + _ => {} + } + } +} diff --git a/vendor/handlebars/src/json/value.rs b/vendor/handlebars/src/json/value.rs new file mode 100644 index 000000000..863eab0b8 --- /dev/null +++ b/vendor/handlebars/src/json/value.rs @@ -0,0 +1,202 @@ +use serde::Serialize; +use serde_json::value::{to_value, Value as Json}; + +pub(crate) static DEFAULT_VALUE: Json = Json::Null; + +/// A JSON wrapper designed for handlebars internal use case +/// +/// * Constant: the JSON value hardcoded into template +/// * Context: the JSON value referenced in your provided data context +/// * Derived: the owned JSON value computed during rendering process +/// +#[derive(Debug)] +pub enum ScopedJson<'reg: 'rc, 'rc> { + Constant(&'reg Json), + Derived(Json), + // represents a json reference to context value, its full path + Context(&'rc Json, Vec), + Missing, +} + +impl<'reg: 'rc, 'rc> ScopedJson<'reg, 'rc> { + /// get the JSON reference + pub fn as_json(&self) -> &Json { + match self { + ScopedJson::Constant(j) => j, + ScopedJson::Derived(ref j) => j, + ScopedJson::Context(j, _) => j, + _ => &DEFAULT_VALUE, + } + } + + pub fn render(&self) -> String { + self.as_json().render() + } + + pub fn is_missing(&self) -> bool { + matches!(self, ScopedJson::Missing) + } + + pub fn into_derived(self) -> ScopedJson<'reg, 'rc> { + let v = self.as_json(); + ScopedJson::Derived(v.clone()) + } + + pub fn context_path(&self) -> Option<&Vec> { + match self { + ScopedJson::Context(_, ref p) => Some(p), + _ => None, + } + } +} + +impl<'reg: 'rc, 'rc> From for ScopedJson<'reg, 'rc> { + fn from(v: Json) -> ScopedJson<'reg, 'rc> { + ScopedJson::Derived(v) + } +} + +/// Json wrapper that holds the Json value and reference path information +/// +#[derive(Debug)] +pub struct PathAndJson<'reg, 'rc> { + relative_path: Option, + value: ScopedJson<'reg, 'rc>, +} + +impl<'reg: 'rc, 'rc> PathAndJson<'reg, 'rc> { + pub fn new( + relative_path: Option, + value: ScopedJson<'reg, 'rc>, + ) -> PathAndJson<'reg, 'rc> { + PathAndJson { + relative_path, + value, + } + } + + /// Returns relative path when the value is referenced + /// If the value is from a literal, the path is `None` + pub fn relative_path(&self) -> Option<&String> { + self.relative_path.as_ref() + } + + /// Returns full path to this value if any + pub fn context_path(&self) -> Option<&Vec> { + self.value.context_path() + } + + /// Returns the value + pub fn value(&self) -> &Json { + self.value.as_json() + } + + /// Test if value is missing + pub fn is_value_missing(&self) -> bool { + self.value.is_missing() + } + + pub fn render(&self) -> String { + self.value.render() + } +} + +/// Render Json data with default format +pub trait JsonRender { + fn render(&self) -> String; +} + +pub trait JsonTruthy { + fn is_truthy(&self, include_zero: bool) -> bool; +} + +impl JsonRender for Json { + fn render(&self) -> String { + match *self { + Json::String(ref s) => s.to_string(), + Json::Bool(i) => i.to_string(), + Json::Number(ref n) => n.to_string(), + Json::Null => "".to_owned(), + Json::Array(ref a) => { + let mut buf = String::new(); + buf.push('['); + for i in a.iter() { + buf.push_str(i.render().as_ref()); + buf.push_str(", "); + } + buf.push(']'); + buf + } + Json::Object(_) => "[object]".to_owned(), + } + } +} + +/// Convert any serializable data into Serde Json type +pub fn to_json(src: T) -> Json +where + T: Serialize, +{ + to_value(src).unwrap_or_default() +} + +pub fn as_string(src: &Json) -> Option<&str> { + src.as_str() +} + +impl JsonTruthy for Json { + fn is_truthy(&self, include_zero: bool) -> bool { + match *self { + Json::Bool(ref i) => *i, + Json::Number(ref n) => { + if include_zero { + n.as_f64().map(|f| !f.is_nan()).unwrap_or(false) + } else { + // there is no inifity in json/serde_json + n.as_f64().map(|f| f.is_normal()).unwrap_or(false) + } + } + Json::Null => false, + Json::String(ref i) => !i.is_empty(), + Json::Array(ref i) => !i.is_empty(), + Json::Object(ref i) => !i.is_empty(), + } + } +} + +#[test] +fn test_json_render() { + let raw = "

Hello world

\n

"; + let thing = Json::String(raw.to_string()); + + assert_eq!(raw, thing.render()); +} + +#[test] +fn test_json_number_truthy() { + use std::f64; + assert!(json!(16i16).is_truthy(false)); + assert!(json!(16i16).is_truthy(true)); + + assert!(json!(0i16).is_truthy(true)); + assert!(!json!(0i16).is_truthy(false)); + + assert!(json!(1.0f64).is_truthy(false)); + assert!(json!(1.0f64).is_truthy(true)); + + assert!(json!(Some(16i16)).is_truthy(false)); + assert!(json!(Some(16i16)).is_truthy(true)); + + assert!(!json!(None as Option).is_truthy(false)); + assert!(!json!(None as Option).is_truthy(true)); + + assert!(!json!(f64::NAN).is_truthy(false)); + assert!(!json!(f64::NAN).is_truthy(true)); + + // there is no infinity in json/serde_json + // assert!(json!(f64::INFINITY).is_truthy(false)); + // assert!(json!(f64::INFINITY).is_truthy(true)); + + // assert!(json!(f64::NEG_INFINITY).is_truthy(false)); + // assert!(json!(f64::NEG_INFINITY).is_truthy(true)); +} -- cgit v1.2.3