From e441f66e1777e92c2d091bf22c739e7f5c9d5e6b Mon Sep 17 00:00:00 2001 From: Rodney Lab Date: Thu, 28 Nov 2024 09:14:30 +0000 Subject: [PATCH] =?UTF-8?q?ci:=20=F0=9F=90=9D=20add=20JSR=20metadata?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- deno.json | 5 +++- src/text/mod.rs | 66 +++++++++++++++++++++++++++++++++++++++++++++++ src/text/tests.rs | 43 ++++++++++++++++++++++++++++++ 3 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 src/text/mod.rs create mode 100644 src/text/tests.rs diff --git a/deno.json b/deno.json index f420400..388ba0f 100644 --- a/deno.json +++ b/deno.json @@ -1,4 +1,8 @@ { + "name": "@rodney/parsedown", + "version": "0.4.2", + "license": "BSD-3-Clause", + "exports": "./mod.ts", "fmt": { "exclude": [".github/"] }, @@ -7,6 +11,5 @@ "test": "deno test -A", "wasmbuild": "deno run -A jsr:@deno/wasmbuild@0.17.3 --project=parsedown" }, - "exclude": ["lib/"], "imports": { "@std/assert": "jsr:@std/assert@^1.0.8" } } diff --git a/src/text/mod.rs b/src/text/mod.rs new file mode 100644 index 0000000..fc6f5a1 --- /dev/null +++ b/src/text/mod.rs @@ -0,0 +1,66 @@ +#[cfg(test)] +mod tests; + +use std::borrow::Cow; + +pub fn format_line<'a, I: Into>>(line: I) -> Cow<'a, str> { + let line = line.into(); + fn is_replace_character(c: char) -> bool { + c == '\'' || c == '"' + } + + let first = line.find(is_replace_character); + if let Some(value) = first { + let (mut result, rest) = match value { + 0 => match &line[0..1] { + "\"" => (String::from('\u{201c}'), line[1..].chars()), + "'" => (String::from('\u{2018}'), line[1..].chars()), + _ => (String::from(&line[0..value]), line[value..].chars()), + }, + _ => { + if &line[(value - 1)..value] == " " { + ( + String::from(&line[0..(value - 1)]), + line[(value - 1)..].chars(), + ) + } else { + (String::from(&line[0..value]), line[value..].chars()) + } + } + }; + result.reserve(line.len() - value); + + let mut preceded_by_space = false; + for c in rest { + match c { + '\'' => { + if preceded_by_space { + preceded_by_space = false; + result.push('\u{2018}') + } else { + result.push('\u{2019}') + } + } + '"' => { + if preceded_by_space { + preceded_by_space = false; + result.push('\u{201c}') + } else { + result.push('\u{201d}') + } + } + ' ' => { + preceded_by_space = true; + result.push(c); + } + _ => { + preceded_by_space = false; + result.push(c); + } + } + } + Cow::Owned(result) + } else { + line + } +} diff --git a/src/text/tests.rs b/src/text/tests.rs new file mode 100644 index 0000000..6954817 --- /dev/null +++ b/src/text/tests.rs @@ -0,0 +1,43 @@ +use crate::text::format_line; + +#[test] +fn format_line_replaces_inner_apostrophe() { + let line = "My apple's quite tasty."; + let result = format_line(line); + assert_eq!(result, "My apple’s quite tasty."); +} + +#[test] +fn test_line_replaces_outer_apostrophe() { + let line = "My trees' apples are tasty."; + let result = format_line(line); + assert_eq!(result, "My trees’ apples are tasty."); +} + +#[test] +fn test_line_adds_double_smart_quotes() { + let line = r#"The person said "My apple is quite tasty.""#; + let result = format_line(line); + assert_eq!(result, r#"The person said “My apple is quite tasty.”"#); +} + +#[test] +fn test_line_adds_single_smart_quotes() { + let line = "My apple is quite 'tasty'."; + let result = format_line(line); + assert_eq!(result, "My apple is quite ‘tasty’."); +} + +#[test] +fn test_line_replaces_unmatched_single_double_quote_pairs() { + let line = r#"My apple is quite 'tasty"."#; + let result = format_line(line); + assert_eq!(result, "My apple is quite ‘tasty”."); +} + +#[test] +fn test_line_does_nothing_when_line_has_no_quotes_or_apostrophes() { + let line = "My apple is quite tasty."; + let result = format_line(line); + assert_eq!(result, "My apple is quite tasty."); +}