Skip to content
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

Can't pass single-quoted strings as parameters #575

Closed
nickvollmar opened this issue May 2, 2023 · 1 comment
Closed

Can't pass single-quoted strings as parameters #575

nickvollmar opened this issue May 2, 2023 · 1 comment

Comments

@nickvollmar
Copy link
Contributor

Reproduction

In tests/helper_macro.rs, within the function test_macro_helper, you can add the following assertion.

    assert_eq!(
        hbs.render_template("{{tag 'html'}}", &()).unwrap(),
        "<html>"
    );
thread 'test_macro_helper' panicked at 'called `Result::unwrap()` on an `Err` value: RenderError { desc: "`tag` helper: Couldn't convert parameter t to type `str`. It's Null as JSON. Got these params: [PathAndJson { relative_path: Some(\"'html'\"), value: Missing }]", template_name: None, line_no: Some(1), column_no: Some(1), cause: None, unimplemented: false }', tests/helper_macro.rs:77:52

Cause

I believe the origin of this behavior is

if let Ok(json) = Json::from_str(s) {
Parameter::Literal(json)
} else {
Parameter::Name(s.to_owned())
}

The single-quoted literal matches the Rule::literal parser rule, but it is not valid JSON, so it becomes a Name object.

As evidence of this, here is the data structure I get by parsing the template {{tag 'html'}}:

Template {
  name: None,
  elements: [
    Expression(HelperTemplate {
      name: Name("tag"),
      params: [Name("'html'")],
      hash: {},
      block_param: None,
      template: None,
      inverse: None,
      block: false
    })
  ],
  mapping: [TemplateMapping(1, 1)]
}

Proposal

I think the way forward is to somehow extract more information from the pest parse results.

Here is a rough sketch of how I think that logic might look. As you can see, I'm out of my depth here, but this passes all the tests!

Rule::literal => {
    let param = param.into_inner().next().unwrap();
    match param.as_rule() {
        Rule::string_literal => {
            let string_inner = param.into_inner().next().unwrap();
            // don't double-escape characters - see test_string_no_escape_422
            let double_quoted = format!("\"{}\"", string_inner.as_str());
            Parameter::Literal(Json::from_str(&double_quoted).unwrap())
        }
        _ => {
            Parameter::Literal(Json::from_str(param_span.as_str()).unwrap())
        }
    }
}

(In the suggestion above I removed the Name code path, since I don't think any other JSON data type would make sense as a Name.)

Thank you very much, for reading this report and for all your work on this project.

@sunng87
Copy link
Owner

sunng87 commented May 4, 2023

Thank you for reporting and the solution looks good to me. Could you please create a pull request for this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants