aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lib.rs267
-rw-r--r--src/to_html.rs5
-rw-r--r--src/util/line_ending.rs129
-rw-r--r--src/util/mdx.rs131
-rw-r--r--src/util/mod.rs2
5 files changed, 277 insertions, 257 deletions
diff --git a/src/lib.rs b/src/lib.rs
index f874c02..f655bbc 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -14,8 +14,9 @@
#![no_std]
#![deny(clippy::pedantic)]
#![allow(clippy::doc_link_with_quotes)]
-#![allow(clippy::too_many_lines)]
#![allow(clippy::missing_panics_doc)]
+#![allow(clippy::must_use_candidate)]
+#![allow(clippy::too_many_lines)]
#![doc(
html_logo_url = "https://raw.githubusercontent.com/wooorm/markdown-rs/8924580/media/logo-monochromatic.svg?sanitize=true"
)]
@@ -48,159 +49,12 @@ pub use util::sanitize_uri::sanitize;
#[doc(hidden)]
pub use util::location::Location;
-/// Type of line endings in markdown.
-///
-/// Particularly when working with Windows, you might want to use
-/// `LineEnding::CarriageReturnLineFeed`.
-///
-/// ## Examples
-///
-/// ```
-/// use markdown::LineEnding;
-/// # fn main() {
-///
-/// // Use a CR + LF combination:
-/// let crlf = LineEnding::CarriageReturnLineFeed;
-/// # }
-/// ```
-#[derive(Clone, Debug, Default, Eq, PartialEq)]
-pub enum LineEnding {
- /// Both a carriage return (`\r`) and a line feed (`\n`).
- ///
- /// ## Example
- ///
- /// ```markdown
- /// a␍␊
- /// b
- /// ```
- CarriageReturnLineFeed,
- /// Sole carriage return (`\r`).
- ///
- /// ## Example
- ///
- /// ```markdown
- /// a␍
- /// b
- /// ```
- CarriageReturn,
- /// Sole line feed (`\n`).
- ///
- /// ## Example
- ///
- /// ```markdown
- /// a␊
- /// b
- /// ```
- #[default]
- LineFeed,
-}
+pub use util::line_ending::LineEnding;
-impl LineEnding {
- /// Turn the line ending into a [str].
- fn as_str(&self) -> &str {
- match self {
- LineEnding::CarriageReturnLineFeed => "\r\n",
- LineEnding::CarriageReturn => "\r",
- LineEnding::LineFeed => "\n",
- }
- }
- /// Turn a string into a line ending.
- ///
- /// ## Panics
- ///
- /// Panics if `code` is not `\r\n`, `\r`, or `\n`.
- fn from_str(str: &str) -> LineEnding {
- debug_assert!(matches!(str, "\r\n" | "\r" | "\n"), "expected eol");
- match str {
- "\r\n" => LineEnding::CarriageReturnLineFeed,
- "\r" => LineEnding::CarriageReturn,
- _ => LineEnding::LineFeed,
- }
- }
-}
-
-/// Signal used as feedback when parsing MDX ESM/expressions.
-#[derive(Clone, Debug)]
-pub enum MdxSignal {
- /// A syntax error.
- ///
- /// `markdown-rs` will crash with error message `String`, and convert the
- /// `usize` (byte offset into `&str` passed to `MdxExpressionParse` or
- /// `MdxEsmParse`) to where it happened in the whole document.
- ///
- /// ## Examples
- ///
- /// ```rust ignore
- /// MdxSignal::Error("Unexpected `\"`, expected identifier".into(), 1)
- /// ```
- Error(String, usize),
- /// An error at the end of the (partial?) expression.
- ///
- /// `markdown-rs` will either crash with error message `String` if it
- /// doesn’t have any more text, or it will try again later when more text
- /// is available.
- ///
- /// ## Examples
- ///
- /// ```rust ignore
- /// MdxSignal::Eof("Unexpected end of file in string literal".into())
- /// ```
- Eof(String),
- /// Done, successfully.
- ///
- /// `markdown-rs` knows that this is the end of a valid expression/esm and
- /// continues with markdown.
- ///
- /// ## Examples
- ///
- /// ```rust ignore
- /// MdxSignal::Ok
- /// ```
- Ok,
-}
-
-/// Signature of a function that parses MDX ESM.
-///
-/// Can be passed as `mdx_esm_parse` in [`ParseOptions`][] to support
-/// ESM according to a certain grammar (typically, a programming language).
-pub type MdxEsmParse = dyn Fn(&str) -> MdxSignal;
-
-/// Expression kind.
-#[derive(Clone, Debug)]
-pub enum MdxExpressionKind {
- /// Kind of expressions in prose.
- ///
- /// ```mdx
- /// > | # {Math.PI}
- /// ^^^^^^^^^
- /// |
- /// > | {Math.PI}
- /// ^^^^^^^^^
- /// ```
- Expression,
- /// Kind of expressions as attributes.
- ///
- /// ```mdx
- /// > | <a {...b}>
- /// ^^^^^^
- /// ```
- AttributeExpression,
- /// Kind of expressions as attribute values.
- ///
- /// ```mdx
- /// > | <a b={c}>
- /// ^^^
- /// ```
- AttributeValueExpression,
-}
-
-/// Signature of a function that parses MDX expressions.
-///
-/// Can be passed as `mdx_expression_parse` in [`ParseOptions`][] to support
-/// expressions according to a certain grammar (typically, a programming
-/// language).
-///
-pub type MdxExpressionParse = dyn Fn(&str, &MdxExpressionKind) -> MdxSignal;
+pub use util::mdx::{
+ EsmParse as MdxEsmParse, ExpressionKind as MdxExpressionKind,
+ ExpressionParse as MdxExpressionParse, Signal as MdxSignal,
+};
/// Control which constructs are enabled.
///
@@ -527,6 +381,7 @@ pub struct Constructs {
pub thematic_break: bool,
}
+// xxxxxxxxxxxxxxx
impl Default for Constructs {
/// `CommonMark`.
///
@@ -585,7 +440,7 @@ impl Constructs {
///
/// For more information, see the GFM specification:
/// <https://github.github.com/gfm/>.
- #[must_use]
+ // xxxxxxxxxxxxxxx
pub fn gfm() -> Self {
Self {
gfm_autolink_literal: true,
@@ -617,7 +472,7 @@ impl Constructs {
/// > programming language).
/// > Otherwise, expressions are parsed with a basic algorithm that only
/// > cares about braces.
- #[must_use]
+ // xxxxxxxxxxxxxxx
pub fn mdx() -> Self {
Self {
autolink: false,
@@ -1088,6 +943,7 @@ pub struct CompileOptions {
pub gfm_tagfilter: bool,
}
+// xxxxxxxxxxxxxxx
impl CompileOptions {
/// GFM.
///
@@ -1098,7 +954,6 @@ impl CompileOptions {
///
/// For more information, see the GFM specification:
/// <https://github.github.com/gfm/>.
- #[must_use]
pub fn gfm() -> Self {
Self {
gfm_tagfilter: true,
@@ -1355,7 +1210,6 @@ impl ParseOptions {
///
/// For more information, see the GFM specification:
/// <https://github.github.com/gfm/>
- #[must_use]
pub fn gfm() -> Self {
Self {
constructs: Constructs::gfm(),
@@ -1382,7 +1236,7 @@ impl ParseOptions {
/// > programming language).
/// > Otherwise, expressions are parsed with a basic algorithm that only
/// > cares about braces.
- #[must_use]
+ // xxxxxxxxxxxxxxx
pub fn mdx() -> Self {
Self {
constructs: Constructs::mdx(),
@@ -1429,7 +1283,6 @@ impl Options {
///
/// For more information, see the GFM specification:
/// <https://github.github.com/gfm/>
- #[must_use]
pub fn gfm() -> Self {
Self {
parse: ParseOptions::gfm(),
@@ -1451,7 +1304,7 @@ impl Options {
///
/// assert_eq!(to_html("# Hello, world!"), "<h1>Hello, world!</h1>");
/// ```
-#[must_use]
+// xxxxxxxxxxxxxxx
pub fn to_html(value: &str) -> String {
to_html_with_options(value, &Options::default()).unwrap()
}
@@ -1536,51 +1389,7 @@ mod tests {
use alloc::format;
#[test]
- fn test_line_ending() {
- assert_eq!(
- LineEnding::from_str("\r"),
- LineEnding::CarriageReturn,
- "should support turning a string into a carriage return"
- );
- assert_eq!(
- LineEnding::CarriageReturn.as_str(),
- "\r",
- "should support turning a carriage return into a string"
- );
-
- assert_eq!(
- LineEnding::from_str("\n"),
- LineEnding::LineFeed,
- "should support turning a string into a line feed"
- );
- assert_eq!(
- LineEnding::LineFeed.as_str(),
- "\n",
- "should support turning a line feed into a string"
- );
-
- assert_eq!(
- LineEnding::from_str("\r\n"),
- LineEnding::CarriageReturnLineFeed,
- "should support turning a string into a carriage return + line feed"
- );
- assert_eq!(
- LineEnding::CarriageReturnLineFeed.as_str(),
- "\r\n",
- "should support turning a carriage return + line feed into a string"
- );
- }
-
- #[test]
- #[should_panic = "expected eol"]
- fn test_line_ending_broken() {
- // Hide stack trace.
- LineEnding::from_str("a");
- }
-
- #[test]
fn test_constructs() {
- #![allow(unused_must_use)]
Constructs::default();
Constructs::gfm();
Constructs::mdx();
@@ -1624,7 +1433,6 @@ mod tests {
#[test]
fn test_parse_options() {
- #![allow(unused_must_use)]
ParseOptions::default();
ParseOptions::gfm();
ParseOptions::mdx();
@@ -1693,7 +1501,6 @@ mod tests {
#[test]
fn test_compile_options() {
- #![allow(unused_must_use)]
CompileOptions::default();
CompileOptions::gfm();
@@ -1720,7 +1527,6 @@ mod tests {
#[test]
fn test_options() {
- #![allow(unused_must_use)]
Options::default();
let options = Options::default();
@@ -1762,9 +1568,6 @@ mod tests {
#[test]
fn test_to_html() {
- #![allow(unused_must_use)]
- to_html("a");
-
assert_eq!(
to_html("a"),
"<p>a</p>",
@@ -1774,9 +1577,6 @@ mod tests {
#[test]
fn test_to_html_with_options() {
- #![allow(unused_must_use)]
- to_html_with_options("a", &Options::default());
-
assert_eq!(
to_html_with_options("a", &Options::default()).unwrap(),
"<p>a</p>",
@@ -1786,9 +1586,6 @@ mod tests {
#[test]
fn test_to_mdast() {
- #![allow(unused_must_use)]
- to_mdast("a", &ParseOptions::default());
-
assert!(
matches!(
to_mdast("a", &ParseOptions::default()).unwrap(),
@@ -1797,42 +1594,4 @@ mod tests {
"should support turning markdown into mdast with `to_mdast`"
);
}
-
- #[test]
- fn test_mdx_expression_parse() {
- fn func(_value: &str, _kind: &MdxExpressionKind) -> MdxSignal {
- MdxSignal::Ok
- }
-
- let func_accepting = |_a: Box<MdxExpressionParse>| true;
-
- assert!(
- matches!(func("a", &MdxExpressionKind::Expression), MdxSignal::Ok),
- "should expose an `MdxExpressionParse` type (1)"
- );
-
- assert!(
- func_accepting(Box::new(func)),
- "should expose an `MdxExpressionParse` type (2)"
- );
- }
-
- #[test]
- fn test_mdx_esm_parse() {
- fn func(_value: &str) -> MdxSignal {
- MdxSignal::Ok
- }
-
- let func_accepting = |_a: Box<MdxEsmParse>| true;
-
- assert!(
- matches!(func("a"), MdxSignal::Ok),
- "should expose an `MdxEsmParse` type (1)"
- );
-
- assert!(
- func_accepting(Box::new(func)),
- "should expose an `MdxEsmParse` type (2)"
- );
- }
}
diff --git a/src/to_html.rs b/src/to_html.rs
index 6811350..2685120 100644
--- a/src/to_html.rs
+++ b/src/to_html.rs
@@ -216,9 +216,8 @@ pub fn compile(events: &[Event], bytes: &[u8], options: &CompileOptions) -> Stri
if event.kind == Kind::Exit
&& (event.name == Name::BlankLineEnding || event.name == Name::LineEnding)
{
- line_ending_inferred = Some(LineEnding::from_str(
- Slice::from_position(bytes, &Position::from_exit_event(events, index)).as_str(),
- ));
+ let slice = Slice::from_position(bytes, &Position::from_exit_event(events, index));
+ line_ending_inferred = Some(slice.as_str().parse().unwrap());
break;
}
diff --git a/src/util/line_ending.rs b/src/util/line_ending.rs
new file mode 100644
index 0000000..a018fe8
--- /dev/null
+++ b/src/util/line_ending.rs
@@ -0,0 +1,129 @@
+extern crate alloc;
+
+use alloc::{str::FromStr, string::String};
+
+/// Type of line endings in markdown.
+///
+/// Particularly when working with Windows, you might want to use
+/// `LineEnding::CarriageReturnLineFeed`.
+///
+/// ## Examples
+///
+/// ```
+/// use markdown::LineEnding;
+/// # fn main() {
+///
+/// // Use a CR + LF combination:
+/// let crlf = LineEnding::CarriageReturnLineFeed;
+/// # }
+/// ```
+#[derive(Clone, Debug, Default, Eq, PartialEq)]
+pub enum LineEnding {
+ /// Both a carriage return (`\r`) and a line feed (`\n`).
+ ///
+ /// ## Example
+ ///
+ /// ```markdown
+ /// a␍␊
+ /// b
+ /// ```
+ CarriageReturnLineFeed,
+ /// Sole carriage return (`\r`).
+ ///
+ /// ## Example
+ ///
+ /// ```markdown
+ /// a␍
+ /// b
+ /// ```
+ CarriageReturn,
+ /// Sole line feed (`\n`).
+ ///
+ /// ## Example
+ ///
+ /// ```markdown
+ /// a␊
+ /// b
+ /// ```
+ #[default]
+ LineFeed,
+}
+
+// xxxxxxxxxxxxxxx
+impl LineEnding {
+ /// Turn the line ending into a [str].
+ #[must_use]
+ pub fn as_str(&self) -> &str {
+ match self {
+ LineEnding::CarriageReturnLineFeed => "\r\n",
+ LineEnding::CarriageReturn => "\r",
+ LineEnding::LineFeed => "\n",
+ }
+ }
+}
+
+impl FromStr for LineEnding {
+ type Err = String;
+
+ /// Turn a string into a line ending.
+ ///
+ /// ## Panics
+ ///
+ /// Panics if `code` is not `\r\n`, `\r`, or `\n`.
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ match s {
+ "\r\n" => Ok(LineEnding::CarriageReturnLineFeed),
+ "\r" => Ok(LineEnding::CarriageReturn),
+ "\n" => Ok(LineEnding::LineFeed),
+ _ => Err("Expected CR, LF, or CRLF".into()),
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ extern crate std;
+ use super::*;
+
+ #[test]
+ fn test_line_ending() {
+ assert_eq!(
+ "\r".parse(),
+ Ok(LineEnding::CarriageReturn),
+ "should support turning a string into a carriage return"
+ );
+ assert_eq!(
+ LineEnding::CarriageReturn.as_str(),
+ "\r",
+ "should support turning a carriage return into a string"
+ );
+
+ assert_eq!(
+ "\n".parse(),
+ Ok(LineEnding::LineFeed),
+ "should support turning a string into a line feed"
+ );
+ assert_eq!(
+ LineEnding::LineFeed.as_str(),
+ "\n",
+ "should support turning a line feed into a string"
+ );
+
+ assert_eq!(
+ "\r\n".parse(),
+ Ok(LineEnding::CarriageReturnLineFeed),
+ "should support turning a string into a carriage return + line feed"
+ );
+ assert_eq!(
+ LineEnding::CarriageReturnLineFeed.as_str(),
+ "\r\n",
+ "should support turning a carriage return + line feed into a string"
+ );
+
+ assert_eq!(
+ "aaa".parse::<LineEnding>(),
+ Err("Expected CR, LF, or CRLF".into()),
+ "should error when parsing a non-eol"
+ );
+ }
+}
diff --git a/src/util/mdx.rs b/src/util/mdx.rs
new file mode 100644
index 0000000..712b2c7
--- /dev/null
+++ b/src/util/mdx.rs
@@ -0,0 +1,131 @@
+extern crate alloc;
+
+use alloc::string::String;
+
+/// Signal used as feedback when parsing MDX ESM/expressions.
+#[derive(Clone, Debug)]
+pub enum Signal {
+ /// A syntax error.
+ ///
+ /// `markdown-rs` will crash with error message `String`, and convert the
+ /// `usize` (byte offset into `&str` passed to `MdxExpressionParse` or
+ /// `MdxEsmParse`) to where it happened in the whole document.
+ ///
+ /// ## Examples
+ ///
+ /// ```rust ignore
+ /// Signal::Error("Unexpected `\"`, expected identifier".into(), 1)
+ /// ```
+ Error(String, usize),
+ /// An error at the end of the (partial?) expression.
+ ///
+ /// `markdown-rs` will either crash with error message `String` if it
+ /// doesn’t have any more text, or it will try again later when more text
+ /// is available.
+ ///
+ /// ## Examples
+ ///
+ /// ```rust ignore
+ /// Signal::Eof("Unexpected end of file in string literal".into())
+ /// ```
+ Eof(String),
+ /// Done, successfully.
+ ///
+ /// `markdown-rs` knows that this is the end of a valid expression/esm and
+ /// continues with markdown.
+ ///
+ /// ## Examples
+ ///
+ /// ```rust ignore
+ /// Signal::Ok
+ /// ```
+ Ok,
+}
+
+/// Signature of a function that parses MDX ESM.
+///
+/// Can be passed as `mdx_esm_parse` in [`ParseOptions`][] to support
+/// ESM according to a certain grammar (typically, a programming language).
+pub type EsmParse = dyn Fn(&str) -> Signal;
+
+/// Expression kind.
+#[derive(Clone, Debug)]
+pub enum ExpressionKind {
+ /// Kind of expressions in prose.
+ ///
+ /// ```mdx
+ /// > | # {Math.PI}
+ /// ^^^^^^^^^
+ /// |
+ /// > | {Math.PI}
+ /// ^^^^^^^^^
+ /// ```
+ Expression,
+ /// Kind of expressions as attributes.
+ ///
+ /// ```mdx
+ /// > | <a {...b}>
+ /// ^^^^^^
+ /// ```
+ AttributeExpression,
+ /// Kind of expressions as attribute values.
+ ///
+ /// ```mdx
+ /// > | <a b={c}>
+ /// ^^^
+ /// ```
+ AttributeValueExpression,
+}
+
+/// Signature of a function that parses MDX expressions.
+///
+/// Can be passed as `mdx_expression_parse` in [`ParseOptions`][] to support
+/// expressions according to a certain grammar (typically, a programming
+/// language).
+///
+pub type ExpressionParse = dyn Fn(&str, &ExpressionKind) -> Signal;
+
+#[cfg(test)]
+mod tests {
+ extern crate std;
+ use super::*;
+ use alloc::boxed::Box;
+
+ #[test]
+ fn test_mdx_expression_parse() {
+ fn func(_value: &str, _kind: &ExpressionKind) -> Signal {
+ Signal::Ok
+ }
+
+ let func_accepting = |_a: Box<ExpressionParse>| true;
+
+ assert!(
+ matches!(func("a", &ExpressionKind::Expression), Signal::Ok),
+ "should expose an `ExpressionParse` type (1)"
+ );
+
+ assert!(
+ func_accepting(Box::new(func)),
+ "should expose an `ExpressionParse` type (2)"
+ );
+ }
+
+ #[test]
+ fn test_mdx_esm_parse() {
+ fn func(_value: &str) -> Signal {
+ Signal::Ok
+ }
+
+ let func_accepting = |_a: Box<EsmParse>| true;
+
+ assert!(
+ matches!(func("a"), Signal::Ok),
+ "should expose an `EsmParse` type (1)"
+ );
+
+ assert!(
+ func_accepting(Box::new(func)),
+ "should expose an `EsmParse` type (2)"
+ );
+ }
+}
diff --git a/src/util/mod.rs b/src/util/mod.rs
index f44e183..cb9a40b 100644
--- a/src/util/mod.rs
+++ b/src/util/mod.rs
@@ -8,7 +8,9 @@ pub mod encode;
pub mod gfm_tagfilter;
pub mod identifier;
pub mod infer;
+pub mod line_ending;
pub mod location;
+pub mod mdx;
pub mod mdx_collect;
pub mod normalize_identifier;
pub mod sanitize_uri;