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/helpers/mod.rs | 291 +++++++++++++++++++++++++++++++++++ 1 file changed, 291 insertions(+) create mode 100644 vendor/handlebars/src/helpers/mod.rs (limited to 'vendor/handlebars/src/helpers/mod.rs') diff --git a/vendor/handlebars/src/helpers/mod.rs b/vendor/handlebars/src/helpers/mod.rs new file mode 100644 index 000000000..bfd50c1f4 --- /dev/null +++ b/vendor/handlebars/src/helpers/mod.rs @@ -0,0 +1,291 @@ +use crate::context::Context; +use crate::error::RenderError; +use crate::json::value::ScopedJson; +use crate::output::Output; +use crate::registry::Registry; +use crate::render::{do_escape, Helper, RenderContext}; + +pub use self::helper_each::EACH_HELPER; +pub use self::helper_if::{IF_HELPER, UNLESS_HELPER}; +pub use self::helper_log::LOG_HELPER; +pub use self::helper_lookup::LOOKUP_HELPER; +pub use self::helper_raw::RAW_HELPER; +pub use self::helper_with::WITH_HELPER; + +/// A type alias for `Result<(), RenderError>` +pub type HelperResult = Result<(), RenderError>; + +/// Helper Definition +/// +/// Implement `HelperDef` to create custom helpers. You can retrieve useful information from these arguments. +/// +/// * `&Helper`: current helper template information, contains name, params, hashes and nested template +/// * `&Registry`: the global registry, you can find templates by name from registry +/// * `&Context`: the whole data to render, in most case you can use data from `Helper` +/// * `&mut RenderContext`: you can access data or modify variables (starts with @)/partials in render context, for example, @index of #each. See its document for detail. +/// * `&mut dyn Output`: where you write output to +/// +/// By default, you can use a bare function as a helper definition because we have supported unboxed_closure. If you have stateful or configurable helper, you can create a struct to implement `HelperDef`. +/// +/// ## Define an inline helper +/// +/// ``` +/// use handlebars::*; +/// +/// fn upper(h: &Helper<'_, '_>, _: &Handlebars<'_>, _: &Context, rc: &mut RenderContext<'_, '_>, out: &mut Output) +/// -> HelperResult { +/// // get parameter from helper or throw an error +/// let param = h.param(0).and_then(|v| v.value().as_str()).unwrap_or(""); +/// out.write(param.to_uppercase().as_ref())?; +/// Ok(()) +/// } +/// ``` +/// +/// ## Define block helper +/// +/// Block helper is like `#if` or `#each` which has a inner template and an optional *inverse* template (the template in else branch). You can access the inner template by `helper.template()` and `helper.inverse()`. In most cases you will just call `render` on it. +/// +/// ``` +/// use handlebars::*; +/// +/// fn dummy_block<'reg, 'rc>( +/// h: &Helper<'reg, 'rc>, +/// r: &'reg Handlebars<'reg>, +/// ctx: &'rc Context, +/// rc: &mut RenderContext<'reg, 'rc>, +/// out: &mut dyn Output, +/// ) -> HelperResult { +/// h.template() +/// .map(|t| t.render(r, ctx, rc, out)) +/// .unwrap_or(Ok(())) +/// } +/// ``` +/// +/// ## Define helper function using macro +/// +/// In most cases you just need some simple function to call from templates. We have a `handlebars_helper!` macro to simplify the job. +/// +/// ``` +/// use handlebars::*; +/// +/// handlebars_helper!(plus: |x: i64, y: i64| x + y); +/// +/// let mut hbs = Handlebars::new(); +/// hbs.register_helper("plus", Box::new(plus)); +/// ``` +/// +pub trait HelperDef { + /// A simplified api to define helper + /// + /// To implement your own `call_inner`, you will return a new `ScopedJson` + /// which has a JSON value computed from current context. + /// + /// ### Calling from subexpression + /// + /// When calling the helper as a subexpression, the value and its type can + /// be received by upper level helpers. + /// + /// Note that the value can be `json!(null)` which is treated as `false` in + /// helpers like `if` and rendered as empty string. + fn call_inner<'reg: 'rc, 'rc>( + &self, + _: &Helper<'reg, 'rc>, + _: &'reg Registry<'reg>, + _: &'rc Context, + _: &mut RenderContext<'reg, 'rc>, + ) -> Result, RenderError> { + Err(RenderError::unimplemented()) + } + + /// A complex version of helper interface. + /// + /// This function offers `Output`, which you can write custom string into + /// and render child template. Helpers like `if` and `each` are implemented + /// with this. Because the data written into `Output` are typically without + /// type information. So helpers defined by this function are not composable. + /// + /// ### Calling from subexpression + /// + /// Although helpers defined by this are not composable, when called from + /// subexpression, handlebars tries to parse the string output as JSON to + /// re-build its type. This can be buggy with numrical and other literal values. + /// So it is not recommended to use these helpers in subexpression. + fn call<'reg: 'rc, 'rc>( + &self, + h: &Helper<'reg, 'rc>, + r: &'reg Registry<'reg>, + ctx: &'rc Context, + rc: &mut RenderContext<'reg, 'rc>, + out: &mut dyn Output, + ) -> HelperResult { + match self.call_inner(h, r, ctx, rc) { + Ok(result) => { + if r.strict_mode() && result.is_missing() { + Err(RenderError::strict_error(None)) + } else { + // auto escape according to settings + let output = do_escape(r, rc, result.render()); + out.write(output.as_ref())?; + Ok(()) + } + } + Err(e) => { + if e.is_unimplemented() { + // default implementation, do nothing + Ok(()) + } else { + Err(e) + } + } + } + } +} + +/// implement HelperDef for bare function so we can use function as helper +impl< + F: for<'reg, 'rc> Fn( + &Helper<'reg, 'rc>, + &'reg Registry<'reg>, + &'rc Context, + &mut RenderContext<'reg, 'rc>, + &mut dyn Output, + ) -> HelperResult, + > HelperDef for F +{ + fn call<'reg: 'rc, 'rc>( + &self, + h: &Helper<'reg, 'rc>, + r: &'reg Registry<'reg>, + ctx: &'rc Context, + rc: &mut RenderContext<'reg, 'rc>, + out: &mut dyn Output, + ) -> HelperResult { + (*self)(h, r, ctx, rc, out) + } +} + +mod block_util; +mod helper_each; +pub(crate) mod helper_extras; +mod helper_if; +mod helper_log; +mod helper_lookup; +mod helper_raw; +mod helper_with; +#[cfg(feature = "script_helper")] +pub(crate) mod scripting; + +// pub type HelperDef = for <'a, 'b, 'c> Fn<(&'a Context, &'b Helper, &'b Registry, &'c mut RenderContext), Result>; +// +// pub fn helper_dummy (ctx: &Context, h: &Helper, r: &Registry, rc: &mut RenderContext) -> Result { +// h.template().unwrap().render(ctx, r, rc).unwrap() +// } +// +#[cfg(test)] +mod test { + use std::collections::BTreeMap; + + use crate::context::Context; + use crate::error::RenderError; + use crate::helpers::HelperDef; + use crate::json::value::JsonRender; + use crate::output::Output; + use crate::registry::Registry; + use crate::render::{Helper, RenderContext, Renderable}; + + #[derive(Clone, Copy)] + struct MetaHelper; + + impl HelperDef for MetaHelper { + fn call<'reg: 'rc, 'rc>( + &self, + h: &Helper<'reg, 'rc>, + r: &'reg Registry<'reg>, + ctx: &'rc Context, + rc: &mut RenderContext<'reg, 'rc>, + out: &mut dyn Output, + ) -> Result<(), RenderError> { + let v = h.param(0).unwrap(); + + if !h.is_block() { + let output = format!("{}:{}", h.name(), v.value().render()); + out.write(output.as_ref())?; + } else { + let output = format!("{}:{}", h.name(), v.value().render()); + out.write(output.as_ref())?; + out.write("->")?; + h.template().unwrap().render(r, ctx, rc, out)?; + }; + Ok(()) + } + } + + #[test] + fn test_meta_helper() { + let mut handlebars = Registry::new(); + assert!(handlebars + .register_template_string("t0", "{{foo this}}") + .is_ok()); + assert!(handlebars + .register_template_string("t1", "{{#bar this}}nice{{/bar}}") + .is_ok()); + + let meta_helper = MetaHelper; + handlebars.register_helper("helperMissing", Box::new(meta_helper)); + handlebars.register_helper("blockHelperMissing", Box::new(meta_helper)); + + let r0 = handlebars.render("t0", &true); + assert_eq!(r0.ok().unwrap(), "foo:true".to_string()); + + let r1 = handlebars.render("t1", &true); + assert_eq!(r1.ok().unwrap(), "bar:true->nice".to_string()); + } + + #[test] + fn test_helper_for_subexpression() { + let mut handlebars = Registry::new(); + assert!(handlebars + .register_template_string("t2", "{{foo value=(bar 0)}}") + .is_ok()); + + handlebars.register_helper( + "helperMissing", + Box::new( + |h: &Helper<'_, '_>, + _: &Registry<'_>, + _: &Context, + _: &mut RenderContext<'_, '_>, + out: &mut dyn Output| + -> Result<(), RenderError> { + let output = format!("{}{}", h.name(), h.param(0).unwrap().value()); + out.write(output.as_ref())?; + Ok(()) + }, + ), + ); + handlebars.register_helper( + "foo", + Box::new( + |h: &Helper<'_, '_>, + _: &Registry<'_>, + _: &Context, + _: &mut RenderContext<'_, '_>, + out: &mut dyn Output| + -> Result<(), RenderError> { + let output = format!("{}", h.hash_get("value").unwrap().value().render()); + out.write(output.as_ref())?; + Ok(()) + }, + ), + ); + + let mut data = BTreeMap::new(); + // handlebars should never try to lookup this value because + // subexpressions are now resolved as string literal + data.insert("bar0".to_string(), true); + + let r2 = handlebars.render("t2", &data); + + assert_eq!(r2.ok().unwrap(), "bar0".to_string()); + } +} -- cgit v1.2.3