Skip to content

Commit

Permalink
Properly escape characters, including \u200b (closes #209).
Browse files Browse the repository at this point in the history
  • Loading branch information
01mf02 committed Sep 10, 2024
1 parent 3923d87 commit b8f8e4f
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 10 deletions.
22 changes: 21 additions & 1 deletion jaq-json/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -876,6 +876,26 @@ fn float_cmp(left: f64, right: f64) -> Ordering {
}
}

/// Format a string as valid JSON string, including leading and trailing quotes.
pub fn fmt_str(f: &mut fmt::Formatter, s: &str) -> fmt::Result {
write!(f, "\"")?;
for s in s.split_inclusive(|c| c < ' ' || c == '\\' || c == '"') {
// split s into last character and everything before (init)
let mut chars = s.chars();
let last = chars.next_back();
let init = chars.as_str();

match last {
Some(last @ ('\t' | '\n' | '\r' | '\\' | '"')) => {
write!(f, "{init}{}", last.escape_default())
}
Some(last) if last < ' ' => write!(f, "{init}\\u{:04x}", last as u8),
_ => write!(f, "{s}"),
}?;
}
write!(f, "\"")
}

impl fmt::Display for Val {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Expand All @@ -885,7 +905,7 @@ impl fmt::Display for Val {
Self::Float(x) if x.is_finite() => write!(f, "{x:?}"),
Self::Float(_) => write!(f, "null"),
Self::Num(n) => write!(f, "{n}"),
Self::Str(s) => write!(f, "{s:?}"),
Self::Str(s) => fmt_str(f, s),
Self::Arr(a) => {
write!(f, "[")?;
let mut iter = a.iter();
Expand Down
7 changes: 5 additions & 2 deletions jaq-play/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use core::fmt::{self, Debug, Display, Formatter};
use jaq_core::{compile, load, Ctx, Native, RcIter};
use jaq_json::Val;
use jaq_json::{fmt_str, Val};
use wasm_bindgen::prelude::*;

type Filter = jaq_core::Filter<Native<Val>>;
Expand Down Expand Up @@ -60,7 +60,10 @@ fn fmt_val(f: &mut Formatter, opts: &PpOpts, level: usize, v: &Val) -> fmt::Resu
Val::Float(x) if x.is_finite() => span_dbg(f, "number", x),
Val::Float(_) => span(f, "null", "null"),
Val::Num(n) => span(f, "number", n),
Val::Str(s) => span_dbg(f, "string", escape(s)),
Val::Str(s) => {
let display = FormatterFn(|f: &mut Formatter| fmt_str(f, &escape(s)));
span(f, "string", display)
}
Val::Arr(a) if a.is_empty() => write!(f, "[]"),
Val::Arr(a) => {
write!(f, "[")?;
Expand Down
9 changes: 2 additions & 7 deletions jaq/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -554,13 +554,8 @@ where
fn fmt_val(f: &mut Formatter, opts: &PpOpts, level: usize, v: &Val) -> fmt::Result {
use yansi::Paint;
match v {
Val::Null => "null".fmt(f),
Val::Bool(b) => b.fmt(f),
Val::Int(i) => i.fmt(f),
Val::Float(x) if x.is_finite() => write!(f, "{x:?}"),
Val::Float(_) => "null".fmt(f),
Val::Num(n) => n.fmt(f),
Val::Str(s) => write!(f, "{:?}", s.green()),
Val::Null | Val::Bool(_) | Val::Int(_) | Val::Float(_) | Val::Num(_) => v.fmt(f),
Val::Str(_) => write!(f, "{}", v.green()),
Val::Arr(a) => {
'['.bold().fmt(f)?;
if !a.is_empty() {
Expand Down
7 changes: 7 additions & 0 deletions jaq/tests/golden.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,13 @@ test!(
"Three""#
);

test!(
fmt_str,
&[],
r#""\u0000\u200b\r\t\n asdf""#,
r#""\u0000​\r\t\n asdf""#
);

test!(
mods,
&["-c", "-L", "tests", r#"include "a"; [a, data]"#],
Expand Down

0 comments on commit b8f8e4f

Please sign in to comment.