Skip to content

Commit

Permalink
Allow use of custom tags
Browse files Browse the repository at this point in the history
  • Loading branch information
kailan committed Dec 2, 2024
1 parent b9b6484 commit 3c1f3dc
Show file tree
Hide file tree
Showing 4 changed files with 29 additions and 22 deletions.
10 changes: 6 additions & 4 deletions esi/src/config.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use crate::parse::TagNames;

/// This struct is used to configure optional behaviour within the ESI processor.
///
/// ## Usage Example
Expand All @@ -8,16 +10,16 @@
#[allow(clippy::return_self_not_must_use)]
#[derive(Clone, Debug)]
pub struct Configuration {
/// The XML namespace to use when scanning for ESI tags. Defaults to `esi`.
pub namespace: String,
// Define the tag names that the processor will operate on.
pub tag_names: TagNames,
/// For working with non-HTML ESI templates, e.g. JSON files, this option allows you to disable the unescaping of URLs
pub is_escaped_content: bool,
}

impl Default for Configuration {
fn default() -> Self {
Self {
namespace: String::from("esi"),
tag_names: Default::default(),
is_escaped_content: true,
}
}
Expand All @@ -28,7 +30,7 @@ impl Configuration {
///
/// For example, setting this to `test` would cause the processor to only match tags like `<test:include>`.
pub fn with_namespace(mut self, namespace: impl Into<String>) -> Self {
self.namespace = namespace.into();
self.tag_names = TagNames::from_namespace_with_defaults(&namespace.into());
self
}
/// For working with non-HTML ESI templates, eg JSON files, allows to disable URLs unescaping
Expand Down
4 changes: 2 additions & 2 deletions esi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use std::io::{BufRead, Write};

pub use crate::document::{Element, Fragment};
pub use crate::error::Result;
pub use crate::parse::{parse_tags, Event, Include, Tag, Tag::Try};
pub use crate::parse::{parse_tags, Event, Include, Tag, Tag::Try, TagNames};

pub use crate::config::Configuration;
pub use crate::error::ExecutionError;
Expand Down Expand Up @@ -147,7 +147,7 @@ impl Processor {
// on each tag / event it finds in the document.
// The callback function `handle_events` will handle the event.
parse_tags(
&self.configuration.namespace,
&self.configuration.tag_names,
&mut src_document,
&mut |event| {
event_receiver(
Expand Down
19 changes: 12 additions & 7 deletions esi/src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,17 +43,18 @@ pub enum Event<'e> {
ESI(Tag<'e>),
}

// #[derive(Debug)]
struct TagNames {
#[derive(Clone, Debug)]
pub struct TagNames {
include: Vec<u8>,
comment: Vec<u8>,
remove: Vec<u8>,
r#try: Vec<u8>,
attempt: Vec<u8>,
except: Vec<u8>,
}

impl TagNames {
fn init(namespace: &str) -> Self {
pub fn from_namespace_with_defaults(namespace: &str) -> Self {
Self {
include: format!("{namespace}:include",).into_bytes(),
comment: format!("{namespace}:comment",).into_bytes(),
Expand All @@ -65,6 +66,12 @@ impl TagNames {
}
}

impl Default for TagNames {
fn default() -> Self {
Self::from_namespace_with_defaults("esi")
}
}

fn do_parse<'a, R>(
reader: &mut Reader<R>,
callback: &mut dyn FnMut(Event<'a>) -> Result<()>,
Expand Down Expand Up @@ -185,7 +192,7 @@ where

/// Parses the ESI document from the given `reader` and calls the `callback` closure upon each successfully parsed ESI tag.
pub fn parse_tags<'a, R>(
namespace: &str,
tag_names: &TagNames,
reader: &mut Reader<R>,
callback: &mut dyn FnMut(Event<'a>) -> Result<()>,
) -> Result<()>
Expand All @@ -194,8 +201,6 @@ where
{
debug!("Parsing document...");

// Initialize the ESI tags
let tags = TagNames::init(namespace);
// set the initial depth of nested tags
let mut depth = 0;
let mut root = Vec::new();
Expand All @@ -208,7 +213,7 @@ where
&mut root,
&mut depth,
&mut current_arm,
&tags,
tag_names,
)?;
debug!("Root: {:?}", root);

Expand Down
18 changes: 9 additions & 9 deletions esi/tests/parse.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use esi::{parse_tags, Event, ExecutionError, Tag};
use esi::{parse_tags, Event, ExecutionError, Tag, TagNames};
use quick_xml::Reader;

use std::sync::Once;
Expand All @@ -17,7 +17,7 @@ fn parse_basic_include() -> Result<(), ExecutionError> {
let input = "<html><body><esi:include src=\"https://example.com/hello\"/></body></html>";
let mut parsed = false;

parse_tags("esi", &mut Reader::from_str(input), &mut |event| {
parse_tags(&Default::default(), &mut Reader::from_str(input), &mut |event| {
if let Event::ESI(Tag::Include {
src,
alt,
Expand All @@ -44,7 +44,7 @@ fn parse_advanced_include_with_namespace() -> Result<(), ExecutionError> {
let input = "<app:include src=\"abc\" alt=\"def\" onerror=\"continue\"/>";
let mut parsed = false;

parse_tags("app", &mut Reader::from_str(input), &mut |event| {
parse_tags(&TagNames::from_namespace_with_defaults("app"), &mut Reader::from_str(input), &mut |event| {
if let Event::ESI(Tag::Include {
src,
alt,
Expand All @@ -71,7 +71,7 @@ fn parse_open_include() -> Result<(), ExecutionError> {
let input = "<esi:include src=\"abc\" alt=\"def\" onerror=\"continue\"></esi:include>";
let mut parsed = false;

parse_tags("esi", &mut Reader::from_str(input), &mut |event| {
parse_tags(&Default::default(), &mut Reader::from_str(input), &mut |event| {
if let Event::ESI(Tag::Include {
src,
alt,
Expand All @@ -97,7 +97,7 @@ fn parse_invalid_include() -> Result<(), ExecutionError> {

let input = "<esi:include/>";

let res = parse_tags("esi", &mut Reader::from_str(input), &mut |_| Ok(()));
let res = parse_tags(&Default::default(), &mut Reader::from_str(input), &mut |_| Ok(()));

assert!(matches!(
res,
Expand All @@ -114,7 +114,7 @@ fn parse_basic_include_with_onerror() -> Result<(), ExecutionError> {
let input = "<esi:include src=\"/_fragments/content.html\" onerror=\"continue\"/>";
let mut parsed = false;

parse_tags("esi", &mut Reader::from_str(input), &mut |event| {
parse_tags(&Default::default(), &mut Reader::from_str(input), &mut |event| {
if let Event::ESI(Tag::Include {
src,
alt,
Expand Down Expand Up @@ -142,7 +142,7 @@ fn parse_try_accept_only_include() -> Result<(), ExecutionError> {
let input = "<esi:try><esi:attempt><esi:include src=\"abc\" alt=\"def\" onerror=\"continue\"/></esi:attempt></esi:try>";
let mut parsed = false;

parse_tags("esi", &mut Reader::from_str(input), &mut |event| {
parse_tags(&Default::default(), &mut Reader::from_str(input), &mut |event| {
if let Event::ESI(Tag::Include {
src,
alt,
Expand Down Expand Up @@ -181,7 +181,7 @@ fn parse_try_accept_except_include() -> Result<(), ExecutionError> {
let mut accept_include_parsed = false;
let mut except_include_parsed = false;

parse_tags("esi", &mut Reader::from_str(input), &mut |event| {
parse_tags(&Default::default(), &mut Reader::from_str(input), &mut |event| {
println!("Event - {event:?}");
if let Event::ESI(Tag::Include {
ref src,
Expand Down Expand Up @@ -266,7 +266,7 @@ fn parse_try_nested() -> Result<(), ExecutionError> {
let mut accept_include_parsed_level2 = false;
let mut except_include_parsed_level2 = false;

parse_tags("esi", &mut Reader::from_str(input), &mut |event| {
parse_tags(&Default::default(), &mut Reader::from_str(input), &mut |event| {
assert_eq!(
format!("{event:?}"),
r#"ESI(Try { attempt_events: [XML(Text(BytesText { content: Owned("0xA ") })), ESI(Include { src: "/abc", alt: None, continue_on_error: false }), XML(Text(BytesText { content: Owned("0xA ") })), XML(Text(BytesText { content: Owned("0xA ") })), XML(Text(BytesText { content: Owned("0xA ") })), XML(Text(BytesText { content: Owned("0xA ") })), ESI(Try { attempt_events: [XML(Text(BytesText { content: Owned("0xA ") })), ESI(Include { src: "/foo", alt: None, continue_on_error: false }), XML(Text(BytesText { content: Owned("0xA ") }))], except_events: [XML(Text(BytesText { content: Owned("0xA ") })), ESI(Include { src: "/bar", alt: None, continue_on_error: false }), XML(Text(BytesText { content: Owned("0xA ") }))] }), XML(Text(BytesText { content: Owned("0xA ") }))], except_events: [XML(Text(BytesText { content: Owned("0xA ") })), ESI(Include { src: "/xyz", alt: None, continue_on_error: false }), XML(Text(BytesText { content: Owned("0xA ") })), XML(Empty(BytesStart { buf: Owned("a href=\"/efg\""), name_len: 1 })), XML(Text(BytesText { content: Owned("0xA just text0xA ") }))] })"#
Expand Down

0 comments on commit 3c1f3dc

Please sign in to comment.