Skip to content

Update dependency handlebars to v5 for mdman. #13249

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 4, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -48,7 +48,7 @@ git2-curl = "0.19.0"
gix = { version = "0.57.1", default-features = false, features = ["blocking-http-transport-curl", "progress-tree", "revision"] }
gix-features-for-configuration-only = { version = "0.37.1", package = "gix-features", features = [ "parallel" ] }
glob = "0.3.1"
handlebars = { version = "4.5.0", features = ["dir_source"] }
handlebars = { version = "5.0.0", features = ["dir_source"] }
hex = "0.4.3"
hmac = "0.12.1"
home = "0.5.9"
88 changes: 56 additions & 32 deletions crates/mdman/src/hbs.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
//! Handlebars template processing.
use crate::format::Formatter;
use std::collections::HashMap;
use std::path::Path;

use anyhow::Error;
use handlebars::{
handlebars_helper, Context, Decorator, Handlebars, Helper, HelperDef, HelperResult, Output,
RenderContext, RenderError, Renderable,
handlebars_helper, Context, Decorator, DirectorySourceOptions, Handlebars, Helper, HelperDef,
HelperResult, Output, RenderContext, RenderError, RenderErrorReason, Renderable,
};
use std::collections::HashMap;
use std::path::Path;

use crate::format::Formatter;

type FormatterRef<'a> = &'a (dyn Formatter + Send + Sync);

@@ -22,7 +24,12 @@ pub fn expand(file: &Path, formatter: FormatterRef<'_>) -> Result<String, Error>
handlebars.register_decorator("set", Box::new(set_decorator));
handlebars.register_template_file("template", file)?;
let includes = file.parent().unwrap().join("includes");
handlebars.register_templates_directory(".md", includes)?;
let options = DirectorySourceOptions {
tpl_extension: ".md".to_string(),
hidden: false,
temporary: false,
};
handlebars.register_templates_directory(includes, options)?;
let man_name = file
.file_stem()
.expect("expected filename")
@@ -42,22 +49,29 @@ struct OptionsHelper<'a> {
impl HelperDef for OptionsHelper<'_> {
fn call<'reg: 'rc, 'rc>(
&self,
h: &Helper<'reg, 'rc>,
h: &Helper<'rc>,
r: &'reg Handlebars<'reg>,
ctx: &'rc Context,
rc: &mut RenderContext<'reg, 'rc>,
out: &mut dyn Output,
) -> HelperResult {
if in_options(rc) {
return Err(RenderError::new("options blocks cannot be nested"));
return Err(
RenderErrorReason::Other("options blocks cannot be nested".to_string()).into(),
);
}
// Prevent nested {{#options}}.
set_in_context(rc, "__MDMAN_IN_OPTIONS", serde_json::Value::Bool(true));
let s = self.formatter.render_options_start();
out.write(&s)?;
let t = match h.template() {
Some(t) => t,
None => return Err(RenderError::new("options block must not be empty")),
None => {
return Err(RenderErrorReason::Other(
"options block must not be empty".to_string(),
)
.into());
}
};
let block = t.renders(r, ctx, rc)?;
out.write(&block)?;
@@ -83,20 +97,23 @@ struct OptionHelper<'a> {
impl HelperDef for OptionHelper<'_> {
fn call<'reg: 'rc, 'rc>(
&self,
h: &Helper<'reg, 'rc>,
h: &Helper<'rc>,
r: &'reg Handlebars<'reg>,
ctx: &'rc Context,
rc: &mut RenderContext<'reg, 'rc>,
out: &mut dyn Output,
) -> HelperResult {
if !in_options(rc) {
return Err(RenderError::new("option must be in options block"));
return Err(
RenderErrorReason::Other("option must be in options block".to_string()).into(),
);
}
let params = h.params();
if params.is_empty() {
return Err(RenderError::new(
"option block must have at least one param",
));
return Err(RenderErrorReason::Other(
"option block must have at least one param".to_string(),
)
.into());
}
// Convert params to strings.
let params = params
@@ -105,12 +122,19 @@ impl HelperDef for OptionHelper<'_> {
param
.value()
.as_str()
.ok_or_else(|| RenderError::new("option params must be strings"))
.ok_or_else(|| {
RenderErrorReason::Other("option params must be strings".to_string())
})
.into()
})
.collect::<Result<Vec<&str>, RenderError>>()?;
.collect::<Result<Vec<&str>, RenderErrorReason>>()?;
let t = match h.template() {
Some(t) => t,
None => return Err(RenderError::new("option block must not be empty")),
None => {
return Err(
RenderErrorReason::Other("option block must not be empty".to_string()).into(),
);
}
};
// Render the block.
let block = t.renders(r, ctx, rc)?;
@@ -127,7 +151,7 @@ impl HelperDef for OptionHelper<'_> {
let option = self
.formatter
.render_option(&params, &block, man_name)
.map_err(|e| RenderError::new(format!("option render failed: {}", e)))?;
.map_err(|e| RenderErrorReason::Other(format!("option render failed: {}", e)))?;
out.write(&option)?;
Ok(())
}
@@ -141,30 +165,30 @@ struct ManLinkHelper<'a> {
impl HelperDef for ManLinkHelper<'_> {
fn call<'reg: 'rc, 'rc>(
&self,
h: &Helper<'reg, 'rc>,
h: &Helper<'rc>,
_r: &'reg Handlebars<'reg>,
_ctx: &'rc Context,
_rc: &mut RenderContext<'reg, 'rc>,
out: &mut dyn Output,
) -> HelperResult {
let params = h.params();
if params.len() != 2 {
return Err(RenderError::new("{{man}} must have two arguments"));
return Err(
RenderErrorReason::Other("{{man}} must have two arguments".to_string()).into(),
);
}
let name = params[0]
.value()
.as_str()
.ok_or_else(|| RenderError::new("man link name must be a string"))?;
let section = params[1]
.value()
.as_u64()
.ok_or_else(|| RenderError::new("man link section must be an integer"))?;
let section =
u8::try_from(section).map_err(|_e| RenderError::new("section number too large"))?;
let name = params[0].value().as_str().ok_or_else(|| {
RenderErrorReason::Other("man link name must be a string".to_string())
})?;
let section = params[1].value().as_u64().ok_or_else(|| {
RenderErrorReason::Other("man link section must be an integer".to_string())
})?;
let section = u8::try_from(section)
.map_err(|_e| RenderErrorReason::Other("section number too large".to_string()))?;
let link = self
.formatter
.linkify_man_to_md(name, section)
.map_err(|e| RenderError::new(format!("failed to linkify man: {}", e)))?;
.map_err(|e| RenderErrorReason::Other(format!("failed to linkify man: {}", e)))?;
out.write(&link)?;
Ok(())
}
@@ -174,7 +198,7 @@ impl HelperDef for ManLinkHelper<'_> {
///
/// This sets a variable to a value within the template context.
fn set_decorator(
d: &Decorator<'_, '_>,
d: &Decorator<'_>,
_: &Handlebars<'_>,
_ctx: &Context,
rc: &mut RenderContext<'_, '_>,