feat(xml): Add xml crates (#5329)

This commit is contained in:
Alexander Akait 2022-08-01 06:56:12 +03:00 committed by GitHub
parent c984cfa3b9
commit 83e502367b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
98 changed files with 16622 additions and 0 deletions

View File

@ -281,6 +281,22 @@ jobs:
os: ubuntu-latest
- crate: swc_html_visit
os: ubuntu-latest
- crate: swc_xml
os: ubuntu-latest
- crate: swc_xml_ast
os: ubuntu-latest
- crate: swc_xml_codegen
os: ubuntu-latest
- crate: swc_xml_codegen
os: windows-latest
- crate: swc_xml_codegen_macros
os: ubuntu-latest
- crate: swc_xml_parser
os: ubuntu-latest
- crate: swc_xml_parser
os: windows-latest
- crate: swc_xml_visit
os: ubuntu-latest
- crate: swc_macros_common
os: ubuntu-latest
- crate: swc_node_base

74
Cargo.lock generated
View File

@ -4214,6 +4214,80 @@ dependencies = [
"syn",
]
[[package]]
name = "swc_xml"
version = "0.1.0"
dependencies = [
"swc_xml_ast",
"swc_xml_codegen",
"swc_xml_parser",
"swc_xml_visit",
]
[[package]]
name = "swc_xml_ast"
version = "0.1.0"
dependencies = [
"is-macro",
"serde",
"string_enum",
"swc_atoms",
"swc_common",
]
[[package]]
name = "swc_xml_codegen"
version = "0.1.0"
dependencies = [
"auto_impl",
"bitflags",
"rustc-hash",
"swc_atoms",
"swc_common",
"swc_xml_ast",
"swc_xml_codegen_macros",
"swc_xml_parser",
"swc_xml_visit",
"testing",
]
[[package]]
name = "swc_xml_codegen_macros"
version = "0.1.0"
dependencies = [
"pmutil",
"proc-macro2",
"quote",
"swc_macros_common",
"syn",
]
[[package]]
name = "swc_xml_parser"
version = "0.1.0"
dependencies = [
"criterion",
"serde",
"serde_json",
"swc_atoms",
"swc_common",
"swc_node_base",
"swc_xml_ast",
"swc_xml_visit",
"testing",
]
[[package]]
name = "swc_xml_visit"
version = "0.1.0"
dependencies = [
"serde",
"swc_atoms",
"swc_common",
"swc_visit",
"swc_xml_ast",
]
[[package]]
name = "syn"
version = "1.0.92"

View File

@ -19,6 +19,7 @@ members = [
"crates/swc_plugin_testing",
"crates/swc_plugin_proxy",
"crates/swc_timer",
"crates/swc_xml",
]
[profile.release]

22
crates/swc_xml/Cargo.toml Normal file
View File

@ -0,0 +1,22 @@
[package]
authors = ["강동윤 <kdy1997.dev@gmail.com>", "Alexander Akait <sheo13666q@gmail.com>"]
description = "XML apis for rust"
documentation = "https://rustdoc.swc.rs/swc_xml/"
edition = "2021"
license = "Apache-2.0"
name = "swc_xml"
repository = "https://github.com/swc-project/swc.git"
version = "0.1.0"
[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]
[lib]
bench = false
[dependencies]
swc_xml_ast = {version = "0.1.0", path = "../swc_xml_ast"}
swc_xml_codegen = {version = "0.1.0", path = "../swc_xml_codegen"}
swc_xml_parser = {version = "0.1.0", path = "../swc_xml_parser"}
swc_xml_visit = {version = "0.1.0", path = "../swc_xml_visit"}

View File

@ -0,0 +1,4 @@
pub extern crate swc_xml_ast as ast;
pub extern crate swc_xml_codegen as codegen;
pub extern crate swc_xml_parser as parser;
pub extern crate swc_xml_visit as visit;

View File

@ -0,0 +1,19 @@
[package]
authors = ["강동윤 <kdy1997.dev@gmail.com>", "Alexander Akait <sheo13666q@gmail.com>"]
description = "AST definitions of xml"
documentation = "https://rustdoc.swc.rs/swc_xml_ast/"
edition = "2021"
license = "Apache-2.0"
name = "swc_xml_ast"
repository = "https://github.com/swc-project/swc.git"
version = "0.1.0"
[lib]
bench = false
[dependencies]
is-macro = "0.2.0"
serde = {version = "1.0.127", features = ["derive"]}
string_enum = {version = "0.3.1", path = "../string_enum/"}
swc_atoms = {version = "0.3.0", path = "../swc_atoms"}
swc_common = { version = "0.26.0", path = "../swc_common"}

View File

@ -0,0 +1,107 @@
use is_macro::Is;
use string_enum::StringEnum;
use swc_atoms::JsWord;
use swc_common::{ast_node, EqIgnoreSpan, Span};
#[ast_node("Document")]
#[derive(Eq, Hash, EqIgnoreSpan)]
pub struct Document {
pub span: Span,
pub children: Vec<Child>,
}
#[derive(StringEnum, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash, EqIgnoreSpan)]
pub enum DocumentMode {
/// `no-quirks`
NoQuirks,
/// `limited-quirks`
LimitedQuirks,
/// `quirks`
Quirks,
}
#[ast_node]
#[derive(Eq, Hash, Is, EqIgnoreSpan)]
pub enum Child {
#[tag("DocumentType")]
DocumentType(DocumentType),
#[tag("Element")]
Element(Element),
#[tag("Text")]
Text(Text),
#[tag("Comment")]
Comment(Comment),
#[tag("ProcessingInstruction")]
ProcessingInstruction(ProcessingInstruction),
}
#[ast_node("DocumentType")]
#[derive(Eq, Hash, EqIgnoreSpan)]
pub struct DocumentType {
pub span: Span,
pub name: Option<JsWord>,
pub public_id: Option<JsWord>,
pub system_id: Option<JsWord>,
pub raw: Option<JsWord>,
}
#[derive(StringEnum, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash, EqIgnoreSpan)]
pub enum Namespace {
/// `http://www.w3.org/1999/xhtml`
HTML,
/// `http://www.w3.org/1998/Math/MathML`
MATHML,
/// `http://www.w3.org/2000/svg`
SVG,
/// `http://www.w3.org/1999/xlink`
XLINK,
/// `http://www.w3.org/XML/1998/namespace`
XML,
/// `http://www.w3.org/2000/xmlns/`
XMLNS,
}
#[ast_node("Element")]
#[derive(Eq, Hash, EqIgnoreSpan)]
pub struct Element {
pub span: Span,
pub tag_name: JsWord,
pub attributes: Vec<Attribute>,
pub children: Vec<Child>,
}
#[ast_node("Attribute")]
#[derive(Eq, Hash, EqIgnoreSpan)]
pub struct Attribute {
pub span: Span,
pub namespace: Option<Namespace>,
pub prefix: Option<JsWord>,
pub name: JsWord,
pub raw_name: Option<JsWord>,
pub value: Option<JsWord>,
pub raw_value: Option<JsWord>,
}
#[ast_node("Text")]
#[derive(Eq, Hash, EqIgnoreSpan)]
pub struct Text {
pub span: Span,
pub data: JsWord,
pub raw: Option<JsWord>,
}
#[ast_node("ProcessingInstruction")]
#[derive(Eq, Hash, EqIgnoreSpan)]
pub struct ProcessingInstruction {
pub span: Span,
pub target: JsWord,
pub data: JsWord,
}
#[ast_node("Comment")]
#[derive(Eq, Hash, EqIgnoreSpan)]
pub struct Comment {
pub span: Span,
pub data: JsWord,
pub raw: Option<JsWord>,
}

View File

@ -0,0 +1,8 @@
#![deny(clippy::all)]
#![allow(clippy::large_enum_variant)]
//! AST definitions for XML.
pub use self::{base::*, token::*};
mod base;
mod token;

View File

@ -0,0 +1,64 @@
use serde::{Deserialize, Serialize};
use swc_atoms::JsWord;
use swc_common::{ast_node, EqIgnoreSpan, Span};
#[ast_node("TokenAndSpan")]
#[derive(Eq, Hash, EqIgnoreSpan)]
pub struct TokenAndSpan {
pub span: Span,
pub token: Token,
}
#[derive(
Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, EqIgnoreSpan,
)]
pub struct AttributeToken {
pub span: Span,
pub name: JsWord,
pub raw_name: Option<JsWord>,
pub value: Option<JsWord>,
pub raw_value: Option<JsWord>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, EqIgnoreSpan)]
pub enum Token {
Doctype {
// Name
name: Option<JsWord>,
// Public identifier
public_id: Option<JsWord>,
// System identifier
system_id: Option<JsWord>,
// Raw value
raw: Option<JsWord>,
},
StartTag {
tag_name: JsWord,
attributes: Vec<AttributeToken>,
},
EndTag {
tag_name: JsWord,
attributes: Vec<AttributeToken>,
},
ShortTag {
tag_name: JsWord,
attributes: Vec<AttributeToken>,
},
EmptyTag {
tag_name: JsWord,
attributes: Vec<AttributeToken>,
},
Comment {
data: JsWord,
raw: JsWord,
},
Character {
value: char,
raw: Option<JsWord>,
},
ProcessingInstruction {
target: JsWord,
data: JsWord,
},
Eof,
}

View File

@ -0,0 +1,33 @@
[package]
authors = [
"강동윤 <kdy1997.dev@gmail.com>",
"Alexander Akait <sheo13666q@gmail.com>",
]
description = "XML code generator for the swc project"
documentation = "https://rustdoc.swc.rs/swc_xml_codegen/"
edition = "2021"
include = ["Cargo.toml", "src/**/*.rs"]
license = "Apache-2.0"
name = "swc_xml_codegen"
repository = "https://github.com/swc-project/swc.git"
version = "0.1.0"
[lib]
bench = false
[dependencies]
auto_impl = "0.5.0"
bitflags = "1.3.2"
rustc-hash = "1.1.0"
swc_atoms = { version = "0.3.0", path = "../swc_atoms" }
swc_common = { version = "0.26.0", path = "../swc_common" }
swc_xml_ast = { version = "0.1.0", path = "../swc_xml_ast" }
swc_xml_codegen_macros = { version = "0.1.0", path = "../swc_xml_codegen_macros" }
[dev-dependencies]
swc_common = { version = "0.26.0", path = "../swc_common", features = [
"sourcemap",
] }
swc_xml_parser = { version = "0.1.0", path = "../swc_xml_parser" }
swc_xml_visit = { version = "0.1.0", path = "../swc_xml_visit" }
testing = { version = "0.28.0", path = "../testing" }

View File

@ -0,0 +1,50 @@
use std::ops::{Deref, DerefMut};
use crate::{writer::XmlWriter, CodeGenerator};
impl<'b, W> CodeGenerator<'b, W>
where
W: XmlWriter,
{
/// Original context is restored when returned guard is dropped.
#[inline]
pub(super) fn with_ctx(&mut self, ctx: Ctx) -> WithCtx<'_, 'b, W> {
let orig_ctx = self.ctx;
self.ctx = ctx;
WithCtx {
orig_ctx,
inner: self,
}
}
}
#[derive(Debug, Default, Clone, Copy)]
pub(crate) struct Ctx {
pub need_escape_text: bool,
}
pub(super) struct WithCtx<'w, 'a, I: 'w + XmlWriter> {
inner: &'w mut CodeGenerator<'a, I>,
orig_ctx: Ctx,
}
impl<'w, I: XmlWriter> Deref for WithCtx<'_, 'w, I> {
type Target = CodeGenerator<'w, I>;
fn deref(&self) -> &CodeGenerator<'w, I> {
self.inner
}
}
impl<'w, I: XmlWriter> DerefMut for WithCtx<'_, 'w, I> {
fn deref_mut(&mut self) -> &mut CodeGenerator<'w, I> {
self.inner
}
}
impl<'w, I: XmlWriter> Drop for WithCtx<'_, 'w, I> {
fn drop(&mut self) {
self.inner.ctx = self.orig_ctx;
}
}

View File

@ -0,0 +1,53 @@
use std::fmt::Result;
use swc_common::Spanned;
///
/// # Type parameters
///
/// ## `T`
///
/// The type of the ast node.
pub trait Emit<T>
where
T: Spanned,
{
fn emit(&mut self, node: &T) -> Result;
}
impl<T, E> Emit<&'_ T> for E
where
E: Emit<T>,
T: Spanned,
{
#[allow(clippy::only_used_in_recursion)]
#[inline]
fn emit(&mut self, node: &&'_ T) -> Result {
self.emit(&**node)
}
}
impl<T, E> Emit<Box<T>> for E
where
E: Emit<T>,
T: Spanned,
{
#[inline]
fn emit(&mut self, node: &Box<T>) -> Result {
self.emit(&**node)
}
}
impl<T, E> Emit<Option<T>> for E
where
E: Emit<T>,
T: Spanned,
{
#[inline]
fn emit(&mut self, node: &Option<T>) -> Result {
match node {
Some(node) => self.emit(node),
None => Ok(()),
}
}
}

View File

@ -0,0 +1,467 @@
#![deny(clippy::all)]
#![allow(clippy::needless_update)]
pub use std::fmt::Result;
use std::{iter::Peekable, str::Chars};
use swc_common::Spanned;
use swc_xml_ast::*;
use swc_xml_codegen_macros::emitter;
use writer::XmlWriter;
pub use self::emit::*;
use self::{ctx::Ctx, list::ListFormat};
#[macro_use]
mod macros;
mod ctx;
mod emit;
mod list;
pub mod writer;
#[derive(Debug, Clone, Default)]
pub struct CodegenConfig<'a> {
pub minify: bool,
pub scripting_enabled: bool,
/// Should be used only for `DocumentFragment` code generation
pub context_element: Option<&'a Element>,
}
#[derive(Debug)]
pub struct CodeGenerator<'a, W>
where
W: XmlWriter,
{
wr: W,
config: CodegenConfig<'a>,
ctx: Ctx,
}
impl<'a, W> CodeGenerator<'a, W>
where
W: XmlWriter,
{
pub fn new(wr: W, config: CodegenConfig<'a>) -> Self {
CodeGenerator {
wr,
config,
ctx: Default::default(),
}
}
#[emitter]
fn emit_document(&mut self, n: &Document) -> Result {
self.emit_list(&n.children, ListFormat::NotDelimited)?;
}
#[emitter]
fn emit_child(&mut self, n: &Child) -> Result {
match n {
Child::DocumentType(n) => emit!(self, n),
Child::Element(n) => emit!(self, n),
Child::Text(n) => emit!(self, n),
Child::Comment(n) => emit!(self, n),
Child::ProcessingInstruction(n) => emit!(self, n),
}
}
#[emitter]
fn emit_document_doctype(&mut self, n: &DocumentType) -> Result {
let mut doctype = String::with_capacity(
10 + if let Some(name) = &n.name {
name.len() + 1
} else {
0
} + if let Some(public_id) = &n.public_id {
let mut len = public_id.len() + 10;
if let Some(system_id) = &n.system_id {
len += system_id.len() + 3
}
len
} else if let Some(system_id) = &n.system_id {
system_id.len() + 10
} else {
0
},
);
doctype.push('<');
doctype.push('!');
if self.config.minify {
doctype.push_str("doctype");
} else {
doctype.push_str("DOCTYPE");
}
if let Some(name) = &n.name {
doctype.push(' ');
doctype.push_str(name);
}
if let Some(public_id) = &n.public_id {
doctype.push(' ');
if self.config.minify {
doctype.push_str("public");
} else {
doctype.push_str("PUBLIC");
}
doctype.push(' ');
let public_id_quote = if public_id.contains('"') { '\'' } else { '"' };
doctype.push(public_id_quote);
doctype.push_str(public_id);
doctype.push(public_id_quote);
if let Some(system_id) = &n.system_id {
doctype.push(' ');
let system_id_quote = if system_id.contains('"') { '\'' } else { '"' };
doctype.push(system_id_quote);
doctype.push_str(system_id);
doctype.push(system_id_quote);
}
} else if let Some(system_id) = &n.system_id {
doctype.push(' ');
if self.config.minify {
doctype.push_str("system");
} else {
doctype.push_str("SYSTEM");
}
doctype.push(' ');
let system_id_quote = if system_id.contains('"') { '\'' } else { '"' };
doctype.push(system_id_quote);
doctype.push_str(system_id);
doctype.push(system_id_quote);
}
doctype.push('>');
write_raw!(self, n.span, &doctype);
formatting_newline!(self);
}
fn basic_emit_element(&mut self, n: &Element) -> Result {
let has_attributes = !n.attributes.is_empty();
let is_void_element = n.children.is_empty();
write_raw!(self, "<");
write_raw!(self, &n.tag_name);
if has_attributes {
space!(self);
self.emit_list(&n.attributes, ListFormat::SpaceDelimited)?;
}
if is_void_element {
if self.config.minify {
let need_space = match n.attributes.last() {
Some(Attribute {
value: Some(value), ..
}) => !value.chars().any(|c| match c {
c if c.is_ascii_whitespace() => true,
'`' | '=' | '<' | '>' | '"' | '\'' => true,
_ => false,
}),
_ => false,
};
if need_space {
write_raw!(self, " ");
}
} else {
write_raw!(self, " ");
}
write_raw!(self, "/");
}
write_raw!(self, ">");
if is_void_element {
return Ok(());
}
if !n.children.is_empty() {
let ctx = self.create_context_for_element(n);
self.with_ctx(ctx)
.emit_list(&n.children, ListFormat::NotDelimited)?;
}
write_raw!(self, "<");
write_raw!(self, "/");
write_raw!(self, &n.tag_name);
write_raw!(self, ">");
Ok(())
}
#[emitter]
fn emit_element(&mut self, n: &Element) -> Result {
self.basic_emit_element(n)?;
}
#[emitter]
fn emit_attribute(&mut self, n: &Attribute) -> Result {
let mut attribute = String::with_capacity(
if let Some(prefix) = &n.prefix {
prefix.len() + 1
} else {
0
} + n.name.len()
+ if let Some(value) = &n.value {
value.len() + 1
} else {
0
},
);
if let Some(prefix) = &n.prefix {
attribute.push_str(prefix);
attribute.push(':');
}
attribute.push_str(&n.name);
if let Some(value) = &n.value {
attribute.push('=');
let normalized = normalize_attribute_value(value);
attribute.push_str(&normalized);
}
write_multiline_raw!(self, n.span, &attribute);
}
#[emitter]
fn emit_text(&mut self, n: &Text) -> Result {
if self.ctx.need_escape_text {
let mut data = String::with_capacity(n.data.len());
if self.config.minify {
data.push_str(&minify_text(&n.data));
} else {
data.push_str(&escape_string(&n.data, false));
}
write_multiline_raw!(self, n.span, &data);
} else {
write_multiline_raw!(self, n.span, &n.data);
}
}
#[emitter]
fn emit_comment(&mut self, n: &Comment) -> Result {
let mut comment = String::with_capacity(n.data.len() + 7);
comment.push_str("<!--");
comment.push_str(&n.data);
comment.push_str("-->");
write_multiline_raw!(self, n.span, &comment);
}
#[emitter]
fn emit_processing_instruction(&mut self, n: &ProcessingInstruction) -> Result {
let mut processing_instruction = String::with_capacity(n.target.len() + n.data.len() + 5);
processing_instruction.push_str("<?");
processing_instruction.push_str(&n.target);
processing_instruction.push(' ');
processing_instruction.push_str(&n.data);
processing_instruction.push_str("?>");
write_multiline_raw!(self, n.span, &processing_instruction);
// TODO only for top instructions
newline!(self);
}
fn create_context_for_element(&self, n: &Element) -> Ctx {
let need_escape_text = match &*n.tag_name {
"noscript" => !self.config.scripting_enabled,
_ => true,
};
Ctx {
need_escape_text,
..self.ctx
}
}
fn emit_list<N>(&mut self, nodes: &[N], format: ListFormat) -> Result
where
Self: Emit<N>,
N: Spanned,
{
for (idx, node) in nodes.iter().enumerate() {
if idx != 0 {
self.write_delim(format)?;
if format & ListFormat::LinesMask == ListFormat::MultiLine {
formatting_newline!(self);
}
}
emit!(self, node)
}
Ok(())
}
fn write_delim(&mut self, f: ListFormat) -> Result {
match f & ListFormat::DelimitersMask {
ListFormat::None => {}
ListFormat::SpaceDelimited => {
space!(self)
}
_ => unreachable!(),
}
Ok(())
}
}
fn normalize_attribute_value(value: &str) -> String {
if value.is_empty() {
return "\"\"".to_string();
}
let mut normalized = String::with_capacity(value.len() + 2);
normalized.push('"');
normalized.push_str(value);
normalized.push('"');
normalized
}
fn minify_text(value: &str) -> String {
let mut result = String::with_capacity(value.len());
let mut chars = value.chars().peekable();
while let Some(c) = chars.next() {
match c {
'&' => {
result.push_str(&minify_amp(&mut chars));
}
'<' => {
result.push_str("&lt;");
}
_ => result.push(c),
}
}
result
}
fn minify_amp(chars: &mut Peekable<Chars>) -> String {
let mut result = String::with_capacity(7);
match chars.next() {
Some(hash @ '#') => {
match chars.next() {
// HTML CODE
// Prevent `&amp;#38;` -> `&#38`
Some(number @ '0'..='9') => {
result.push_str("&amp;");
result.push(hash);
result.push(number);
}
Some(x @ 'x' | x @ 'X') => {
match chars.peek() {
// HEX CODE
// Prevent `&amp;#x38;` -> `&#x38`
Some(c) if c.is_ascii_hexdigit() => {
result.push_str("&amp;");
result.push(hash);
result.push(x);
}
_ => {
result.push('&');
result.push(hash);
result.push(x);
}
}
}
any => {
result.push('&');
result.push(hash);
if let Some(any) = any {
result.push(any);
}
}
}
}
// Named entity
// Prevent `&amp;current` -> `&current`
Some(c @ 'a'..='z') | Some(c @ 'A'..='Z') => {
let mut entity_temporary_buffer = String::with_capacity(33);
entity_temporary_buffer.push('&');
entity_temporary_buffer.push(c);
result.push('&');
result.push_str(&entity_temporary_buffer[1..]);
}
any => {
result.push('&');
if let Some(any) = any {
result.push(any);
}
}
}
result
}
// Escaping a string (for the purposes of the algorithm above) consists of
// running the following steps:
//
// 1. Replace any occurrence of the "&" character by the string "&amp;".
//
// 2. Replace any occurrences of the U+00A0 NO-BREAK SPACE character by the
// string "&nbsp;".
//
// 3. If the algorithm was invoked in the attribute mode, replace any
// occurrences of the """ character by the string "&quot;".
//
// 4. If the algorithm was not invoked in the attribute mode, replace any
// occurrences of the "<" character by the string "&lt;", and any occurrences of
// the ">" character by the string "&gt;".
fn escape_string(value: &str, is_attribute_mode: bool) -> String {
let mut result = String::with_capacity(value.len());
for c in value.chars() {
match c {
'&' => {
result.push_str("&amp;");
}
'\u{00A0}' => result.push_str("&nbsp;"),
'"' if is_attribute_mode => result.push_str("&quot;"),
'<' if !is_attribute_mode => {
result.push_str("&lt;");
}
'>' if !is_attribute_mode => {
result.push_str("&gt;");
}
_ => result.push(c),
}
}
result
}

View File

@ -0,0 +1,31 @@
#![allow(non_upper_case_globals)]
use bitflags::bitflags;
use swc_common::add_bitflags;
bitflags! {
pub struct ListFormat: u16 {
const None = 0;
}
}
add_bitflags!(
ListFormat,
// Handled by bitflags! macro.
// Values { None: 0 },
/// Line separators
Values {
/// Prints the list on a single line (default).
SingleLine: 0,
/// Prints the list on multiple lines.
MultiLine: 1 << 0,
/// Prints the list using line preservation if possible.
PreserveLines: 1 << 1,
LinesMask: SingleLine | MultiLine | PreserveLines,
},
/// Delimiters
Values {
NotDelimited: 0,
SpaceDelimited: 1 << 2,
DelimitersMask: SpaceDelimited,
},
);

View File

@ -0,0 +1,59 @@
macro_rules! emit {
($g:expr,$n:expr) => {{
use crate::Emit;
$g.emit(&$n)?;
}};
}
macro_rules! write_raw {
($g:expr,$span:expr,$n:expr) => {{
$g.wr.write_raw(Some($span), $n)?;
}};
($g:expr,$n:expr) => {{
$g.wr.write_raw(None, $n)?;
}};
}
macro_rules! write_multiline_raw {
($g:expr,$span:expr,$n:expr) => {{
$g.wr.write_multiline_raw($span, $n)?;
}};
}
macro_rules! newline {
($g:expr) => {{
$g.wr.write_newline()?;
}};
}
macro_rules! formatting_newline {
($g:expr) => {{
if !$g.config.minify {
$g.wr.write_newline()?;
}
}};
}
macro_rules! space {
($g:expr) => {{
$g.wr.write_space()?;
}};
}
// macro_rules! increase_indent {
// ($g:expr) => {{
// if !$g.config.minify {
// $g.wr.increase_indent();
// }
// }};
// }
//
// macro_rules! decrease_indent {
// ($g:expr) => {{
// if !$g.config.minify {
// $g.wr.decrease_indent();
// }
// }};
// }

View File

@ -0,0 +1,271 @@
use std::fmt::{Result, Write};
use rustc_hash::FxHashSet;
use swc_common::{BytePos, LineCol, Span};
use super::XmlWriter;
pub enum IndentType {
Tab,
Space,
}
impl Default for IndentType {
fn default() -> Self {
IndentType::Space
}
}
pub enum LineFeed {
LF,
CRLF,
}
impl Default for LineFeed {
fn default() -> Self {
LineFeed::LF
}
}
pub struct BasicXmlWriterConfig {
pub indent_type: IndentType,
pub indent_width: i32,
pub linefeed: LineFeed,
}
impl Default for BasicXmlWriterConfig {
fn default() -> Self {
BasicXmlWriterConfig {
indent_type: IndentType::default(),
indent_width: 2,
linefeed: LineFeed::default(),
}
}
}
pub struct BasicXmlWriter<'a, W>
where
W: Write,
{
line_start: bool,
line: usize,
col: usize,
indent_type: &'a str,
indent_level: usize,
linefeed: &'a str,
srcmap: Option<&'a mut Vec<(BytePos, LineCol)>>,
srcmap_done: FxHashSet<(BytePos, u32, u32)>,
/// Used to avoid including whitespaces created by indention.
pending_srcmap: Option<BytePos>,
config: BasicXmlWriterConfig,
w: W,
}
impl<'a, W> BasicXmlWriter<'a, W>
where
W: Write,
{
pub fn new(
writer: W,
srcmap: Option<&'a mut Vec<(BytePos, LineCol)>>,
config: BasicXmlWriterConfig,
) -> Self {
let indent_type = match config.indent_type {
IndentType::Tab => "\t",
IndentType::Space => " ",
};
let linefeed = match config.linefeed {
LineFeed::LF => "\n",
LineFeed::CRLF => "\r\n",
};
BasicXmlWriter {
line_start: true,
line: 0,
col: 0,
indent_type,
indent_level: 0,
linefeed,
config,
srcmap,
w: writer,
pending_srcmap: Default::default(),
srcmap_done: Default::default(),
}
}
fn write_indent_string(&mut self) -> Result {
for _ in 0..(self.config.indent_width * self.indent_level as i32) {
self.raw_write(self.indent_type)?;
}
Ok(())
}
fn raw_write(&mut self, data: &str) -> Result {
self.w.write_str(data)?;
self.col += data.chars().count();
Ok(())
}
fn write(&mut self, span: Option<Span>, data: &str) -> Result {
if !data.is_empty() {
if self.line_start {
self.write_indent_string()?;
self.line_start = false;
if let Some(pending) = self.pending_srcmap.take() {
self.srcmap(pending);
}
}
if let Some(span) = span {
if !span.is_dummy() {
self.srcmap(span.lo())
}
}
self.raw_write(data)?;
if let Some(span) = span {
if !span.is_dummy() {
self.srcmap(span.hi())
}
}
}
Ok(())
}
fn srcmap(&mut self, byte_pos: BytePos) {
if byte_pos.is_dummy() {
return;
}
if let Some(ref mut srcmap) = self.srcmap {
if self
.srcmap_done
.insert((byte_pos, self.line as _, self.col as _))
{
let loc = LineCol {
line: self.line as _,
col: self.col as _,
};
srcmap.push((byte_pos, loc));
}
}
}
}
impl<W> XmlWriter for BasicXmlWriter<'_, W>
where
W: Write,
{
fn write_space(&mut self) -> Result {
self.write_raw(None, " ")
}
fn write_newline(&mut self) -> Result {
let pending = self.pending_srcmap.take();
if !self.line_start {
self.raw_write(self.linefeed)?;
self.line += 1;
self.col = 0;
self.line_start = true;
if let Some(pending) = pending {
self.srcmap(pending)
}
}
Ok(())
}
fn write_raw(&mut self, span: Option<Span>, text: &str) -> Result {
debug_assert!(
!text.contains('\n'),
"write_raw should not contains new lines, got '{}'",
text,
);
self.write(span, text)?;
Ok(())
}
fn write_multiline_raw(&mut self, span: Span, s: &str) -> Result {
if !s.is_empty() {
if !span.is_dummy() {
self.srcmap(span.lo())
}
self.write(None, s)?;
let line_start_of_s = compute_line_starts(s);
if line_start_of_s.len() > 1 {
self.line = self.line + line_start_of_s.len() - 1;
let last_line_byte_index = line_start_of_s.last().cloned().unwrap_or(0);
self.col = s[last_line_byte_index..].chars().count();
}
if !span.is_dummy() {
self.srcmap(span.hi())
}
}
Ok(())
}
fn increase_indent(&mut self) {
self.indent_level += 1;
}
fn decrease_indent(&mut self) {
debug_assert!(
(self.indent_level as i32) >= 0,
"indent should zero or greater than zero",
);
self.indent_level -= 1;
}
}
fn compute_line_starts(s: &str) -> Vec<usize> {
let mut res = vec![];
let mut line_start = 0;
let mut chars = s.char_indices().peekable();
while let Some((pos, c)) = chars.next() {
match c {
'\r' => {
if let Some(&(_, '\n')) = chars.peek() {
let _ = chars.next();
}
}
'\n' => {
res.push(line_start);
line_start = pos + 1;
}
_ => {}
}
}
// Last line.
res.push(line_start);
res
}

View File

@ -0,0 +1,21 @@
use std::fmt::Result;
use auto_impl::auto_impl;
use swc_common::Span;
pub mod basic;
#[auto_impl(&mut, Box)]
pub trait XmlWriter {
fn write_space(&mut self) -> Result;
fn write_newline(&mut self) -> Result;
fn write_raw(&mut self, span: Option<Span>, text: &str) -> Result;
fn write_multiline_raw(&mut self, span: Span, s: &str) -> Result;
fn increase_indent(&mut self);
fn decrease_indent(&mut self);
}

View File

@ -0,0 +1,277 @@
#![allow(clippy::needless_update)]
use std::{
mem::take,
path::{Path, PathBuf},
};
use swc_common::{FileName, Span};
use swc_xml_ast::*;
use swc_xml_codegen::{
writer::basic::{BasicXmlWriter, BasicXmlWriterConfig, IndentType, LineFeed},
CodeGenerator, CodegenConfig, Emit,
};
use swc_xml_parser::{parse_file_as_document, parser::ParserConfig};
use swc_xml_visit::{VisitMut, VisitMutWith};
use testing::{assert_eq, run_test2, NormalizedOutput};
fn print_document(
input: &Path,
parser_config: Option<ParserConfig>,
writer_config: Option<BasicXmlWriterConfig>,
codegen_config: Option<CodegenConfig>,
) {
let dir = input.parent().unwrap();
let parser_config = match parser_config {
Some(parser_config) => parser_config,
_ => ParserConfig::default(),
};
let writer_config = match writer_config {
Some(writer_config) => writer_config,
_ => BasicXmlWriterConfig::default(),
};
let codegen_config = match codegen_config {
Some(codegen_config) => codegen_config,
_ => CodegenConfig::default(),
};
let output = if codegen_config.minify {
dir.join(format!(
"output.min.{}",
input.extension().unwrap().to_string_lossy()
))
} else {
dir.join(format!(
"output.{}",
input.extension().unwrap().to_string_lossy()
))
};
run_test2(false, |cm, handler| {
let fm = cm.load_file(input).unwrap();
let mut errors = vec![];
let mut document: Document =
parse_file_as_document(&fm, parser_config, &mut errors).unwrap();
for err in take(&mut errors) {
err.to_diagnostics(&handler).emit();
}
let mut xml_str = String::new();
let wr = BasicXmlWriter::new(&mut xml_str, None, writer_config);
let mut gen = CodeGenerator::new(wr, codegen_config);
gen.emit(&document).unwrap();
let fm_output = cm.load_file(&output).unwrap();
NormalizedOutput::new_raw(xml_str)
.compare_to_file(output)
.unwrap();
let mut errors = vec![];
let mut document_parsed_again =
parse_file_as_document(&fm_output, parser_config, &mut errors).map_err(|err| {
err.to_diagnostics(&handler).emit();
})?;
for error in take(&mut errors) {
error.to_diagnostics(&handler).emit();
}
document.visit_mut_with(&mut DropSpan);
document_parsed_again.visit_mut_with(&mut DropSpan);
assert_eq!(document, document_parsed_again);
Ok(())
})
.unwrap();
}
fn verify_document(
input: &Path,
parser_config: Option<ParserConfig>,
writer_config: Option<BasicXmlWriterConfig>,
codegen_config: Option<CodegenConfig>,
ignore_errors: bool,
) {
let parser_config = match parser_config {
Some(parser_config) => parser_config,
_ => ParserConfig::default(),
};
let writer_config = match writer_config {
Some(writer_config) => writer_config,
_ => BasicXmlWriterConfig::default(),
};
let codegen_config = match codegen_config {
Some(codegen_config) => codegen_config,
_ => CodegenConfig::default(),
};
testing::run_test2(false, |cm, handler| {
let fm = cm.load_file(input).unwrap();
let mut errors = vec![];
let mut document =
parse_file_as_document(&fm, parser_config, &mut errors).map_err(|err| {
err.to_diagnostics(&handler).emit();
})?;
if !ignore_errors {
for err in take(&mut errors) {
err.to_diagnostics(&handler).emit();
}
}
let mut xml_str = String::new();
let wr = BasicXmlWriter::new(&mut xml_str, None, writer_config);
let mut gen = CodeGenerator::new(wr, codegen_config);
gen.emit(&document).unwrap();
let new_fm = cm.new_source_file(FileName::Anon, xml_str);
let mut parsed_errors = vec![];
let mut document_parsed_again =
parse_file_as_document(&new_fm, parser_config, &mut parsed_errors).map_err(|err| {
err.to_diagnostics(&handler).emit();
})?;
if !ignore_errors {
for err in parsed_errors {
err.to_diagnostics(&handler).emit();
}
}
document.visit_mut_with(&mut DropSpan);
document_parsed_again.visit_mut_with(&mut DropSpan);
assert_eq!(document, document_parsed_again);
Ok(())
})
.unwrap();
}
struct DropSpan;
impl VisitMut for DropSpan {
fn visit_mut_document_type(&mut self, n: &mut DocumentType) {
n.visit_mut_children_with(self);
n.raw = None;
}
fn visit_mut_comment(&mut self, n: &mut Comment) {
n.visit_mut_children_with(self);
n.raw = None;
}
fn visit_mut_text(&mut self, n: &mut Text) {
n.visit_mut_children_with(self);
n.raw = None;
}
fn visit_mut_attribute(&mut self, n: &mut Attribute) {
n.visit_mut_children_with(self);
n.raw_name = None;
n.raw_value = None;
}
fn visit_mut_span(&mut self, n: &mut Span) {
*n = Default::default()
}
}
#[testing::fixture("tests/fixture/**/input.xml")]
fn test_document(input: PathBuf) {
print_document(
&input,
None,
None,
Some(CodegenConfig {
scripting_enabled: false,
minify: false,
..Default::default()
}),
);
print_document(
&input,
None,
None,
Some(CodegenConfig {
scripting_enabled: false,
minify: true,
..Default::default()
}),
);
}
#[testing::fixture("tests/options/indent_type/**/input.xml")]
fn test_indent_type_option(input: PathBuf) {
print_document(
&input,
None,
Some(BasicXmlWriterConfig {
indent_type: IndentType::Tab,
indent_width: 2,
linefeed: LineFeed::default(),
}),
None,
);
}
#[testing::fixture("../swc_xml_parser/tests/fixture/**/*.xml")]
fn parser_verify(input: PathBuf) {
verify_document(&input, None, None, None, false);
verify_document(
&input,
None,
None,
Some(CodegenConfig {
scripting_enabled: false,
minify: true,
..Default::default()
}),
false,
);
verify_document(
&input,
None,
None,
Some(CodegenConfig {
scripting_enabled: false,
minify: true,
..Default::default()
}),
false,
);
}
#[testing::fixture("../swc_xml_parser/tests/recovery/**/*.xml")]
fn parser_recovery_verify(input: PathBuf) {
verify_document(
&input,
None,
None,
Some(CodegenConfig {
scripting_enabled: false,
minify: true,
..Default::default()
}),
true,
);
verify_document(
&input,
None,
None,
Some(CodegenConfig {
scripting_enabled: false,
minify: true,
..Default::default()
}),
true,
);
}

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>

View File

@ -0,0 +1,9 @@
<root>
<z></z></><a/>
<!-- start tag and end tag -->
<start-tag>Start</start-tag>
<!-- short tag -->
<short-tag />
<!-- empty tag -->
</>
</root>

View File

@ -0,0 +1,9 @@
<root>
<z/><a/>
<!-- start tag and end tag -->
<start-tag>Start</start-tag>
<!-- short tag -->
<short-tag/>
<!-- empty tag -->
</root>

View File

@ -0,0 +1,9 @@
<root>
<z /><a />
<!-- start tag and end tag -->
<start-tag>Start</start-tag>
<!-- short tag -->
<short-tag />
<!-- empty tag -->
</root>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"><note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"><note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"><note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>

View File

@ -0,0 +1,20 @@
[package]
authors = ["강동윤 <kdy1997.dev@gmail.com>", "Alexander Akait <sheo13666q@gmail.com>"]
description = "Internal macro for the xml code generator"
documentation = "https://rustdoc.swc.rs/swc_xml_codegen_macros/"
edition = "2021"
license = "Apache-2.0"
name = "swc_xml_codegen_macros"
repository = "https://github.com/swc-project/swc.git"
version = "0.1.0"
[lib]
bench = false
proc-macro = true
[dependencies]
pmutil = "0.5.1"
proc-macro2 = "1"
quote = "1"
swc_macros_common = {version = "0.3.4", path = "../swc_macros_common"}
syn = {version = "1", features = ["fold"]}

View File

@ -0,0 +1,86 @@
#![deny(clippy::all)]
extern crate proc_macro;
use pmutil::{smart_quote, Quote, ToTokensExt};
use syn::{FnArg, ImplItemMethod, Type, TypeReference};
#[proc_macro_attribute]
pub fn emitter(
_attr: proc_macro::TokenStream,
item: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
let item: ImplItemMethod = syn::parse(item).expect("failed to parse input as an item");
let item = expand(item);
item.dump().into()
}
fn expand(i: ImplItemMethod) -> ImplItemMethod {
let mtd_name = i.sig.ident.clone();
assert!(
format!("{}", i.sig.ident).starts_with("emit_"),
"#[emitter] methods should start with `emit_`"
);
let block = {
let node_type = {
i.sig
.inputs
.clone()
.into_iter()
.nth(1)
.and_then(|arg| match arg {
FnArg::Typed(ty) => Some(ty.ty),
_ => None,
})
.map(|ty| {
// &Ident -> Ident
match *ty {
Type::Reference(TypeReference { elem, .. }) => *elem,
_ => panic!(
"Type of node parameter should be reference but got {}",
ty.dump()
),
}
})
.expect(
"#[emitter] methods should have signature of
fn (&mut self, node: Node) -> Result;
",
)
};
Quote::new_call_site()
.quote_with(smart_quote!(
Vars {
block: &i.block,
NodeType: &node_type,
mtd_name,
},
{
{
impl<W> crate::Emit<NodeType> for crate::CodeGenerator<'_, W>
where
W: crate::writer::XmlWriter,
{
fn emit(&mut self, n: &NodeType) -> crate::Result {
self.mtd_name(n)
}
}
block
// Emitter methods return Result<_, _>
// We inject this to avoid writing Ok(()) every time.
#[allow(unreachable_code)]
{
return Ok(());
}
}
}
))
.parse()
};
ImplItemMethod { block, ..i }
}

View File

@ -0,0 +1,32 @@
[package]
authors = [
"강동윤 <kdy1997.dev@gmail.com>",
"Alexander Akait <sheo13666q@gmail.com>",
]
description = "XML parser"
documentation = "https://rustdoc.swc.rs/swc_xml_parser/"
edition = "2021"
include = ["Cargo.toml", "src/**/*.rs", "src/**/*.json"]
license = "Apache-2.0"
name = "swc_xml_parser"
repository = "https://github.com/swc-project/swc.git"
version = "0.1.0"
[lib]
bench = false
[features]
debug = []
[dependencies]
swc_atoms = { version = "0.3.0", path = "../swc_atoms" }
swc_common = { version = "0.26.0", path = "../swc_common" }
swc_xml_ast = { version = "0.1.0", path = "../swc_xml_ast" }
[dev-dependencies]
criterion = "0.3"
serde = "1.0.127"
serde_json = "1.0.66"
swc_xml_visit = { version = "0.1.0", path = "../swc_xml_visit" }
swc_node_base = { version = "0.5.0", path = "../swc_node_base" }
testing = { version = "0.28.0", path = "../testing" }

View File

@ -0,0 +1,164 @@
use std::borrow::Cow;
use swc_common::{
errors::{DiagnosticBuilder, Handler},
Span,
};
/// Size is same as a size of a pointer.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Error {
inner: Box<(Span, ErrorKind)>,
}
impl Error {
pub fn kind(&self) -> &ErrorKind {
&self.inner.1
}
pub fn into_inner(self) -> Box<(Span, ErrorKind)> {
self.inner
}
pub fn new(span: Span, kind: ErrorKind) -> Self {
Error {
inner: Box::new((span, kind)),
}
}
pub fn message(&self) -> Cow<'static, str> {
match &self.inner.1 {
ErrorKind::Eof => "Unexpected end of file".into(),
// Lexer errors
ErrorKind::AbruptClosingOfEmptyComment => "Abrupt closing of empty comment".into(),
ErrorKind::AbruptDoctypePublicIdentifier => "Abrupt doctype public identifier".into(),
ErrorKind::AbruptDoctypeSystemIdentifier => "Abrupt doctype system identifier".into(),
ErrorKind::ControlCharacterInInputStream => "Control character in input stream".into(),
ErrorKind::EndTagWithAttributes => "End tag with attributes".into(),
ErrorKind::ShortTagWithAttributes => "Short tag with attributes".into(),
ErrorKind::DuplicateAttribute => "Duplicate attribute".into(),
ErrorKind::EndTagWithTrailingSolidus => "End tag with trailing solidus".into(),
ErrorKind::EofBeforeTagName => "Eof before tag name".into(),
ErrorKind::EofInCdata => "Eof in cdata".into(),
ErrorKind::EofInComment => "Eof in comment".into(),
ErrorKind::EofInDoctype => "Eof in doctype".into(),
ErrorKind::EofInTag => "Eof in tag".into(),
ErrorKind::EofInProcessingInstruction => "Eof in processing instruction".into(),
ErrorKind::IncorrectlyClosedComment => "Incorrectly closed comment".into(),
ErrorKind::IncorrectlyOpenedComment => "Incorrectly opened comment".into(),
ErrorKind::InvalidCharacterSequenceAfterDoctypeName => {
"Invalid character sequence after doctype name".into()
}
ErrorKind::InvalidFirstCharacterOfTagName => {
"Invalid first character of tag name".into()
}
ErrorKind::InvalidCharacterOfProcessingInstruction => {
"Invalid character of processing instruction".into()
}
ErrorKind::InvalidCharacterInTag => "Invalid character in tag".into(),
ErrorKind::MissingDoctypeName => "Missing doctype name".into(),
ErrorKind::MissingDoctypePublicIdentifier => "Missing doctype public identifier".into(),
ErrorKind::MissingQuoteBeforeDoctypePublicIdentifier => {
"Missing quote before doctype public identifier".into()
}
ErrorKind::MissingQuoteBeforeDoctypeSystemIdentifier => {
"Missing quote before doctype system identifier".into()
}
ErrorKind::MissingSemicolonAfterCharacterReference => {
"Missing semicolon after character reference".into()
}
ErrorKind::MissingWhitespaceAfterDoctypePublicKeyword => {
"Missing whitespace after doctype public keyword".into()
}
ErrorKind::MissingWhitespaceAfterDoctypeSystemKeyword => {
"Missing whitespace after doctype system keyword".into()
}
ErrorKind::MissingWhitespaceBeforeDoctypeName => {
"Missing whitespace before doctype name".into()
}
ErrorKind::MissingWhitespaceBetweenDoctypePublicAndSystemIdentifiers => {
"Missing whitespace between doctype public and system identifiers".into()
}
ErrorKind::NestedComment => "Nested comment".into(),
ErrorKind::NoncharacterInInputStream => "Noncharacter in input stream".into(),
ErrorKind::SurrogateInInputStream => "Surrogate in input stream".into(),
ErrorKind::SurrogateCharacterReference => "Surrogate character reference".into(),
ErrorKind::UnexpectedCharacterAfterDoctypeSystemIdentifier => {
"Unexpected character after doctype system identifier".into()
}
ErrorKind::UnexpectedColonBeforeAttributeName => {
"Unexpected colon before attribute name".into()
}
ErrorKind::UnexpectedSolidusInTag => "Unexpected solidus in tag".into(),
// Parser errors
ErrorKind::UnexpectedTokenInStartPhase => "Unexpected token in start phase".into(),
ErrorKind::UnexpectedTokenInMainPhase => "Unexpected token in main phase".into(),
ErrorKind::UnexpectedTokenInEndPhase => "Unexpected token in end phase".into(),
ErrorKind::UnexpectedEofInStartPhase => "Unexpected end of file in start phase".into(),
ErrorKind::UnexpectedEofInMainPhase => "Unexpected end of file in main phase".into(),
ErrorKind::OpeningAndEndingTagMismatch => "Opening and ending tag mismatch".into(),
ErrorKind::UnexpectedCharacter => {
"Unexpected character, only whitespace character allowed".into()
}
}
}
pub fn to_diagnostics<'a>(&self, handler: &'a Handler) -> DiagnosticBuilder<'a> {
handler.struct_span_err(self.inner.0, &self.message())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum ErrorKind {
Eof,
// Lexer errors
AbruptClosingOfEmptyComment,
AbruptDoctypePublicIdentifier,
AbruptDoctypeSystemIdentifier,
ControlCharacterInInputStream,
EndTagWithAttributes,
ShortTagWithAttributes,
DuplicateAttribute,
EndTagWithTrailingSolidus,
EofBeforeTagName,
EofInCdata,
EofInComment,
EofInDoctype,
EofInTag,
EofInProcessingInstruction,
IncorrectlyClosedComment,
IncorrectlyOpenedComment,
InvalidCharacterSequenceAfterDoctypeName,
InvalidFirstCharacterOfTagName,
InvalidCharacterOfProcessingInstruction,
InvalidCharacterInTag,
MissingDoctypeName,
MissingDoctypePublicIdentifier,
MissingQuoteBeforeDoctypePublicIdentifier,
MissingQuoteBeforeDoctypeSystemIdentifier,
MissingSemicolonAfterCharacterReference,
MissingWhitespaceAfterDoctypePublicKeyword,
MissingWhitespaceAfterDoctypeSystemKeyword,
MissingWhitespaceBeforeDoctypeName,
MissingWhitespaceBetweenDoctypePublicAndSystemIdentifiers,
NestedComment,
NoncharacterInInputStream,
SurrogateInInputStream,
SurrogateCharacterReference,
UnexpectedCharacterAfterDoctypeSystemIdentifier,
UnexpectedColonBeforeAttributeName,
UnexpectedSolidusInTag,
// Parser errors
UnexpectedTokenInStartPhase,
UnexpectedTokenInMainPhase,
UnexpectedTokenInEndPhase,
UnexpectedEofInStartPhase,
UnexpectedEofInMainPhase,
OpeningAndEndingTagMismatch,
UnexpectedCharacter,
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,37 @@
#![cfg_attr(docsrs, feature(doc_cfg))]
#![deny(unused_must_use)]
#![deny(clippy::all)]
#![allow(clippy::needless_return)]
#![allow(clippy::nonminimal_bool)]
#![allow(clippy::wrong_self_convention)]
use swc_common::{input::StringInput, SourceFile};
use swc_xml_ast::Document;
use crate::{
error::Error,
lexer::Lexer,
parser::{PResult, Parser, ParserConfig},
};
pub mod error;
pub mod lexer;
pub mod parser;
/// Parse a given file as `Document`.
///
/// If there are syntax errors but if it was recoverable, it will be appended to
/// `errors`.
pub fn parse_file_as_document(
fm: &SourceFile,
config: ParserConfig,
errors: &mut Vec<Error>,
) -> PResult<Document> {
let lexer = Lexer::new(StringInput::from(fm));
let mut parser = Parser::new(lexer, config);
let result = parser.parse_document();
errors.extend(parser.take_errors());
result
}

View File

@ -0,0 +1,91 @@
use std::{fmt::Debug, mem::take};
use swc_common::{BytePos, Span};
use swc_xml_ast::{Token, TokenAndSpan};
use super::PResult;
use crate::error::Error;
pub trait ParserInput: Iterator<Item = TokenAndSpan> {
fn start_pos(&mut self) -> BytePos;
fn last_pos(&mut self) -> BytePos;
fn take_errors(&mut self) -> Vec<Error>;
}
#[derive(Debug)]
pub(super) struct Buffer<I>
where
I: ParserInput,
{
cur: Option<TokenAndSpan>,
input: I,
}
impl<I> Buffer<I>
where
I: ParserInput,
{
pub fn new(input: I) -> Self {
Buffer { cur: None, input }
}
/// Last start position
pub fn start_pos(&mut self) -> PResult<BytePos> {
Ok(self.input.start_pos())
}
/// Last end position
pub fn last_pos(&mut self) -> PResult<BytePos> {
Ok(self.input.last_pos())
}
pub fn cur_span(&mut self) -> PResult<Span> {
if self.cur.is_none() {
self.bump_inner()?;
}
Ok(self.cur.as_ref().map(|cur| cur.span).unwrap_or_default())
}
pub fn cur(&mut self) -> PResult<Option<&Token>> {
if self.cur.is_none() {
self.bump_inner()?;
}
Ok(self.cur.as_ref().map(|v| &v.token))
}
#[track_caller]
pub fn bump(&mut self) -> PResult<Option<TokenAndSpan>> {
debug_assert!(
self.cur.is_some(),
"bump() is called without checking current token"
);
let token = self.cur.take();
Ok(token)
}
fn bump_inner(&mut self) -> PResult<()> {
self.cur = None;
if self.cur.is_none() {
let result = self.input.next();
if let Some(result) = result {
self.cur = Some(result);
} else {
return Ok(());
}
}
Ok(())
}
pub fn take_errors(&mut self) -> Vec<Error> {
take(&mut self.input.take_errors())
}
}

View File

@ -0,0 +1,23 @@
macro_rules! span {
($parser:expr, $start:expr) => {{
let last_pos = $parser.input.last_pos()?;
swc_common::Span::new($start, last_pos, Default::default())
}};
}
macro_rules! bump {
($parser:expr) => {
$parser.input.bump()?.unwrap().token
};
}
macro_rules! get_tag_name {
($node:expr) => {{
match &$node.data {
crate::parser::Data::Element { tag_name, .. } => tag_name.as_ref(),
_ => {
unreachable!();
}
}
}};
}

View File

@ -0,0 +1,620 @@
use std::{cell::RefCell, mem, rc::Rc};
use node::*;
use open_elements_stack::*;
use swc_common::{Span, DUMMY_SP};
use swc_xml_ast::*;
use self::input::{Buffer, ParserInput};
use crate::error::{Error, ErrorKind};
#[macro_use]
mod macros;
pub mod input;
mod node;
mod open_elements_stack;
pub type PResult<T> = Result<T, Error>;
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ParserConfig {}
pub enum Phase {
StartPhase,
MainPhase,
EndPhase,
}
impl Default for Phase {
fn default() -> Self {
Phase::StartPhase
}
}
pub struct Parser<I>
where
I: ParserInput,
{
#[allow(dead_code)]
config: ParserConfig,
input: Buffer<I>,
stopped: bool,
document: Option<RcNode>,
open_elements_stack: OpenElementsStack,
errors: Vec<Error>,
phase: Phase,
}
impl<I> Parser<I>
where
I: ParserInput,
{
pub fn new(input: I, config: ParserConfig) -> Self {
Parser {
config,
input: Buffer::new(input),
stopped: false,
document: None,
open_elements_stack: OpenElementsStack::new(),
errors: Default::default(),
phase: Phase::default(),
}
}
pub fn dump_cur(&mut self) -> String {
format!("{:?}", self.input.cur())
}
pub fn take_errors(&mut self) -> Vec<Error> {
mem::take(&mut self.errors)
}
pub fn parse_document(&mut self) -> PResult<Document> {
let start = self.input.cur_span()?;
self.document = Some(self.create_document());
self.run()?;
let document = &mut self.document.take().unwrap();
let nodes = document.children.take();
let mut children = Vec::with_capacity(nodes.len());
for node in nodes {
children.push(self.node_to_child(node));
}
let last = self.input.last_pos()?;
Ok(Document {
span: Span::new(start.lo(), last, Default::default()),
children,
})
}
fn create_document(&self) -> RcNode {
Node::new(Data::Document, DUMMY_SP)
}
fn get_deep_end_span(&mut self, children: &[Child]) -> Option<Span> {
match children.last() {
Some(Child::DocumentType(DocumentType { span, .. })) => Some(*span),
Some(Child::Element(Element { span, children, .. })) => {
if span.is_dummy() {
return self.get_deep_end_span(children);
}
Some(*span)
}
Some(Child::Comment(Comment { span, .. })) => Some(*span),
Some(Child::Text(Text { span, .. })) => Some(*span),
_ => None,
}
}
fn node_to_child(&mut self, node: RcNode) -> Child {
let start_span = node.start_span.take();
match node.data.clone() {
Data::DocumentType {
name,
public_id,
system_id,
raw,
} => Child::DocumentType(DocumentType {
span: start_span,
name,
public_id,
system_id,
raw,
}),
Data::Element {
tag_name,
attributes,
} => {
let nodes = node.children.take();
let mut new_children = Vec::with_capacity(nodes.len());
for node in nodes {
new_children.push(self.node_to_child(node));
}
let attributes = attributes.take();
let span = if start_span.is_dummy() {
start_span
} else {
let end_span = match node.end_span.take() {
Some(end_span) if !end_span.is_dummy() => end_span,
_ => match self.get_deep_end_span(&new_children) {
Some(end_span) => end_span,
_ => start_span,
},
};
Span::new(start_span.lo(), end_span.hi(), Default::default())
};
Child::Element(Element {
span,
tag_name,
attributes,
children: new_children,
})
}
Data::Text { data, raw } => {
let span = if let Some(end_span) = node.end_span.take() {
swc_common::Span::new(start_span.lo(), end_span.hi(), Default::default())
} else {
start_span
};
Child::Text(Text {
span,
data: data.take().into(),
raw: Some(raw.take().into()),
})
}
Data::Comment { data, raw } => Child::Comment(Comment {
span: start_span,
data,
raw,
}),
Data::ProcessingInstruction { target, data } => {
Child::ProcessingInstruction(ProcessingInstruction {
span: start_span,
target,
data,
})
}
_ => {
unreachable!();
}
}
}
fn run(&mut self) -> PResult<()> {
while !self.stopped {
let mut token_and_info = match self.input.cur()? {
Some(_) => {
let span = self.input.cur_span()?;
let token = bump!(self);
TokenAndInfo {
span: span!(self, span.lo()),
acknowledged: false,
token,
}
}
None => {
let start_pos = self.input.start_pos()?;
let last_pos = self.input.last_pos()?;
TokenAndInfo {
span: Span::new(start_pos, last_pos, Default::default()),
acknowledged: false,
token: Token::Eof,
}
}
};
// Re-emit errors from tokenizer
for error in self.input.take_errors() {
let (span, kind) = *error.into_inner();
self.errors.push(Error::new(span, kind));
}
self.tree_construction_dispatcher(&mut token_and_info)?;
}
Ok(())
}
fn tree_construction_dispatcher(&mut self, token_and_info: &mut TokenAndInfo) -> PResult<()> {
self.process_token(token_and_info, None)
}
fn process_token(
&mut self,
token_and_info: &mut TokenAndInfo,
phase: Option<Phase>,
) -> PResult<()> {
let phase = match &phase {
Some(phase) => phase,
_ => &self.phase,
};
match phase {
Phase::StartPhase => match &token_and_info.token {
Token::StartTag { .. } => {
let element = self.create_element_for_token(token_and_info.clone());
self.append_node(self.document.as_ref().unwrap(), element.clone());
self.open_elements_stack.items.push(element);
self.phase = Phase::MainPhase;
}
Token::EmptyTag { .. } => {
let element = self.create_element_for_token(token_and_info.clone());
self.append_node(self.document.as_ref().unwrap(), element);
self.phase = Phase::EndPhase;
}
Token::Comment { .. } => {
self.append_comment_to_doc(token_and_info)?;
}
Token::ProcessingInstruction { .. } => {
self.append_processing_instruction_to_doc(token_and_info)?;
}
Token::Character { value, .. } => {
if !is_whitespace(*value) {
self.errors.push(Error::new(
token_and_info.span,
ErrorKind::UnexpectedCharacter,
));
}
}
Token::Eof => {
self.errors.push(Error::new(
token_and_info.span,
ErrorKind::UnexpectedEofInStartPhase,
));
self.process_token(token_and_info, Some(Phase::EndPhase))?;
}
Token::Doctype { .. } => {
let document_type = self.create_document_type_for_token(token_and_info);
self.append_node(self.document.as_ref().unwrap(), document_type);
}
_ => {
self.errors.push(Error::new(
token_and_info.span,
ErrorKind::UnexpectedTokenInStartPhase,
));
}
},
Phase::MainPhase => match &token_and_info.token {
Token::Character { .. } => {
self.append_character_to_current_element(token_and_info)?;
}
Token::StartTag { .. } => {
let element = self.create_element_for_token(token_and_info.clone());
self.append_node(self.get_current_element(), element.clone());
self.open_elements_stack.items.push(element);
}
Token::EmptyTag { .. } => {
let element = self.create_element_for_token(token_and_info.clone());
self.append_node(self.get_current_element(), element);
}
Token::EndTag { tag_name, .. } => {
if get_tag_name!(self.get_current_element()) != tag_name {
self.errors.push(Error::new(
token_and_info.span,
ErrorKind::OpeningAndEndingTagMismatch,
));
}
let is_closed = self
.open_elements_stack
.items
.iter()
.rev()
.any(|node| get_tag_name!(node) == tag_name);
if is_closed {
let popped = self
.open_elements_stack
.pop_until_tag_name_popped(&[tag_name]);
self.update_end_tag_span(popped.as_ref(), token_and_info.span);
}
if self.open_elements_stack.items.is_empty() {
self.phase = Phase::EndPhase;
}
}
Token::ShortTag { .. } => {
self.open_elements_stack.items.pop();
if self.open_elements_stack.items.is_empty() {
self.phase = Phase::EndPhase;
}
}
Token::Comment { .. } => {
let comment = self.create_comment(token_and_info);
self.append_node(self.get_current_element(), comment);
}
Token::ProcessingInstruction { .. } => {
let processing_instruction = self.create_processing_instruction(token_and_info);
self.append_node(self.get_current_element(), processing_instruction);
}
Token::Eof => {
self.errors.push(Error::new(
token_and_info.span,
ErrorKind::UnexpectedEofInMainPhase,
));
self.process_token(token_and_info, Some(Phase::EndPhase))?;
}
_ => {
self.errors.push(Error::new(
token_and_info.span,
ErrorKind::UnexpectedTokenInMainPhase,
));
}
},
Phase::EndPhase => match &token_and_info.token {
Token::Comment { .. } => {
self.append_comment_to_doc(token_and_info)?;
}
Token::ProcessingInstruction { .. } => {
self.append_processing_instruction_to_doc(token_and_info)?;
}
Token::Character { value, .. } => {
if !is_whitespace(*value) {
self.errors.push(Error::new(
token_and_info.span,
ErrorKind::UnexpectedCharacter,
));
}
}
Token::Eof => {
self.stopped = true;
}
_ => {
self.errors.push(Error::new(
token_and_info.span,
ErrorKind::UnexpectedTokenInEndPhase,
));
}
},
}
Ok(())
}
fn append_node(&self, parent: &RcNode, child: RcNode) {
let previous_parent = child.parent.replace(Some(Rc::downgrade(parent)));
// Invariant: child cannot have existing parent
assert!(previous_parent.is_none());
parent.children.borrow_mut().push(child);
}
fn get_current_element(&self) -> &RcNode {
self.open_elements_stack
.items
.last()
.expect("no current element")
}
fn create_document_type_for_token(&self, token_and_info: &mut TokenAndInfo) -> RcNode {
let (name, public_id, system_id, raw) = match &token_and_info.token {
Token::Doctype {
name,
public_id,
system_id,
raw,
} => (
name.clone(),
public_id.clone(),
system_id.clone(),
raw.clone(),
),
_ => {
unreachable!()
}
};
Node::new(
Data::DocumentType {
name,
public_id,
system_id,
raw,
},
token_and_info.span,
)
}
fn create_element_for_token(&self, token_and_info: TokenAndInfo) -> RcNode {
let element = match token_and_info.token {
Token::StartTag {
tag_name,
attributes,
..
}
| Token::EndTag {
tag_name,
attributes,
..
}
| Token::ShortTag {
tag_name,
attributes,
..
}
| Token::EmptyTag {
tag_name,
attributes,
..
} => {
let attributes = attributes
.into_iter()
.map(|attribute_token| Attribute {
span: attribute_token.span,
namespace: None,
prefix: None,
name: attribute_token.name,
raw_name: attribute_token.raw_name,
value: attribute_token.value,
raw_value: attribute_token.raw_value,
})
.collect();
Data::Element {
tag_name,
attributes: RefCell::new(attributes),
}
}
_ => {
unreachable!();
}
};
Node::new(element, token_and_info.span)
}
fn append_character_to_current_element(
&mut self,
token_and_info: &mut TokenAndInfo,
) -> PResult<()> {
if let Some(last) = self.open_elements_stack.items.last() {
let children = last.children.borrow();
if let Some(last) = children.last() {
if let Data::Text {
data,
raw: raw_data,
} = &last.data
{
match &token_and_info.token {
Token::Character {
value: c,
raw: raw_c,
} => {
data.borrow_mut().push(*c);
if let Some(raw_c) = raw_c {
raw_data.borrow_mut().push_str(raw_c);
}
}
_ => {
unreachable!();
}
}
let mut span = last.end_span.borrow_mut();
*span = Some(token_and_info.span);
return Ok(());
}
}
}
let (data, raw) = match &token_and_info.token {
Token::Character {
value: c,
raw: raw_c,
} => {
let mut data = String::with_capacity(255);
data.push(*c);
let mut raw = String::with_capacity(255);
if let Some(raw_c) = raw_c {
raw.push_str(raw_c);
}
(RefCell::new(data), RefCell::new(raw))
}
_ => {
unreachable!()
}
};
let text = Node::new(Data::Text { data, raw }, token_and_info.span);
self.append_node(self.get_current_element(), text);
Ok(())
}
fn create_comment(&self, token_and_info: &mut TokenAndInfo) -> RcNode {
let (data, raw) = match &token_and_info.token {
Token::Comment { data, raw } => (data.clone(), Some(raw.clone())),
_ => {
unreachable!()
}
};
Node::new(Data::Comment { data, raw }, token_and_info.span)
}
fn append_comment_to_doc(&mut self, token_and_info: &mut TokenAndInfo) -> PResult<()> {
let comment = self.create_comment(token_and_info);
self.append_node(self.document.as_ref().unwrap(), comment);
Ok(())
}
fn create_processing_instruction(&self, token_and_info: &mut TokenAndInfo) -> RcNode {
let (target, data) = match &token_and_info.token {
Token::ProcessingInstruction { target, data } => (target.clone(), data.clone()),
_ => {
unreachable!()
}
};
Node::new(
Data::ProcessingInstruction { target, data },
token_and_info.span,
)
}
fn append_processing_instruction_to_doc(
&mut self,
token_and_info: &mut TokenAndInfo,
) -> PResult<()> {
let child = self.create_processing_instruction(token_and_info);
self.append_node(self.document.as_ref().unwrap(), child);
Ok(())
}
fn update_end_tag_span(&self, node: Option<&RcNode>, span: Span) {
if let Some(node) = node {
if node.start_span.borrow().is_dummy() {
return;
}
let mut end_tag_span = node.end_span.borrow_mut();
*end_tag_span = Some(span);
}
}
}
fn is_whitespace(c: char) -> bool {
matches!(c, '\t' | '\r' | '\n' | '\x0C' | ' ')
}

View File

@ -0,0 +1,88 @@
use std::{
cell::{Cell, RefCell},
fmt, mem,
rc::{Rc, Weak},
};
use swc_atoms::JsWord;
use swc_common::Span;
use swc_xml_ast::*;
#[derive(Debug, Clone)]
pub struct TokenAndInfo {
pub span: Span,
pub acknowledged: bool,
pub token: Token,
}
#[derive(Debug, Clone)]
pub enum Data {
Document,
DocumentType {
name: Option<JsWord>,
public_id: Option<JsWord>,
system_id: Option<JsWord>,
raw: Option<JsWord>,
},
Element {
tag_name: JsWord,
attributes: RefCell<Vec<Attribute>>,
},
Text {
data: RefCell<String>,
raw: RefCell<String>,
},
ProcessingInstruction {
target: JsWord,
data: JsWord,
},
Comment {
data: JsWord,
raw: Option<JsWord>,
},
}
pub struct Node {
pub parent: Cell<Option<WeakNode>>,
pub children: RefCell<Vec<RcNode>>,
pub data: Data,
pub start_span: RefCell<Span>,
pub end_span: RefCell<Option<Span>>,
}
impl Node {
/// Create a new node from its contents
pub fn new(data: Data, span: Span) -> Rc<Self> {
Rc::new(Node {
parent: Cell::new(None),
children: RefCell::new(vec![]),
start_span: RefCell::new(span),
end_span: RefCell::new(None),
data,
})
}
}
impl Drop for Node {
fn drop(&mut self) {
let mut nodes = mem::take(&mut *self.children.borrow_mut());
while let Some(node) = nodes.pop() {
let children = mem::take(&mut *node.children.borrow_mut());
nodes.extend(children.into_iter());
}
}
}
impl fmt::Debug for Node {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("Node")
.field("data", &self.data)
.field("children", &self.children)
.finish()
}
}
pub type RcNode = Rc<Node>;
type WeakNode = Weak<Node>;

View File

@ -0,0 +1,23 @@
use crate::parser::RcNode;
pub struct OpenElementsStack {
pub items: Vec<RcNode>,
}
impl OpenElementsStack {
pub fn new() -> Self {
OpenElementsStack {
items: Vec::with_capacity(16),
}
}
pub fn pop_until_tag_name_popped(&mut self, tag_name: &[&str]) -> Option<RcNode> {
while let Some(node) = self.items.pop() {
if tag_name.contains(&get_tag_name!(node)) {
return Some(node);
}
}
None
}
}

View File

@ -0,0 +1,427 @@
#![deny(warnings)]
#![allow(clippy::if_same_then_else)]
#![allow(clippy::needless_update)]
#![allow(clippy::redundant_clone)]
#![allow(clippy::while_let_on_iterator)]
use std::path::PathBuf;
use swc_common::{errors::Handler, input::SourceFileInput, Spanned};
use swc_xml_ast::*;
use swc_xml_parser::{
lexer::Lexer,
parser::{PResult, Parser, ParserConfig},
};
use swc_xml_visit::{Visit, VisitMut, VisitMutWith, VisitWith};
use testing::NormalizedOutput;
fn document_test(input: PathBuf, config: ParserConfig) {
testing::run_test2(false, |cm, handler| {
let json_path = input.parent().unwrap().join("output.json");
let fm = cm.load_file(&input).unwrap();
let lexer = Lexer::new(SourceFileInput::from(&*fm));
let mut parser = Parser::new(lexer, config);
let document: PResult<Document> = parser.parse_document();
let errors = parser.take_errors();
for err in &errors {
err.to_diagnostics(&handler).emit();
}
if !errors.is_empty() {
return Err(());
}
match document {
Ok(document) => {
let actual_json = serde_json::to_string_pretty(&document)
.map(NormalizedOutput::from)
.expect("failed to serialize document");
actual_json.compare_to_file(&json_path).unwrap();
Ok(())
}
Err(err) => {
let mut d = err.to_diagnostics(&handler);
d.note(&format!("current token = {}", parser.dump_cur()));
d.emit();
Err(())
}
}
})
.unwrap();
}
fn document_recovery_test(input: PathBuf, config: ParserConfig) {
let stderr_path = input.parent().unwrap().join("output.stderr");
let mut recovered = false;
let stderr = testing::run_test2(false, |cm, handler| {
// Type annotation
if false {
return Ok(());
}
let json_path = input.parent().unwrap().join("output.json");
let fm = cm.load_file(&input).unwrap();
let lexer = Lexer::new(SourceFileInput::from(&*fm));
let mut parser = Parser::new(lexer, config);
let document: PResult<Document> = parser.parse_document();
let errors = parser.take_errors();
for err in &errors {
err.to_diagnostics(&handler).emit();
}
if !errors.is_empty() {
recovered = true;
}
match document {
Ok(document) => {
let actual_json = serde_json::to_string_pretty(&document)
.map(NormalizedOutput::from)
.expect("failed to serialize document");
actual_json.compare_to_file(&json_path).unwrap();
Err(())
}
Err(err) => {
let mut d = err.to_diagnostics(&handler);
d.note(&format!("current token = {}", parser.dump_cur()));
d.emit();
Err(())
}
}
})
.unwrap_err();
if !recovered {
panic!(
"Parser should emit errors (recover mode), but parser parsed everything successfully \
{}",
stderr
);
}
stderr.compare_to_file(&stderr_path).unwrap();
}
fn document_span_visualizer(input: PathBuf, config: ParserConfig) {
let dir = input.parent().unwrap().to_path_buf();
let output = testing::run_test2(false, |cm, handler| {
// Type annotation
if false {
return Ok(());
}
let fm = cm.load_file(&input).unwrap();
let lexer = Lexer::new(SourceFileInput::from(&*fm));
let mut parser = Parser::new(lexer, config);
let document: PResult<Document> = parser.parse_document();
match document {
Ok(document) => {
document.visit_with(&mut SpanVisualizer { handler: &handler });
Err(())
}
Err(err) => {
let mut d = err.to_diagnostics(&handler);
d.note(&format!("current token = {}", parser.dump_cur()));
d.emit();
panic!();
}
}
})
.unwrap_err();
output
.compare_to_file(&dir.join("span.rust-debug"))
.unwrap();
}
fn document_dom_visualizer(input: PathBuf, config: ParserConfig) {
let dir = input.parent().unwrap().to_path_buf();
testing::run_test2(false, |cm, handler| {
// Type annotation
if false {
return Ok(());
}
let fm = cm.load_file(&input).unwrap();
let lexer = Lexer::new(SourceFileInput::from(&*fm));
let mut parser = Parser::new(lexer, config);
let document: PResult<Document> = parser.parse_document();
match document {
Ok(mut document) => {
let mut dom_buf = String::new();
document.visit_mut_with(&mut DomVisualizer {
dom_buf: &mut dom_buf,
indent: 0,
});
NormalizedOutput::from(dom_buf)
.compare_to_file(&dir.join("dom.rust-debug"))
.unwrap();
Ok(())
}
Err(err) => {
let mut d = err.to_diagnostics(&handler);
d.note(&format!("current token = {}", parser.dump_cur()));
d.emit();
panic!();
}
}
})
.unwrap();
}
struct SpanVisualizer<'a> {
handler: &'a Handler,
}
macro_rules! mtd {
($T:ty,$name:ident) => {
fn $name(&mut self, n: &$T) {
let span = n.span();
self.handler.struct_span_err(span, stringify!($T)).emit();
n.visit_children_with(self);
}
};
}
impl Visit for SpanVisualizer<'_> {
mtd!(Document, visit_document);
mtd!(Child, visit_child);
mtd!(DocumentType, visit_document_type);
mtd!(Element, visit_element);
mtd!(Attribute, visit_attribute);
mtd!(Text, visit_text);
mtd!(ProcessingInstruction, visit_processing_instruction);
mtd!(Comment, visit_comment);
}
struct DomVisualizer<'a> {
dom_buf: &'a mut String,
indent: usize,
}
impl DomVisualizer<'_> {
fn get_ident(&self) -> String {
let mut indent = String::new();
indent.push_str("| ");
indent.push_str(&" ".repeat(self.indent));
indent
}
}
impl VisitMut for DomVisualizer<'_> {
fn visit_mut_document_type(&mut self, n: &mut DocumentType) {
let mut document_type = String::new();
document_type.push_str(&self.get_ident());
document_type.push_str("<!DOCTYPE ");
if let Some(name) = &n.name {
document_type.push_str(name);
}
if let Some(public_id) = &n.public_id {
document_type.push(' ');
document_type.push('"');
document_type.push_str(public_id);
document_type.push('"');
if let Some(system_id) = &n.system_id {
document_type.push(' ');
document_type.push('"');
document_type.push_str(system_id);
document_type.push('"');
} else {
document_type.push(' ');
document_type.push('"');
document_type.push('"');
}
} else if let Some(system_id) = &n.system_id {
document_type.push(' ');
document_type.push('"');
document_type.push('"');
document_type.push(' ');
document_type.push('"');
document_type.push_str(system_id);
document_type.push('"');
}
document_type.push('>');
document_type.push('\n');
self.dom_buf.push_str(&document_type);
n.visit_mut_children_with(self);
}
fn visit_mut_element(&mut self, n: &mut Element) {
let mut element = String::new();
element.push_str(&self.get_ident());
element.push('<');
element.push_str(&n.tag_name);
element.push('>');
element.push('\n');
n.attributes
.sort_by(|a, b| a.name.partial_cmp(&b.name).unwrap());
self.dom_buf.push_str(&element);
let old_indent = self.indent;
self.indent += 1;
n.visit_mut_children_with(self);
self.indent = old_indent;
}
fn visit_mut_attribute(&mut self, n: &mut Attribute) {
let mut attribute = String::new();
attribute.push_str(&self.get_ident());
if let Some(prefix) = &n.prefix {
attribute.push_str(prefix);
attribute.push(' ');
}
attribute.push_str(&n.name);
attribute.push('=');
attribute.push('"');
if let Some(value) = &n.value {
attribute.push_str(value);
}
attribute.push('"');
attribute.push('\n');
self.dom_buf.push_str(&attribute);
n.visit_mut_children_with(self);
}
fn visit_mut_text(&mut self, n: &mut Text) {
let mut text = String::new();
text.push_str(&self.get_ident());
text.push('"');
text.push_str(&n.data);
text.push('"');
text.push('\n');
self.dom_buf.push_str(&text);
n.visit_mut_children_with(self);
}
fn visit_mut_comment(&mut self, n: &mut Comment) {
let mut comment = String::new();
comment.push_str(&self.get_ident());
comment.push_str("<!-- ");
comment.push_str(&n.data);
comment.push_str(" -->");
comment.push('\n');
self.dom_buf.push_str(&comment);
n.visit_mut_children_with(self);
}
fn visit_mut_processing_instruction(&mut self, n: &mut ProcessingInstruction) {
let mut processing_instruction = String::new();
processing_instruction.push_str("<?");
processing_instruction.push_str(&n.target);
processing_instruction.push(' ');
processing_instruction.push_str(&n.data);
processing_instruction.push('>');
processing_instruction.push('\n');
self.dom_buf.push_str(&processing_instruction);
n.visit_mut_children_with(self);
}
}
#[testing::fixture("tests/fixture/**/*.xml")]
fn pass(input: PathBuf) {
document_test(
input,
ParserConfig {
..Default::default()
},
)
}
#[testing::fixture("tests/recovery/**/*.xml")]
fn recovery(input: PathBuf) {
document_recovery_test(
input,
ParserConfig {
..Default::default()
},
)
}
#[testing::fixture("tests/fixture/**/*.xml")]
#[testing::fixture("tests/recovery/**/*.xml")]
fn span_visualizer(input: PathBuf) {
document_span_visualizer(
input,
ParserConfig {
..Default::default()
},
)
}
#[testing::fixture("tests/fixture/**/*.xml")]
#[testing::fixture("tests/recovery/**/*.xml")]
fn dom_visualizer(input: PathBuf) {
document_dom_visualizer(
input,
ParserConfig {
..Default::default()
},
)
}
// TODO tests from xml5lib-tests

View File

@ -0,0 +1,119 @@
<?xml version="1.0">
| <PurchaseOrder>
| OrderDate="1999-10-20"
| PurchaseOrderNumber="99503"
| "
"
| <Address>
| Type="Shipping"
| "
"
| <Name>
| "Ellen Adams"
| "
"
| <Street>
| "123 Maple Street"
| "
"
| <City>
| "Mill Valley"
| "
"
| <State>
| "CA"
| "
"
| <Zip>
| "10999"
| "
"
| <Country>
| "USA"
| "
"
| "
"
| <Address>
| Type="Billing"
| "
"
| <Name>
| "Tai Yee"
| "
"
| <Street>
| "8 Oak Avenue"
| "
"
| <City>
| "Old Town"
| "
"
| <State>
| "PA"
| "
"
| <Zip>
| "95819"
| "
"
| <Country>
| "USA"
| "
"
| "
"
| <DeliveryNotes>
| "Please leave packages in shed by driveway."
| "
"
| <Items>
| "
"
| <Item>
| PartNumber="872-AA"
| "
"
| <ProductName>
| "Lawnmower"
| "
"
| <Quantity>
| "1"
| "
"
| <USPrice>
| "148.95"
| "
"
| <Comment>
| "Confirm this is electric"
| "
"
| "
"
| <Item>
| PartNumber="926-AA"
| "
"
| <ProductName>
| "Baby Monitor"
| "
"
| <Quantity>
| "2"
| "
"
| <USPrice>
| "39.98"
| "
"
| <ShipDate>
| "1999-05-21"
| "
"
| "
"
| "
"

View File

@ -0,0 +1,34 @@
<?xml version="1.0"?>
<PurchaseOrder PurchaseOrderNumber="99503" OrderDate="1999-10-20">
<Address Type="Shipping">
<Name>Ellen Adams</Name>
<Street>123 Maple Street</Street>
<City>Mill Valley</City>
<State>CA</State>
<Zip>10999</Zip>
<Country>USA</Country>
</Address>
<Address Type="Billing">
<Name>Tai Yee</Name>
<Street>8 Oak Avenue</Street>
<City>Old Town</City>
<State>PA</State>
<Zip>95819</Zip>
<Country>USA</Country>
</Address>
<DeliveryNotes>Please leave packages in shed by driveway.</DeliveryNotes>
<Items>
<Item PartNumber="872-AA">
<ProductName>Lawnmower</ProductName>
<Quantity>1</Quantity>
<USPrice>148.95</USPrice>
<Comment>Confirm this is electric</Comment>
</Item>
<Item PartNumber="926-AA">
<ProductName>Baby Monitor</ProductName>
<Quantity>2</Quantity>
<USPrice>39.98</USPrice>
<ShipDate>1999-05-21</ShipDate>
</Item>
</Items>
</PurchaseOrder>

View File

@ -0,0 +1,963 @@
{
"type": "Document",
"span": {
"start": 1,
"end": 1115,
"ctxt": 0
},
"children": [
{
"type": "ProcessingInstruction",
"span": {
"start": 1,
"end": 22,
"ctxt": 0
},
"target": "xml",
"data": "version=\"1.0\""
},
{
"type": "Element",
"span": {
"start": 23,
"end": 1115,
"ctxt": 0
},
"tagName": "PurchaseOrder",
"attributes": [
{
"type": "Attribute",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"namespace": null,
"prefix": null,
"name": "PurchaseOrderNumber",
"rawName": "PurchaseOrderNumber",
"value": "99503",
"rawValue": "\"99503\""
},
{
"type": "Attribute",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"namespace": null,
"prefix": null,
"name": "OrderDate",
"rawName": "OrderDate",
"value": "1999-10-20",
"rawValue": "\"1999-10-20\""
}
],
"children": [
{
"type": "Text",
"span": {
"start": 89,
"end": 94,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Element",
"span": {
"start": 94,
"end": 324,
"ctxt": 0
},
"tagName": "Address",
"attributes": [
{
"type": "Attribute",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"namespace": null,
"prefix": null,
"name": "Type",
"rawName": "Type",
"value": "Shipping",
"rawValue": "\"Shipping\""
}
],
"children": [
{
"type": "Text",
"span": {
"start": 119,
"end": 128,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Element",
"span": {
"start": 128,
"end": 152,
"ctxt": 0
},
"tagName": "Name",
"attributes": [],
"children": [
{
"type": "Text",
"span": {
"start": 134,
"end": 145,
"ctxt": 0
},
"data": "Ellen Adams",
"raw": "Ellen Adams"
}
]
},
{
"type": "Text",
"span": {
"start": 152,
"end": 161,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Element",
"span": {
"start": 161,
"end": 194,
"ctxt": 0
},
"tagName": "Street",
"attributes": [],
"children": [
{
"type": "Text",
"span": {
"start": 169,
"end": 185,
"ctxt": 0
},
"data": "123 Maple Street",
"raw": "123 Maple Street"
}
]
},
{
"type": "Text",
"span": {
"start": 194,
"end": 203,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Element",
"span": {
"start": 203,
"end": 227,
"ctxt": 0
},
"tagName": "City",
"attributes": [],
"children": [
{
"type": "Text",
"span": {
"start": 209,
"end": 220,
"ctxt": 0
},
"data": "Mill Valley",
"raw": "Mill Valley"
}
]
},
{
"type": "Text",
"span": {
"start": 227,
"end": 236,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Element",
"span": {
"start": 236,
"end": 253,
"ctxt": 0
},
"tagName": "State",
"attributes": [],
"children": [
{
"type": "Text",
"span": {
"start": 243,
"end": 245,
"ctxt": 0
},
"data": "CA",
"raw": "CA"
}
]
},
{
"type": "Text",
"span": {
"start": 253,
"end": 262,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Element",
"span": {
"start": 262,
"end": 278,
"ctxt": 0
},
"tagName": "Zip",
"attributes": [],
"children": [
{
"type": "Text",
"span": {
"start": 267,
"end": 272,
"ctxt": 0
},
"data": "10999",
"raw": "10999"
}
]
},
{
"type": "Text",
"span": {
"start": 278,
"end": 287,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Element",
"span": {
"start": 287,
"end": 309,
"ctxt": 0
},
"tagName": "Country",
"attributes": [],
"children": [
{
"type": "Text",
"span": {
"start": 296,
"end": 299,
"ctxt": 0
},
"data": "USA",
"raw": "USA"
}
]
},
{
"type": "Text",
"span": {
"start": 309,
"end": 314,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
}
]
},
{
"type": "Text",
"span": {
"start": 324,
"end": 329,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Element",
"span": {
"start": 329,
"end": 547,
"ctxt": 0
},
"tagName": "Address",
"attributes": [
{
"type": "Attribute",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"namespace": null,
"prefix": null,
"name": "Type",
"rawName": "Type",
"value": "Billing",
"rawValue": "\"Billing\""
}
],
"children": [
{
"type": "Text",
"span": {
"start": 353,
"end": 362,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Element",
"span": {
"start": 362,
"end": 382,
"ctxt": 0
},
"tagName": "Name",
"attributes": [],
"children": [
{
"type": "Text",
"span": {
"start": 368,
"end": 375,
"ctxt": 0
},
"data": "Tai Yee",
"raw": "Tai Yee"
}
]
},
{
"type": "Text",
"span": {
"start": 382,
"end": 391,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Element",
"span": {
"start": 391,
"end": 420,
"ctxt": 0
},
"tagName": "Street",
"attributes": [],
"children": [
{
"type": "Text",
"span": {
"start": 399,
"end": 411,
"ctxt": 0
},
"data": "8 Oak Avenue",
"raw": "8 Oak Avenue"
}
]
},
{
"type": "Text",
"span": {
"start": 420,
"end": 429,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Element",
"span": {
"start": 429,
"end": 450,
"ctxt": 0
},
"tagName": "City",
"attributes": [],
"children": [
{
"type": "Text",
"span": {
"start": 435,
"end": 443,
"ctxt": 0
},
"data": "Old Town",
"raw": "Old Town"
}
]
},
{
"type": "Text",
"span": {
"start": 450,
"end": 459,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Element",
"span": {
"start": 459,
"end": 476,
"ctxt": 0
},
"tagName": "State",
"attributes": [],
"children": [
{
"type": "Text",
"span": {
"start": 466,
"end": 468,
"ctxt": 0
},
"data": "PA",
"raw": "PA"
}
]
},
{
"type": "Text",
"span": {
"start": 476,
"end": 485,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Element",
"span": {
"start": 485,
"end": 501,
"ctxt": 0
},
"tagName": "Zip",
"attributes": [],
"children": [
{
"type": "Text",
"span": {
"start": 490,
"end": 495,
"ctxt": 0
},
"data": "95819",
"raw": "95819"
}
]
},
{
"type": "Text",
"span": {
"start": 501,
"end": 510,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Element",
"span": {
"start": 510,
"end": 532,
"ctxt": 0
},
"tagName": "Country",
"attributes": [],
"children": [
{
"type": "Text",
"span": {
"start": 519,
"end": 522,
"ctxt": 0
},
"data": "USA",
"raw": "USA"
}
]
},
{
"type": "Text",
"span": {
"start": 532,
"end": 537,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
}
]
},
{
"type": "Text",
"span": {
"start": 547,
"end": 552,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Element",
"span": {
"start": 552,
"end": 625,
"ctxt": 0
},
"tagName": "DeliveryNotes",
"attributes": [],
"children": [
{
"type": "Text",
"span": {
"start": 567,
"end": 609,
"ctxt": 0
},
"data": "Please leave packages in shed by driveway.",
"raw": "Please leave packages in shed by driveway."
}
]
},
{
"type": "Text",
"span": {
"start": 625,
"end": 630,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Element",
"span": {
"start": 630,
"end": 1098,
"ctxt": 0
},
"tagName": "Items",
"attributes": [],
"children": [
{
"type": "Text",
"span": {
"start": 637,
"end": 646,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Element",
"span": {
"start": 646,
"end": 866,
"ctxt": 0
},
"tagName": "Item",
"attributes": [
{
"type": "Attribute",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"namespace": null,
"prefix": null,
"name": "PartNumber",
"rawName": "PartNumber",
"value": "872-AA",
"rawValue": "\"872-AA\""
}
],
"children": [
{
"type": "Text",
"span": {
"start": 672,
"end": 685,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Element",
"span": {
"start": 685,
"end": 721,
"ctxt": 0
},
"tagName": "ProductName",
"attributes": [],
"children": [
{
"type": "Text",
"span": {
"start": 698,
"end": 707,
"ctxt": 0
},
"data": "Lawnmower",
"raw": "Lawnmower"
}
]
},
{
"type": "Text",
"span": {
"start": 721,
"end": 734,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Element",
"span": {
"start": 734,
"end": 756,
"ctxt": 0
},
"tagName": "Quantity",
"attributes": [],
"children": [
{
"type": "Text",
"span": {
"start": 744,
"end": 745,
"ctxt": 0
},
"data": "1",
"raw": "1"
}
]
},
{
"type": "Text",
"span": {
"start": 756,
"end": 769,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Element",
"span": {
"start": 769,
"end": 794,
"ctxt": 0
},
"tagName": "USPrice",
"attributes": [],
"children": [
{
"type": "Text",
"span": {
"start": 778,
"end": 784,
"ctxt": 0
},
"data": "148.95",
"raw": "148.95"
}
]
},
{
"type": "Text",
"span": {
"start": 794,
"end": 807,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Element",
"span": {
"start": 807,
"end": 850,
"ctxt": 0
},
"tagName": "Comment",
"attributes": [],
"children": [
{
"type": "Text",
"span": {
"start": 816,
"end": 840,
"ctxt": 0
},
"data": "Confirm this is electric",
"raw": "Confirm this is electric"
}
]
},
{
"type": "Text",
"span": {
"start": 850,
"end": 859,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
}
]
},
{
"type": "Text",
"span": {
"start": 866,
"end": 875,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Element",
"span": {
"start": 875,
"end": 1085,
"ctxt": 0
},
"tagName": "Item",
"attributes": [
{
"type": "Attribute",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"namespace": null,
"prefix": null,
"name": "PartNumber",
"rawName": "PartNumber",
"value": "926-AA",
"rawValue": "\"926-AA\""
}
],
"children": [
{
"type": "Text",
"span": {
"start": 901,
"end": 914,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Element",
"span": {
"start": 914,
"end": 953,
"ctxt": 0
},
"tagName": "ProductName",
"attributes": [],
"children": [
{
"type": "Text",
"span": {
"start": 927,
"end": 939,
"ctxt": 0
},
"data": "Baby Monitor",
"raw": "Baby Monitor"
}
]
},
{
"type": "Text",
"span": {
"start": 953,
"end": 966,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Element",
"span": {
"start": 966,
"end": 988,
"ctxt": 0
},
"tagName": "Quantity",
"attributes": [],
"children": [
{
"type": "Text",
"span": {
"start": 976,
"end": 977,
"ctxt": 0
},
"data": "2",
"raw": "2"
}
]
},
{
"type": "Text",
"span": {
"start": 988,
"end": 1001,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Element",
"span": {
"start": 1001,
"end": 1025,
"ctxt": 0
},
"tagName": "USPrice",
"attributes": [],
"children": [
{
"type": "Text",
"span": {
"start": 1010,
"end": 1015,
"ctxt": 0
},
"data": "39.98",
"raw": "39.98"
}
]
},
{
"type": "Text",
"span": {
"start": 1025,
"end": 1038,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Element",
"span": {
"start": 1038,
"end": 1069,
"ctxt": 0
},
"tagName": "ShipDate",
"attributes": [],
"children": [
{
"type": "Text",
"span": {
"start": 1048,
"end": 1058,
"ctxt": 0
},
"data": "1999-05-21",
"raw": "1999-05-21"
}
]
},
{
"type": "Text",
"span": {
"start": 1069,
"end": 1078,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
}
]
},
{
"type": "Text",
"span": {
"start": 1085,
"end": 1090,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
}
]
},
{
"type": "Text",
"span": {
"start": 1098,
"end": 1099,
"ctxt": 0
},
"data": "\n",
"raw": "\n"
}
]
}
]
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,167 @@
<?xml version="1.0">
| <any_name>
| attr="https://example.com/somepath"
| "
"
| <person>
| id="101"
| "
"
| <phone>
| "+122233344550"
| "
"
| <name>
| "Jack"
| "
"
| <phone>
| "+122233344551"
| "
"
| <age>
| "33"
| "
"
| <emptyNode>
| "
"
| <booleanNode>
| "false"
| "
"
| <booleanNode>
| "true"
| "
"
| <selfclosing>
| "
"
| <selfclosing>
| with="value"
| "
"
| <married>
| attr="val 2"
| firstTime="No"
| "Yes"
| "
"
| <birthday>
| "Wed, 28 Mar 1979 12:13:14 +0300"
| "
"
| <address>
| "
"
| <city>
| "New York"
| "
"
| <street>
| "Park Ave"
| "
"
| <buildingNo>
| "1"
| "
"
| <flatNo>
| "1"
| "
"
| "
"
| <address>
| "
"
| <city>
| "Boston"
| "
"
| <street>
| "Centre St"
| "
"
| <buildingNo>
| "33"
| "
"
| <flatNo>
| "24"
| "
"
| "
"
| "
"
| <person>
| id="102"
| "
"
| <phone>
| "+122233344553"
| "
"
| <name>
| "Boris"
| "
"
| <phone>
| "+122233344554"
| "
"
| <age>
| "34"
| "
"
| <!-- TODO <married ns:firstTime="Yes"><![CDATA[<some>Jack</some>]]><![CDATA[Jack]]></married> -->
| "
"
| <birthday>
| "Mon, 31 Aug 1970 02:03:04 +0300"
| "
"
| <ns:address>
| "
"
| <!-- TODO <city><![CDATA[<some>Jack</some>]]></city> -->
| "
"
| <street>
| "Kahovka"
| "
"
| <buildingNo>
| "1"
| "
"
| <flatNo>
| "2"
| "
"
| "
"
| <address>
| "
"
| <city>
| "Tula"
| "
"
| <street>
| "Lenina"
| "
"
| <buildingNo>
| "3"
| "
"
| <flatNo>
| "78"
| "
"
| "
"
| "
"

View File

@ -0,0 +1,48 @@
<?xml version="1.0"?>
<any_name attr="https://example.com/somepath">
<person id="101">
<phone>+122233344550</phone>
<name>Jack</name>
<phone>+122233344551</phone>
<age>33</age>
<emptyNode></emptyNode>
<booleanNode>false</booleanNode>
<booleanNode>true</booleanNode>
<selfclosing />
<selfclosing with="value" />
<married firstTime="No" attr="val 2">Yes</married>
<birthday>Wed, 28 Mar 1979 12:13:14 +0300</birthday>
<address>
<city>New York</city>
<street>Park Ave</street>
<buildingNo>1</buildingNo>
<flatNo>1</flatNo>
</address>
<address>
<city>Boston</city>
<street>Centre St</street>
<buildingNo>33</buildingNo>
<flatNo>24</flatNo>
</address>
</person>
<person id="102">
<phone>+122233344553</phone>
<name>Boris</name>
<phone>+122233344554</phone>
<age>34</age>
<!-- TODO <married ns:firstTime="Yes"><![CDATA[<some>Jack</some>]]><![CDATA[Jack]]></married>-->
<birthday>Mon, 31 Aug 1970 02:03:04 +0300</birthday>
<ns:address>
<!-- TODO <city><![CDATA[<some>Jack</some>]]></city>-->
<street>Kahovka</street>
<buildingNo>1</buildingNo>
<flatNo>2</flatNo>
</ns:address>
<address>
<city>Tula</city>
<street>Lenina</street>
<buildingNo>3</buildingNo>
<flatNo>78</flatNo>
</address>
</person>
</any_name>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,73 @@
<?xml version="1.0" encoding="UTF-8">
| <svg>
| viewBox="0 0 83 121"
| xmlns="http://www.w3.org/2000/svg"
| "
"
| <!-- test -->
| "
"
| <g>
| fill="none"
| stroke-linecap="round"
| "
"
| <g>
| stroke-width="8"
| "
"
| <path>
| d="M23,40l2,13l-13-2"
| stroke="#FD4"
| "
"
| <path>
| d="M36,40l-1,13l13-3"
| stroke="#D25"
| "
"
| <path>
| d="M23,80l7-11l7,11"
| stroke="#8CE"
| "
"
| "
"
| <g>
| stroke-width="6"
| "
"
| <path>
| d="M8,4c-8,9-5,30,17,49"
| stroke="#FD4"
| "
"
| <path>
| d="M79,25c-22-6-32,14-42,26"
| stroke="#D25"
| "
"
| <path>
| d="M10,118c23-8,20-30,20-44"
| stroke="#8CE"
| "
"
| <path>
| d="M20,48l10,12v13m0-13l10-12"
| stroke="#FFF"
| "
"
| "
"
| <path>
| d="M20,48l10,12v13m0-13l10-12"
| stroke="#000"
| stroke-width="5"
| "
"
| <text>
| "Text"
| "
"
| "
"

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 83 121">
<!-- test -->
<g fill="none" stroke-linecap="round">
<g stroke-width="8">
<path d="M23,40l2,13l-13-2" stroke="#FD4"/>
<path d="M36,40l-1,13l13-3" stroke="#D25"/>
<path d="M23,80l7-11l7,11" stroke="#8CE"/>
</g>
<g stroke-width="6">
<path d="M8,4c-8,9-5,30,17,49" stroke="#FD4"/>
<path d="M79,25c-22-6-32,14-42,26" stroke="#D25"/>
<path d="M10,118c23-8,20-30,20-44" stroke="#8CE"/>
<path d="M20,48l10,12v13m0-13l10-12" stroke="#FFF"/>
</g>
<path d="M20,48l10,12v13m0-13l10-12" stroke-width="5" stroke="#000"/>
<text>Text</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 783 B

View File

@ -0,0 +1,692 @@
{
"type": "Document",
"span": {
"start": 1,
"end": 784,
"ctxt": 0
},
"children": [
{
"type": "ProcessingInstruction",
"span": {
"start": 1,
"end": 39,
"ctxt": 0
},
"target": "xml",
"data": "version=\"1.0\" encoding=\"UTF-8\""
},
{
"type": "Element",
"span": {
"start": 40,
"end": 783,
"ctxt": 0
},
"tagName": "svg",
"attributes": [
{
"type": "Attribute",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"namespace": null,
"prefix": null,
"name": "xmlns",
"rawName": "xmlns",
"value": "http://www.w3.org/2000/svg",
"rawValue": "\"http://www.w3.org/2000/svg\""
},
{
"type": "Attribute",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"namespace": null,
"prefix": null,
"name": "viewBox",
"rawName": "viewBox",
"value": "0 0 83 121",
"rawValue": "\"0 0 83 121\""
}
],
"children": [
{
"type": "Text",
"span": {
"start": 101,
"end": 106,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Comment",
"span": {
"start": 106,
"end": 119,
"ctxt": 0
},
"data": " test ",
"raw": "<!-- test -->"
},
{
"type": "Text",
"span": {
"start": 119,
"end": 124,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Element",
"span": {
"start": 124,
"end": 776,
"ctxt": 0
},
"tagName": "g",
"attributes": [
{
"type": "Attribute",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"namespace": null,
"prefix": null,
"name": "fill",
"rawName": "fill",
"value": "none",
"rawValue": "\"none\""
},
{
"type": "Attribute",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"namespace": null,
"prefix": null,
"name": "stroke-linecap",
"rawName": "stroke-linecap",
"value": "round",
"rawValue": "\"round\""
}
],
"children": [
{
"type": "Text",
"span": {
"start": 162,
"end": 171,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Element",
"span": {
"start": 171,
"end": 371,
"ctxt": 0
},
"tagName": "g",
"attributes": [
{
"type": "Attribute",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"namespace": null,
"prefix": null,
"name": "stroke-width",
"rawName": "stroke-width",
"value": "8",
"rawValue": "\"8\""
}
],
"children": [
{
"type": "Text",
"span": {
"start": 191,
"end": 204,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Element",
"span": {
"start": 204,
"end": 247,
"ctxt": 0
},
"tagName": "path",
"attributes": [
{
"type": "Attribute",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"namespace": null,
"prefix": null,
"name": "d",
"rawName": "d",
"value": "M23,40l2,13l-13-2",
"rawValue": "\"M23,40l2,13l-13-2\""
},
{
"type": "Attribute",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"namespace": null,
"prefix": null,
"name": "stroke",
"rawName": "stroke",
"value": "#FD4",
"rawValue": "\"#FD4\""
}
],
"children": []
},
{
"type": "Text",
"span": {
"start": 247,
"end": 260,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Element",
"span": {
"start": 260,
"end": 303,
"ctxt": 0
},
"tagName": "path",
"attributes": [
{
"type": "Attribute",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"namespace": null,
"prefix": null,
"name": "d",
"rawName": "d",
"value": "M36,40l-1,13l13-3",
"rawValue": "\"M36,40l-1,13l13-3\""
},
{
"type": "Attribute",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"namespace": null,
"prefix": null,
"name": "stroke",
"rawName": "stroke",
"value": "#D25",
"rawValue": "\"#D25\""
}
],
"children": []
},
{
"type": "Text",
"span": {
"start": 303,
"end": 316,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Element",
"span": {
"start": 316,
"end": 358,
"ctxt": 0
},
"tagName": "path",
"attributes": [
{
"type": "Attribute",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"namespace": null,
"prefix": null,
"name": "d",
"rawName": "d",
"value": "M23,80l7-11l7,11",
"rawValue": "\"M23,80l7-11l7,11\""
},
{
"type": "Attribute",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"namespace": null,
"prefix": null,
"name": "stroke",
"rawName": "stroke",
"value": "#8CE",
"rawValue": "\"#8CE\""
}
],
"children": []
},
{
"type": "Text",
"span": {
"start": 358,
"end": 367,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
}
]
},
{
"type": "Text",
"span": {
"start": 371,
"end": 380,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Element",
"span": {
"start": 380,
"end": 663,
"ctxt": 0
},
"tagName": "g",
"attributes": [
{
"type": "Attribute",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"namespace": null,
"prefix": null,
"name": "stroke-width",
"rawName": "stroke-width",
"value": "6",
"rawValue": "\"6\""
}
],
"children": [
{
"type": "Text",
"span": {
"start": 400,
"end": 413,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Element",
"span": {
"start": 413,
"end": 459,
"ctxt": 0
},
"tagName": "path",
"attributes": [
{
"type": "Attribute",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"namespace": null,
"prefix": null,
"name": "d",
"rawName": "d",
"value": "M8,4c-8,9-5,30,17,49",
"rawValue": "\"M8,4c-8,9-5,30,17,49\""
},
{
"type": "Attribute",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"namespace": null,
"prefix": null,
"name": "stroke",
"rawName": "stroke",
"value": "#FD4",
"rawValue": "\"#FD4\""
}
],
"children": []
},
{
"type": "Text",
"span": {
"start": 459,
"end": 472,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Element",
"span": {
"start": 472,
"end": 522,
"ctxt": 0
},
"tagName": "path",
"attributes": [
{
"type": "Attribute",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"namespace": null,
"prefix": null,
"name": "d",
"rawName": "d",
"value": "M79,25c-22-6-32,14-42,26",
"rawValue": "\"M79,25c-22-6-32,14-42,26\""
},
{
"type": "Attribute",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"namespace": null,
"prefix": null,
"name": "stroke",
"rawName": "stroke",
"value": "#D25",
"rawValue": "\"#D25\""
}
],
"children": []
},
{
"type": "Text",
"span": {
"start": 522,
"end": 535,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Element",
"span": {
"start": 535,
"end": 585,
"ctxt": 0
},
"tagName": "path",
"attributes": [
{
"type": "Attribute",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"namespace": null,
"prefix": null,
"name": "d",
"rawName": "d",
"value": "M10,118c23-8,20-30,20-44",
"rawValue": "\"M10,118c23-8,20-30,20-44\""
},
{
"type": "Attribute",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"namespace": null,
"prefix": null,
"name": "stroke",
"rawName": "stroke",
"value": "#8CE",
"rawValue": "\"#8CE\""
}
],
"children": []
},
{
"type": "Text",
"span": {
"start": 585,
"end": 598,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Element",
"span": {
"start": 598,
"end": 650,
"ctxt": 0
},
"tagName": "path",
"attributes": [
{
"type": "Attribute",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"namespace": null,
"prefix": null,
"name": "d",
"rawName": "d",
"value": "M20,48l10,12v13m0-13l10-12",
"rawValue": "\"M20,48l10,12v13m0-13l10-12\""
},
{
"type": "Attribute",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"namespace": null,
"prefix": null,
"name": "stroke",
"rawName": "stroke",
"value": "#FFF",
"rawValue": "\"#FFF\""
}
],
"children": []
},
{
"type": "Text",
"span": {
"start": 650,
"end": 659,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
}
]
},
{
"type": "Text",
"span": {
"start": 663,
"end": 672,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Element",
"span": {
"start": 672,
"end": 741,
"ctxt": 0
},
"tagName": "path",
"attributes": [
{
"type": "Attribute",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"namespace": null,
"prefix": null,
"name": "d",
"rawName": "d",
"value": "M20,48l10,12v13m0-13l10-12",
"rawValue": "\"M20,48l10,12v13m0-13l10-12\""
},
{
"type": "Attribute",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"namespace": null,
"prefix": null,
"name": "stroke-width",
"rawName": "stroke-width",
"value": "5",
"rawValue": "\"5\""
},
{
"type": "Attribute",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"namespace": null,
"prefix": null,
"name": "stroke",
"rawName": "stroke",
"value": "#000",
"rawValue": "\"#000\""
}
],
"children": []
},
{
"type": "Text",
"span": {
"start": 741,
"end": 750,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Element",
"span": {
"start": 750,
"end": 767,
"ctxt": 0
},
"tagName": "text",
"attributes": [],
"children": [
{
"type": "Text",
"span": {
"start": 756,
"end": 760,
"ctxt": 0
},
"data": "Text",
"raw": "Text"
}
]
},
{
"type": "Text",
"span": {
"start": 767,
"end": 772,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
}
]
},
{
"type": "Text",
"span": {
"start": 776,
"end": 777,
"ctxt": 0
},
"data": "\n",
"raw": "\n"
}
]
}
]
}

View File

@ -0,0 +1,495 @@
x Document
,-[$DIR/tests/fixture/basic/input.xml:1:1]
1 | ,-> <?xml version="1.0" encoding="UTF-8"?>
2 | | <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 83 121">
3 | | <!-- test -->
4 | | <g fill="none" stroke-linecap="round">
5 | | <g stroke-width="8">
6 | | <path d="M23,40l2,13l-13-2" stroke="#FD4"/>
7 | | <path d="M36,40l-1,13l13-3" stroke="#D25"/>
8 | | <path d="M23,80l7-11l7,11" stroke="#8CE"/>
9 | | </g>
10 | | <g stroke-width="6">
11 | | <path d="M8,4c-8,9-5,30,17,49" stroke="#FD4"/>
12 | | <path d="M79,25c-22-6-32,14-42,26" stroke="#D25"/>
13 | | <path d="M10,118c23-8,20-30,20-44" stroke="#8CE"/>
14 | | <path d="M20,48l10,12v13m0-13l10-12" stroke="#FFF"/>
15 | | </g>
16 | | <path d="M20,48l10,12v13m0-13l10-12" stroke-width="5" stroke="#000"/>
17 | | <text>Text</text>
18 | | </g>
19 | `-> </svg>
`----
x Child
,-[$DIR/tests/fixture/basic/input.xml:1:1]
1 | <?xml version="1.0" encoding="UTF-8"?>
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x ProcessingInstruction
,-[$DIR/tests/fixture/basic/input.xml:1:1]
1 | <?xml version="1.0" encoding="UTF-8"?>
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x Child
,-[$DIR/tests/fixture/basic/input.xml:2:1]
2 | ,-> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 83 121">
3 | | <!-- test -->
4 | | <g fill="none" stroke-linecap="round">
5 | | <g stroke-width="8">
6 | | <path d="M23,40l2,13l-13-2" stroke="#FD4"/>
7 | | <path d="M36,40l-1,13l13-3" stroke="#D25"/>
8 | | <path d="M23,80l7-11l7,11" stroke="#8CE"/>
9 | | </g>
10 | | <g stroke-width="6">
11 | | <path d="M8,4c-8,9-5,30,17,49" stroke="#FD4"/>
12 | | <path d="M79,25c-22-6-32,14-42,26" stroke="#D25"/>
13 | | <path d="M10,118c23-8,20-30,20-44" stroke="#8CE"/>
14 | | <path d="M20,48l10,12v13m0-13l10-12" stroke="#FFF"/>
15 | | </g>
16 | | <path d="M20,48l10,12v13m0-13l10-12" stroke-width="5" stroke="#000"/>
17 | | <text>Text</text>
18 | | </g>
19 | `-> </svg>
`----
x Element
,-[$DIR/tests/fixture/basic/input.xml:2:1]
2 | ,-> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 83 121">
3 | | <!-- test -->
4 | | <g fill="none" stroke-linecap="round">
5 | | <g stroke-width="8">
6 | | <path d="M23,40l2,13l-13-2" stroke="#FD4"/>
7 | | <path d="M36,40l-1,13l13-3" stroke="#D25"/>
8 | | <path d="M23,80l7-11l7,11" stroke="#8CE"/>
9 | | </g>
10 | | <g stroke-width="6">
11 | | <path d="M8,4c-8,9-5,30,17,49" stroke="#FD4"/>
12 | | <path d="M79,25c-22-6-32,14-42,26" stroke="#D25"/>
13 | | <path d="M10,118c23-8,20-30,20-44" stroke="#8CE"/>
14 | | <path d="M20,48l10,12v13m0-13l10-12" stroke="#FFF"/>
15 | | </g>
16 | | <path d="M20,48l10,12v13m0-13l10-12" stroke-width="5" stroke="#000"/>
17 | | <text>Text</text>
18 | | </g>
19 | `-> </svg>
`----
x Attribute
x Child
,-[$DIR/tests/fixture/basic/input.xml:2:1]
2 | ,-> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 83 121">
3 | `-> <!-- test -->
`----
x Text
,-[$DIR/tests/fixture/basic/input.xml:2:1]
2 | ,-> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 83 121">
3 | `-> <!-- test -->
`----
x Child
,-[$DIR/tests/fixture/basic/input.xml:3:5]
3 | <!-- test -->
: ^^^^^^^^^^^^^
`----
x Comment
,-[$DIR/tests/fixture/basic/input.xml:3:5]
3 | <!-- test -->
: ^^^^^^^^^^^^^
`----
x Child
,-[$DIR/tests/fixture/basic/input.xml:3:5]
3 | ,-> <!-- test -->
4 | `-> <g fill="none" stroke-linecap="round">
`----
x Text
,-[$DIR/tests/fixture/basic/input.xml:3:5]
3 | ,-> <!-- test -->
4 | `-> <g fill="none" stroke-linecap="round">
`----
x Child
,-[$DIR/tests/fixture/basic/input.xml:4:5]
4 | ,-> <g fill="none" stroke-linecap="round">
5 | | <g stroke-width="8">
6 | | <path d="M23,40l2,13l-13-2" stroke="#FD4"/>
7 | | <path d="M36,40l-1,13l13-3" stroke="#D25"/>
8 | | <path d="M23,80l7-11l7,11" stroke="#8CE"/>
9 | | </g>
10 | | <g stroke-width="6">
11 | | <path d="M8,4c-8,9-5,30,17,49" stroke="#FD4"/>
12 | | <path d="M79,25c-22-6-32,14-42,26" stroke="#D25"/>
13 | | <path d="M10,118c23-8,20-30,20-44" stroke="#8CE"/>
14 | | <path d="M20,48l10,12v13m0-13l10-12" stroke="#FFF"/>
15 | | </g>
16 | | <path d="M20,48l10,12v13m0-13l10-12" stroke-width="5" stroke="#000"/>
17 | | <text>Text</text>
18 | `-> </g>
`----
x Element
,-[$DIR/tests/fixture/basic/input.xml:4:5]
4 | ,-> <g fill="none" stroke-linecap="round">
5 | | <g stroke-width="8">
6 | | <path d="M23,40l2,13l-13-2" stroke="#FD4"/>
7 | | <path d="M36,40l-1,13l13-3" stroke="#D25"/>
8 | | <path d="M23,80l7-11l7,11" stroke="#8CE"/>
9 | | </g>
10 | | <g stroke-width="6">
11 | | <path d="M8,4c-8,9-5,30,17,49" stroke="#FD4"/>
12 | | <path d="M79,25c-22-6-32,14-42,26" stroke="#D25"/>
13 | | <path d="M10,118c23-8,20-30,20-44" stroke="#8CE"/>
14 | | <path d="M20,48l10,12v13m0-13l10-12" stroke="#FFF"/>
15 | | </g>
16 | | <path d="M20,48l10,12v13m0-13l10-12" stroke-width="5" stroke="#000"/>
17 | | <text>Text</text>
18 | `-> </g>
`----
x Child
,-[$DIR/tests/fixture/basic/input.xml:4:5]
4 | ,-> <g fill="none" stroke-linecap="round">
5 | `-> <g stroke-width="8">
`----
x Text
,-[$DIR/tests/fixture/basic/input.xml:4:5]
4 | ,-> <g fill="none" stroke-linecap="round">
5 | `-> <g stroke-width="8">
`----
x Child
,-[$DIR/tests/fixture/basic/input.xml:5:9]
5 | ,-> <g stroke-width="8">
6 | | <path d="M23,40l2,13l-13-2" stroke="#FD4"/>
7 | | <path d="M36,40l-1,13l13-3" stroke="#D25"/>
8 | | <path d="M23,80l7-11l7,11" stroke="#8CE"/>
9 | `-> </g>
`----
x Element
,-[$DIR/tests/fixture/basic/input.xml:5:9]
5 | ,-> <g stroke-width="8">
6 | | <path d="M23,40l2,13l-13-2" stroke="#FD4"/>
7 | | <path d="M36,40l-1,13l13-3" stroke="#D25"/>
8 | | <path d="M23,80l7-11l7,11" stroke="#8CE"/>
9 | `-> </g>
`----
x Child
,-[$DIR/tests/fixture/basic/input.xml:5:9]
5 | ,-> <g stroke-width="8">
6 | `-> <path d="M23,40l2,13l-13-2" stroke="#FD4"/>
`----
x Text
,-[$DIR/tests/fixture/basic/input.xml:5:9]
5 | ,-> <g stroke-width="8">
6 | `-> <path d="M23,40l2,13l-13-2" stroke="#FD4"/>
`----
x Child
,-[$DIR/tests/fixture/basic/input.xml:6:13]
6 | <path d="M23,40l2,13l-13-2" stroke="#FD4"/>
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x Element
,-[$DIR/tests/fixture/basic/input.xml:6:13]
6 | <path d="M23,40l2,13l-13-2" stroke="#FD4"/>
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x Child
,-[$DIR/tests/fixture/basic/input.xml:6:13]
6 | ,-> <path d="M23,40l2,13l-13-2" stroke="#FD4"/>
7 | `-> <path d="M36,40l-1,13l13-3" stroke="#D25"/>
`----
x Text
,-[$DIR/tests/fixture/basic/input.xml:6:13]
6 | ,-> <path d="M23,40l2,13l-13-2" stroke="#FD4"/>
7 | `-> <path d="M36,40l-1,13l13-3" stroke="#D25"/>
`----
x Child
,-[$DIR/tests/fixture/basic/input.xml:7:13]
7 | <path d="M36,40l-1,13l13-3" stroke="#D25"/>
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x Element
,-[$DIR/tests/fixture/basic/input.xml:7:13]
7 | <path d="M36,40l-1,13l13-3" stroke="#D25"/>
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x Child
,-[$DIR/tests/fixture/basic/input.xml:7:13]
7 | ,-> <path d="M36,40l-1,13l13-3" stroke="#D25"/>
8 | `-> <path d="M23,80l7-11l7,11" stroke="#8CE"/>
`----
x Text
,-[$DIR/tests/fixture/basic/input.xml:7:13]
7 | ,-> <path d="M36,40l-1,13l13-3" stroke="#D25"/>
8 | `-> <path d="M23,80l7-11l7,11" stroke="#8CE"/>
`----
x Child
,-[$DIR/tests/fixture/basic/input.xml:8:13]
8 | <path d="M23,80l7-11l7,11" stroke="#8CE"/>
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x Element
,-[$DIR/tests/fixture/basic/input.xml:8:13]
8 | <path d="M23,80l7-11l7,11" stroke="#8CE"/>
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x Child
,-[$DIR/tests/fixture/basic/input.xml:8:13]
8 | ,-> <path d="M23,80l7-11l7,11" stroke="#8CE"/>
9 | `-> </g>
`----
x Text
,-[$DIR/tests/fixture/basic/input.xml:8:13]
8 | ,-> <path d="M23,80l7-11l7,11" stroke="#8CE"/>
9 | `-> </g>
`----
x Child
,-[$DIR/tests/fixture/basic/input.xml:9:9]
9 | ,-> </g>
10 | `-> <g stroke-width="6">
`----
x Text
,-[$DIR/tests/fixture/basic/input.xml:9:9]
9 | ,-> </g>
10 | `-> <g stroke-width="6">
`----
x Child
,-[$DIR/tests/fixture/basic/input.xml:10:9]
10 | ,-> <g stroke-width="6">
11 | | <path d="M8,4c-8,9-5,30,17,49" stroke="#FD4"/>
12 | | <path d="M79,25c-22-6-32,14-42,26" stroke="#D25"/>
13 | | <path d="M10,118c23-8,20-30,20-44" stroke="#8CE"/>
14 | | <path d="M20,48l10,12v13m0-13l10-12" stroke="#FFF"/>
15 | `-> </g>
`----
x Element
,-[$DIR/tests/fixture/basic/input.xml:10:9]
10 | ,-> <g stroke-width="6">
11 | | <path d="M8,4c-8,9-5,30,17,49" stroke="#FD4"/>
12 | | <path d="M79,25c-22-6-32,14-42,26" stroke="#D25"/>
13 | | <path d="M10,118c23-8,20-30,20-44" stroke="#8CE"/>
14 | | <path d="M20,48l10,12v13m0-13l10-12" stroke="#FFF"/>
15 | `-> </g>
`----
x Child
,-[$DIR/tests/fixture/basic/input.xml:10:9]
10 | ,-> <g stroke-width="6">
11 | `-> <path d="M8,4c-8,9-5,30,17,49" stroke="#FD4"/>
`----
x Text
,-[$DIR/tests/fixture/basic/input.xml:10:9]
10 | ,-> <g stroke-width="6">
11 | `-> <path d="M8,4c-8,9-5,30,17,49" stroke="#FD4"/>
`----
x Child
,-[$DIR/tests/fixture/basic/input.xml:11:13]
11 | <path d="M8,4c-8,9-5,30,17,49" stroke="#FD4"/>
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x Element
,-[$DIR/tests/fixture/basic/input.xml:11:13]
11 | <path d="M8,4c-8,9-5,30,17,49" stroke="#FD4"/>
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x Child
,-[$DIR/tests/fixture/basic/input.xml:11:13]
11 | ,-> <path d="M8,4c-8,9-5,30,17,49" stroke="#FD4"/>
12 | `-> <path d="M79,25c-22-6-32,14-42,26" stroke="#D25"/>
`----
x Text
,-[$DIR/tests/fixture/basic/input.xml:11:13]
11 | ,-> <path d="M8,4c-8,9-5,30,17,49" stroke="#FD4"/>
12 | `-> <path d="M79,25c-22-6-32,14-42,26" stroke="#D25"/>
`----
x Child
,-[$DIR/tests/fixture/basic/input.xml:12:13]
12 | <path d="M79,25c-22-6-32,14-42,26" stroke="#D25"/>
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x Element
,-[$DIR/tests/fixture/basic/input.xml:12:13]
12 | <path d="M79,25c-22-6-32,14-42,26" stroke="#D25"/>
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x Child
,-[$DIR/tests/fixture/basic/input.xml:12:13]
12 | ,-> <path d="M79,25c-22-6-32,14-42,26" stroke="#D25"/>
13 | `-> <path d="M10,118c23-8,20-30,20-44" stroke="#8CE"/>
`----
x Text
,-[$DIR/tests/fixture/basic/input.xml:12:13]
12 | ,-> <path d="M79,25c-22-6-32,14-42,26" stroke="#D25"/>
13 | `-> <path d="M10,118c23-8,20-30,20-44" stroke="#8CE"/>
`----
x Child
,-[$DIR/tests/fixture/basic/input.xml:13:13]
13 | <path d="M10,118c23-8,20-30,20-44" stroke="#8CE"/>
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x Element
,-[$DIR/tests/fixture/basic/input.xml:13:13]
13 | <path d="M10,118c23-8,20-30,20-44" stroke="#8CE"/>
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x Child
,-[$DIR/tests/fixture/basic/input.xml:13:13]
13 | ,-> <path d="M10,118c23-8,20-30,20-44" stroke="#8CE"/>
14 | `-> <path d="M20,48l10,12v13m0-13l10-12" stroke="#FFF"/>
`----
x Text
,-[$DIR/tests/fixture/basic/input.xml:13:13]
13 | ,-> <path d="M10,118c23-8,20-30,20-44" stroke="#8CE"/>
14 | `-> <path d="M20,48l10,12v13m0-13l10-12" stroke="#FFF"/>
`----
x Child
,-[$DIR/tests/fixture/basic/input.xml:14:13]
14 | <path d="M20,48l10,12v13m0-13l10-12" stroke="#FFF"/>
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x Element
,-[$DIR/tests/fixture/basic/input.xml:14:13]
14 | <path d="M20,48l10,12v13m0-13l10-12" stroke="#FFF"/>
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x Child
,-[$DIR/tests/fixture/basic/input.xml:14:13]
14 | ,-> <path d="M20,48l10,12v13m0-13l10-12" stroke="#FFF"/>
15 | `-> </g>
`----
x Text
,-[$DIR/tests/fixture/basic/input.xml:14:13]
14 | ,-> <path d="M20,48l10,12v13m0-13l10-12" stroke="#FFF"/>
15 | `-> </g>
`----
x Child
,-[$DIR/tests/fixture/basic/input.xml:15:9]
15 | ,-> </g>
16 | `-> <path d="M20,48l10,12v13m0-13l10-12" stroke-width="5" stroke="#000"/>
`----
x Text
,-[$DIR/tests/fixture/basic/input.xml:15:9]
15 | ,-> </g>
16 | `-> <path d="M20,48l10,12v13m0-13l10-12" stroke-width="5" stroke="#000"/>
`----
x Child
,-[$DIR/tests/fixture/basic/input.xml:16:9]
16 | <path d="M20,48l10,12v13m0-13l10-12" stroke-width="5" stroke="#000"/>
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x Element
,-[$DIR/tests/fixture/basic/input.xml:16:9]
16 | <path d="M20,48l10,12v13m0-13l10-12" stroke-width="5" stroke="#000"/>
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x Child
,-[$DIR/tests/fixture/basic/input.xml:16:9]
16 | ,-> <path d="M20,48l10,12v13m0-13l10-12" stroke-width="5" stroke="#000"/>
17 | `-> <text>Text</text>
`----
x Text
,-[$DIR/tests/fixture/basic/input.xml:16:9]
16 | ,-> <path d="M20,48l10,12v13m0-13l10-12" stroke-width="5" stroke="#000"/>
17 | `-> <text>Text</text>
`----
x Child
,-[$DIR/tests/fixture/basic/input.xml:17:9]
17 | <text>Text</text>
: ^^^^^^^^^^^^^^^^^
`----
x Element
,-[$DIR/tests/fixture/basic/input.xml:17:9]
17 | <text>Text</text>
: ^^^^^^^^^^^^^^^^^
`----
x Child
,-[$DIR/tests/fixture/basic/input.xml:17:9]
17 | <text>Text</text>
: ^^^^
`----
x Text
,-[$DIR/tests/fixture/basic/input.xml:17:9]
17 | <text>Text</text>
: ^^^^
`----
x Child
,-[$DIR/tests/fixture/basic/input.xml:17:9]
17 | ,-> <text>Text</text>
18 | `-> </g>
`----
x Text
,-[$DIR/tests/fixture/basic/input.xml:17:9]
17 | ,-> <text>Text</text>
18 | `-> </g>
`----
x Child
,-[$DIR/tests/fixture/basic/input.xml:18:5]
18 | </g>
: ^
19 | </svg>
`----
x Text
,-[$DIR/tests/fixture/basic/input.xml:18:5]
18 | </g>
: ^
19 | </svg>
`----

View File

@ -0,0 +1,24 @@
| <root>
| "
"
| <description>
| "An example of escaped CENDs"
| "
"
| <!-- This text contains a CEND ]]> -->
| "
"
| <!-- In this first case we put the ]] at the end of the first CDATA block
and the > in the second CDATA block -->
| "
"
| <exampleOfACDATA>
| "
Since this is a CDATA section
I can use all sorts of reserved characters
but my document is still well formed!
"
| "
"

View File

@ -0,0 +1,13 @@
<root>
<description>An example of escaped CENDs</description>
<!-- This text contains a CEND ]]> -->
<!-- In this first case we put the ]] at the end of the first CDATA block
and the > in the second CDATA block -->
<exampleOfACDATA>
<![CDATA[
Since this is a CDATA section
I can use all sorts of reserved characters
but my document is still well formed!
]]>
</exampleOfACDATA>
</root>

View File

@ -0,0 +1,136 @@
{
"type": "Document",
"span": {
"start": 1,
"end": 434,
"ctxt": 0
},
"children": [
{
"type": "Element",
"span": {
"start": 1,
"end": 434,
"ctxt": 0
},
"tagName": "root",
"attributes": [],
"children": [
{
"type": "Text",
"span": {
"start": 7,
"end": 12,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Element",
"span": {
"start": 12,
"end": 66,
"ctxt": 0
},
"tagName": "description",
"attributes": [],
"children": [
{
"type": "Text",
"span": {
"start": 25,
"end": 52,
"ctxt": 0
},
"data": "An example of escaped CENDs",
"raw": "An example of escaped CENDs"
}
]
},
{
"type": "Text",
"span": {
"start": 66,
"end": 71,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Comment",
"span": {
"start": 71,
"end": 109,
"ctxt": 0
},
"data": " This text contains a CEND ]]> ",
"raw": "<!-- This text contains a CEND ]]> -->"
},
{
"type": "Text",
"span": {
"start": 109,
"end": 114,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Comment",
"span": {
"start": 114,
"end": 236,
"ctxt": 0
},
"data": " In this first case we put the ]] at the end of the first CDATA block\n and the > in the second CDATA block ",
"raw": "<!-- In this first case we put the ]] at the end of the first CDATA block\n and the > in the second CDATA block -->"
},
{
"type": "Text",
"span": {
"start": 236,
"end": 241,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Element",
"span": {
"start": 241,
"end": 426,
"ctxt": 0
},
"tagName": "exampleOfACDATA",
"attributes": [],
"children": [
{
"type": "Text",
"span": {
"start": 258,
"end": 408,
"ctxt": 0
},
"data": "\n \n Since this is a CDATA section\n I can use all sorts of reserved characters\n but my document is still well formed!\n \n ",
"raw": "\n \n Since this is a CDATA section\n I can use all sorts of reserved characters\n but my document is still well formed!\n \n "
}
]
},
{
"type": "Text",
"span": {
"start": 426,
"end": 427,
"ctxt": 0
},
"data": "\n",
"raw": "\n"
}
]
}
]
}

View File

@ -0,0 +1,205 @@
x Document
,-[$DIR/tests/fixture/cdata/input.xml:1:1]
1 | ,-> <root>
2 | | <description>An example of escaped CENDs</description>
3 | | <!-- This text contains a CEND ]]> -->
4 | | <!-- In this first case we put the ]] at the end of the first CDATA block
5 | | and the > in the second CDATA block -->
6 | | <exampleOfACDATA>
7 | | <![CDATA[
8 | | Since this is a CDATA section
9 | | I can use all sorts of reserved characters
10 | | but my document is still well formed!
11 | | ]]>
12 | | </exampleOfACDATA>
13 | `-> </root>
`----
x Child
,-[$DIR/tests/fixture/cdata/input.xml:1:1]
1 | ,-> <root>
2 | | <description>An example of escaped CENDs</description>
3 | | <!-- This text contains a CEND ]]> -->
4 | | <!-- In this first case we put the ]] at the end of the first CDATA block
5 | | and the > in the second CDATA block -->
6 | | <exampleOfACDATA>
7 | | <![CDATA[
8 | | Since this is a CDATA section
9 | | I can use all sorts of reserved characters
10 | | but my document is still well formed!
11 | | ]]>
12 | | </exampleOfACDATA>
13 | `-> </root>
`----
x Element
,-[$DIR/tests/fixture/cdata/input.xml:1:1]
1 | ,-> <root>
2 | | <description>An example of escaped CENDs</description>
3 | | <!-- This text contains a CEND ]]> -->
4 | | <!-- In this first case we put the ]] at the end of the first CDATA block
5 | | and the > in the second CDATA block -->
6 | | <exampleOfACDATA>
7 | | <![CDATA[
8 | | Since this is a CDATA section
9 | | I can use all sorts of reserved characters
10 | | but my document is still well formed!
11 | | ]]>
12 | | </exampleOfACDATA>
13 | `-> </root>
`----
x Child
,-[$DIR/tests/fixture/cdata/input.xml:1:1]
1 | ,-> <root>
2 | `-> <description>An example of escaped CENDs</description>
`----
x Text
,-[$DIR/tests/fixture/cdata/input.xml:1:1]
1 | ,-> <root>
2 | `-> <description>An example of escaped CENDs</description>
`----
x Child
,-[$DIR/tests/fixture/cdata/input.xml:2:5]
2 | <description>An example of escaped CENDs</description>
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x Element
,-[$DIR/tests/fixture/cdata/input.xml:2:5]
2 | <description>An example of escaped CENDs</description>
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x Child
,-[$DIR/tests/fixture/cdata/input.xml:2:5]
2 | <description>An example of escaped CENDs</description>
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x Text
,-[$DIR/tests/fixture/cdata/input.xml:2:5]
2 | <description>An example of escaped CENDs</description>
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x Child
,-[$DIR/tests/fixture/cdata/input.xml:2:5]
2 | ,-> <description>An example of escaped CENDs</description>
3 | `-> <!-- This text contains a CEND ]]> -->
`----
x Text
,-[$DIR/tests/fixture/cdata/input.xml:2:5]
2 | ,-> <description>An example of escaped CENDs</description>
3 | `-> <!-- This text contains a CEND ]]> -->
`----
x Child
,-[$DIR/tests/fixture/cdata/input.xml:3:5]
3 | <!-- This text contains a CEND ]]> -->
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x Comment
,-[$DIR/tests/fixture/cdata/input.xml:3:5]
3 | <!-- This text contains a CEND ]]> -->
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x Child
,-[$DIR/tests/fixture/cdata/input.xml:3:5]
3 | ,-> <!-- This text contains a CEND ]]> -->
4 | `-> <!-- In this first case we put the ]] at the end of the first CDATA block
`----
x Text
,-[$DIR/tests/fixture/cdata/input.xml:3:5]
3 | ,-> <!-- This text contains a CEND ]]> -->
4 | `-> <!-- In this first case we put the ]] at the end of the first CDATA block
`----
x Child
,-[$DIR/tests/fixture/cdata/input.xml:4:5]
4 | ,-> <!-- In this first case we put the ]] at the end of the first CDATA block
5 | `-> and the > in the second CDATA block -->
`----
x Comment
,-[$DIR/tests/fixture/cdata/input.xml:4:5]
4 | ,-> <!-- In this first case we put the ]] at the end of the first CDATA block
5 | `-> and the > in the second CDATA block -->
`----
x Child
,-[$DIR/tests/fixture/cdata/input.xml:5:10]
5 | ,-> and the > in the second CDATA block -->
6 | `-> <exampleOfACDATA>
`----
x Text
,-[$DIR/tests/fixture/cdata/input.xml:5:10]
5 | ,-> and the > in the second CDATA block -->
6 | `-> <exampleOfACDATA>
`----
x Child
,-[$DIR/tests/fixture/cdata/input.xml:6:5]
6 | ,-> <exampleOfACDATA>
7 | | <![CDATA[
8 | | Since this is a CDATA section
9 | | I can use all sorts of reserved characters
10 | | but my document is still well formed!
11 | | ]]>
12 | `-> </exampleOfACDATA>
`----
x Element
,-[$DIR/tests/fixture/cdata/input.xml:6:5]
6 | ,-> <exampleOfACDATA>
7 | | <![CDATA[
8 | | Since this is a CDATA section
9 | | I can use all sorts of reserved characters
10 | | but my document is still well formed!
11 | | ]]>
12 | `-> </exampleOfACDATA>
`----
x Child
,-[$DIR/tests/fixture/cdata/input.xml:6:5]
6 | ,-> <exampleOfACDATA>
7 | | <![CDATA[
8 | | Since this is a CDATA section
9 | | I can use all sorts of reserved characters
10 | | but my document is still well formed!
11 | | ]]>
12 | `-> </exampleOfACDATA>
`----
x Text
,-[$DIR/tests/fixture/cdata/input.xml:6:5]
6 | ,-> <exampleOfACDATA>
7 | | <![CDATA[
8 | | Since this is a CDATA section
9 | | I can use all sorts of reserved characters
10 | | but my document is still well formed!
11 | | ]]>
12 | `-> </exampleOfACDATA>
`----
x Child
,-[$DIR/tests/fixture/cdata/input.xml:12:5]
12 | </exampleOfACDATA>
: ^
13 | </root>
`----
x Text
,-[$DIR/tests/fixture/cdata/input.xml:12:5]
12 | </exampleOfACDATA>
: ^
13 | </root>
`----

View File

@ -0,0 +1,19 @@
| <root>
| "
"
| <h>
| a="&noti;"
| "
"
| <h>
| a="&lang="
| "
"
| <test>
| test="Ӓ"
| "
"
| <test>
| test="Ē"
| "
"

View File

@ -0,0 +1,6 @@
<root>
<h a='&noti;'/>
<h a='&lang='/>
<test test="&#1234;"></test>
<test test="&#x112;"></test>
</root>

View File

@ -0,0 +1,176 @@
{
"type": "Document",
"span": {
"start": 1,
"end": 121,
"ctxt": 0
},
"children": [
{
"type": "Element",
"span": {
"start": 1,
"end": 121,
"ctxt": 0
},
"tagName": "root",
"attributes": [],
"children": [
{
"type": "Text",
"span": {
"start": 7,
"end": 12,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Element",
"span": {
"start": 12,
"end": 27,
"ctxt": 0
},
"tagName": "h",
"attributes": [
{
"type": "Attribute",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"namespace": null,
"prefix": null,
"name": "a",
"rawName": "a",
"value": "&noti;",
"rawValue": "'&noti;'"
}
],
"children": []
},
{
"type": "Text",
"span": {
"start": 27,
"end": 32,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Element",
"span": {
"start": 32,
"end": 47,
"ctxt": 0
},
"tagName": "h",
"attributes": [
{
"type": "Attribute",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"namespace": null,
"prefix": null,
"name": "a",
"rawName": "a",
"value": "&lang=",
"rawValue": "'&lang='"
}
],
"children": []
},
{
"type": "Text",
"span": {
"start": 47,
"end": 52,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Element",
"span": {
"start": 52,
"end": 80,
"ctxt": 0
},
"tagName": "test",
"attributes": [
{
"type": "Attribute",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"namespace": null,
"prefix": null,
"name": "test",
"rawName": "test",
"value": "Ӓ",
"rawValue": "\"Ӓ\""
}
],
"children": []
},
{
"type": "Text",
"span": {
"start": 80,
"end": 85,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Element",
"span": {
"start": 85,
"end": 113,
"ctxt": 0
},
"tagName": "test",
"attributes": [
{
"type": "Attribute",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"namespace": null,
"prefix": null,
"name": "test",
"rawName": "test",
"value": "Ē",
"rawValue": "\"Ē\""
}
],
"children": []
},
{
"type": "Text",
"span": {
"start": 113,
"end": 114,
"ctxt": 0
},
"data": "\n",
"raw": "\n"
}
]
}
]
}

View File

@ -0,0 +1,142 @@
x Document
,-[$DIR/tests/fixture/entity/input.xml:1:1]
1 | ,-> <root>
2 | | <h a='&noti;'/>
3 | | <h a='&lang='/>
4 | | <test test="&#1234;"></test>
5 | | <test test="&#x112;"></test>
6 | `-> </root>
`----
x Child
,-[$DIR/tests/fixture/entity/input.xml:1:1]
1 | ,-> <root>
2 | | <h a='&noti;'/>
3 | | <h a='&lang='/>
4 | | <test test="&#1234;"></test>
5 | | <test test="&#x112;"></test>
6 | `-> </root>
`----
x Element
,-[$DIR/tests/fixture/entity/input.xml:1:1]
1 | ,-> <root>
2 | | <h a='&noti;'/>
3 | | <h a='&lang='/>
4 | | <test test="&#1234;"></test>
5 | | <test test="&#x112;"></test>
6 | `-> </root>
`----
x Child
,-[$DIR/tests/fixture/entity/input.xml:1:1]
1 | ,-> <root>
2 | `-> <h a='&noti;'/>
`----
x Text
,-[$DIR/tests/fixture/entity/input.xml:1:1]
1 | ,-> <root>
2 | `-> <h a='&noti;'/>
`----
x Child
,-[$DIR/tests/fixture/entity/input.xml:2:5]
2 | <h a='&noti;'/>
: ^^^^^^^^^^^^^^^
`----
x Element
,-[$DIR/tests/fixture/entity/input.xml:2:5]
2 | <h a='&noti;'/>
: ^^^^^^^^^^^^^^^
`----
x Attribute
x Child
,-[$DIR/tests/fixture/entity/input.xml:2:5]
2 | ,-> <h a='&noti;'/>
3 | `-> <h a='&lang='/>
`----
x Text
,-[$DIR/tests/fixture/entity/input.xml:2:5]
2 | ,-> <h a='&noti;'/>
3 | `-> <h a='&lang='/>
`----
x Child
,-[$DIR/tests/fixture/entity/input.xml:3:5]
3 | <h a='&lang='/>
: ^^^^^^^^^^^^^^^
`----
x Element
,-[$DIR/tests/fixture/entity/input.xml:3:5]
3 | <h a='&lang='/>
: ^^^^^^^^^^^^^^^
`----
x Child
,-[$DIR/tests/fixture/entity/input.xml:3:5]
3 | ,-> <h a='&lang='/>
4 | `-> <test test="&#1234;"></test>
`----
x Text
,-[$DIR/tests/fixture/entity/input.xml:3:5]
3 | ,-> <h a='&lang='/>
4 | `-> <test test="&#1234;"></test>
`----
x Child
,-[$DIR/tests/fixture/entity/input.xml:4:5]
4 | <test test="&#1234;"></test>
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x Element
,-[$DIR/tests/fixture/entity/input.xml:4:5]
4 | <test test="&#1234;"></test>
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x Child
,-[$DIR/tests/fixture/entity/input.xml:4:5]
4 | ,-> <test test="&#1234;"></test>
5 | `-> <test test="&#x112;"></test>
`----
x Text
,-[$DIR/tests/fixture/entity/input.xml:4:5]
4 | ,-> <test test="&#1234;"></test>
5 | `-> <test test="&#x112;"></test>
`----
x Child
,-[$DIR/tests/fixture/entity/input.xml:5:5]
5 | <test test="&#x112;"></test>
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x Element
,-[$DIR/tests/fixture/entity/input.xml:5:5]
5 | <test test="&#x112;"></test>
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x Child
,-[$DIR/tests/fixture/entity/input.xml:5:5]
5 | <test test="&#x112;"></test>
: ^
6 | </root>
`----
x Text
,-[$DIR/tests/fixture/entity/input.xml:5:5]
5 | <test test="&#x112;"></test>
: ^
6 | </root>
`----

View File

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8">
| <!-- Generator: Adobe Illustrator 13.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 14948) -->
| <!DOCTYPE svg "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
| <svg>
| enable-background="new 5.5 -3.5 64 64"
| height="64px"
| id="Layer_1"
| version="1.0"
| viewBox="5.5 -3.5 64 64"
| width="64px"
| x="0px"
| xml:space="preserve"
| xmlns="http://www.w3.org/2000/svg"
| xmlns:xlink="http://www.w3.org/1999/xlink"
| y="0px"
| "
"
| <g>
| "
"
| <circle>
| cx="37.637"
| cy="28.806"
| fill="#FFFFFF"
| r="28.276"
| "
"
| <g>
| "
"
| <path>
| d="M37.443-3.5c8.988,0,16.57,3.085,22.742,9.257C66.393,11.967,69.5,19.548,69.5,28.5c0,8.991-3.049,16.476-9.145,22.456 C53.879,57.319,46.242,60.5,37.443,60.5c-8.649,0-16.153-3.144-22.514-9.43C8.644,44.784,5.5,37.262,5.5,28.5 c0-8.761,3.144-16.342,9.429-22.742C21.101-0.415,28.604-3.5,37.443-3.5z M37.557,2.272c-7.276,0-13.428,2.553-18.457,7.657 c-5.22,5.334-7.829,11.525-7.829,18.572c0,7.086,2.59,13.22,7.77,18.398c5.181,5.182,11.352,7.771,18.514,7.771 c7.123,0,13.334-2.607,18.629-7.828c5.029-4.838,7.543-10.952,7.543-18.343c0-7.276-2.553-13.465-7.656-18.571 C50.967,4.824,44.795,2.272,37.557,2.272z M46.129,20.557v13.085h-3.656v15.542h-9.944V33.643h-3.656V20.557 c0-0.572,0.2-1.057,0.599-1.457c0.401-0.399,0.887-0.6,1.457-0.6h13.144c0.533,0,1.01,0.2,1.428,0.6 C45.918,19.5,46.129,19.986,46.129,20.557z M33.042,12.329c0-3.008,1.485-4.514,4.458-4.514s4.457,1.504,4.457,4.514 c0,2.971-1.486,4.457-4.457,4.457S33.042,15.3,33.042,12.329z"
| "
"
| "
"
| "
"

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generator: Adobe Illustrator 13.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 14948) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="64px" height="64px" viewBox="5.5 -3.5 64 64" enable-background="new 5.5 -3.5 64 64" xml:space="preserve">
<g>
<circle fill="#FFFFFF" cx="37.637" cy="28.806" r="28.276"/>
<g>
<path d="M37.443-3.5c8.988,0,16.57,3.085,22.742,9.257C66.393,11.967,69.5,19.548,69.5,28.5c0,8.991-3.049,16.476-9.145,22.456 C53.879,57.319,46.242,60.5,37.443,60.5c-8.649,0-16.153-3.144-22.514-9.43C8.644,44.784,5.5,37.262,5.5,28.5 c0-8.761,3.144-16.342,9.429-22.742C21.101-0.415,28.604-3.5,37.443-3.5z M37.557,2.272c-7.276,0-13.428,2.553-18.457,7.657 c-5.22,5.334-7.829,11.525-7.829,18.572c0,7.086,2.59,13.22,7.77,18.398c5.181,5.182,11.352,7.771,18.514,7.771 c7.123,0,13.334-2.607,18.629-7.828c5.029-4.838,7.543-10.952,7.543-18.343c0-7.276-2.553-13.465-7.656-18.571 C50.967,4.824,44.795,2.272,37.557,2.272z M46.129,20.557v13.085h-3.656v15.542h-9.944V33.643h-3.656V20.557 c0-0.572,0.2-1.057,0.599-1.457c0.401-0.399,0.887-0.6,1.457-0.6h13.144c0.533,0,1.01,0.2,1.428,0.6 C45.918,19.5,46.129,19.986,46.129,20.557z M33.042,12.329c0-3.008,1.485-4.514,4.458-4.514s4.457,1.504,4.457,4.514 c0,2.971-1.486,4.457-4.457,4.457S33.042,15.3,33.042,12.329z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1,397 @@
{
"type": "Document",
"span": {
"start": 1,
"end": 1545,
"ctxt": 0
},
"children": [
{
"type": "ProcessingInstruction",
"span": {
"start": 1,
"end": 39,
"ctxt": 0
},
"target": "xml",
"data": "version=\"1.0\" encoding=\"UTF-8\""
},
{
"type": "Comment",
"span": {
"start": 40,
"end": 138,
"ctxt": 0
},
"data": " Generator: Adobe Illustrator 13.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 14948) ",
"raw": "<!-- Generator: Adobe Illustrator 13.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 14948) -->"
},
{
"type": "DocumentType",
"span": {
"start": 139,
"end": 245,
"ctxt": 0
},
"name": "svg",
"publicId": "-//W3C//DTD SVG 1.0//EN",
"systemId": "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd",
"raw": "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.0//EN\" \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">"
},
{
"type": "Element",
"span": {
"start": 246,
"end": 1544,
"ctxt": 0
},
"tagName": "svg",
"attributes": [
{
"type": "Attribute",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"namespace": null,
"prefix": null,
"name": "version",
"rawName": "version",
"value": "1.0",
"rawValue": "\"1.0\""
},
{
"type": "Attribute",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"namespace": null,
"prefix": null,
"name": "id",
"rawName": "id",
"value": "Layer_1",
"rawValue": "\"Layer_1\""
},
{
"type": "Attribute",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"namespace": null,
"prefix": null,
"name": "xmlns",
"rawName": "xmlns",
"value": "http://www.w3.org/2000/svg",
"rawValue": "\"http://www.w3.org/2000/svg\""
},
{
"type": "Attribute",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"namespace": null,
"prefix": null,
"name": "xmlns:xlink",
"rawName": "xmlns:xlink",
"value": "http://www.w3.org/1999/xlink",
"rawValue": "\"http://www.w3.org/1999/xlink\""
},
{
"type": "Attribute",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"namespace": null,
"prefix": null,
"name": "x",
"rawName": "x",
"value": "0px",
"rawValue": "\"0px\""
},
{
"type": "Attribute",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"namespace": null,
"prefix": null,
"name": "y",
"rawName": "y",
"value": "0px",
"rawValue": "\"0px\""
},
{
"type": "Attribute",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"namespace": null,
"prefix": null,
"name": "width",
"rawName": "width",
"value": "64px",
"rawValue": "\"64px\""
},
{
"type": "Attribute",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"namespace": null,
"prefix": null,
"name": "height",
"rawName": "height",
"value": "64px",
"rawValue": "\"64px\""
},
{
"type": "Attribute",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"namespace": null,
"prefix": null,
"name": "viewBox",
"rawName": "viewBox",
"value": "5.5 -3.5 64 64",
"rawValue": "\"5.5 -3.5 64 64\""
},
{
"type": "Attribute",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"namespace": null,
"prefix": null,
"name": "enable-background",
"rawName": "enable-background",
"value": "new 5.5 -3.5 64 64",
"rawValue": "\"new 5.5 -3.5 64 64\""
},
{
"type": "Attribute",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"namespace": null,
"prefix": null,
"name": "xml:space",
"rawName": "xml:space",
"value": "preserve",
"rawValue": "\"preserve\""
}
],
"children": [
{
"type": "Text",
"span": {
"start": 484,
"end": 485,
"ctxt": 0
},
"data": "\n",
"raw": "\n"
},
{
"type": "Element",
"span": {
"start": 485,
"end": 1537,
"ctxt": 0
},
"tagName": "g",
"attributes": [],
"children": [
{
"type": "Text",
"span": {
"start": 488,
"end": 490,
"ctxt": 0
},
"data": "\n\t",
"raw": "\n\t"
},
{
"type": "Element",
"span": {
"start": 490,
"end": 549,
"ctxt": 0
},
"tagName": "circle",
"attributes": [
{
"type": "Attribute",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"namespace": null,
"prefix": null,
"name": "fill",
"rawName": "fill",
"value": "#FFFFFF",
"rawValue": "\"#FFFFFF\""
},
{
"type": "Attribute",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"namespace": null,
"prefix": null,
"name": "cx",
"rawName": "cx",
"value": "37.637",
"rawValue": "\"37.637\""
},
{
"type": "Attribute",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"namespace": null,
"prefix": null,
"name": "cy",
"rawName": "cy",
"value": "28.806",
"rawValue": "\"28.806\""
},
{
"type": "Attribute",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"namespace": null,
"prefix": null,
"name": "r",
"rawName": "r",
"value": "28.276",
"rawValue": "\"28.276\""
}
],
"children": []
},
{
"type": "Text",
"span": {
"start": 549,
"end": 554,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Element",
"span": {
"start": 554,
"end": 1532,
"ctxt": 0
},
"tagName": "g",
"attributes": [],
"children": [
{
"type": "Text",
"span": {
"start": 557,
"end": 560,
"ctxt": 0
},
"data": "\n\t\t",
"raw": "\n\t\t"
},
{
"type": "Element",
"span": {
"start": 560,
"end": 1526,
"ctxt": 0
},
"tagName": "path",
"attributes": [
{
"type": "Attribute",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"namespace": null,
"prefix": null,
"name": "d",
"rawName": "d",
"value": "M37.443-3.5c8.988,0,16.57,3.085,22.742,9.257C66.393,11.967,69.5,19.548,69.5,28.5c0,8.991-3.049,16.476-9.145,22.456 C53.879,57.319,46.242,60.5,37.443,60.5c-8.649,0-16.153-3.144-22.514-9.43C8.644,44.784,5.5,37.262,5.5,28.5 c0-8.761,3.144-16.342,9.429-22.742C21.101-0.415,28.604-3.5,37.443-3.5z M37.557,2.272c-7.276,0-13.428,2.553-18.457,7.657 c-5.22,5.334-7.829,11.525-7.829,18.572c0,7.086,2.59,13.22,7.77,18.398c5.181,5.182,11.352,7.771,18.514,7.771 c7.123,0,13.334-2.607,18.629-7.828c5.029-4.838,7.543-10.952,7.543-18.343c0-7.276-2.553-13.465-7.656-18.571 C50.967,4.824,44.795,2.272,37.557,2.272z M46.129,20.557v13.085h-3.656v15.542h-9.944V33.643h-3.656V20.557 c0-0.572,0.2-1.057,0.599-1.457c0.401-0.399,0.887-0.6,1.457-0.6h13.144c0.533,0,1.01,0.2,1.428,0.6 C45.918,19.5,46.129,19.986,46.129,20.557z M33.042,12.329c0-3.008,1.485-4.514,4.458-4.514s4.457,1.504,4.457,4.514 c0,2.971-1.486,4.457-4.457,4.457S33.042,15.3,33.042,12.329z",
"rawValue": "\"M37.443-3.5c8.988,0,16.57,3.085,22.742,9.257C66.393,11.967,69.5,19.548,69.5,28.5c0,8.991-3.049,16.476-9.145,22.456 C53.879,57.319,46.242,60.5,37.443,60.5c-8.649,0-16.153-3.144-22.514-9.43C8.644,44.784,5.5,37.262,5.5,28.5 c0-8.761,3.144-16.342,9.429-22.742C21.101-0.415,28.604-3.5,37.443-3.5z M37.557,2.272c-7.276,0-13.428,2.553-18.457,7.657 c-5.22,5.334-7.829,11.525-7.829,18.572c0,7.086,2.59,13.22,7.77,18.398c5.181,5.182,11.352,7.771,18.514,7.771 c7.123,0,13.334-2.607,18.629-7.828c5.029-4.838,7.543-10.952,7.543-18.343c0-7.276-2.553-13.465-7.656-18.571 C50.967,4.824,44.795,2.272,37.557,2.272z M46.129,20.557v13.085h-3.656v15.542h-9.944V33.643h-3.656V20.557 c0-0.572,0.2-1.057,0.599-1.457c0.401-0.399,0.887-0.6,1.457-0.6h13.144c0.533,0,1.01,0.2,1.428,0.6 C45.918,19.5,46.129,19.986,46.129,20.557z M33.042,12.329c0-3.008,1.485-4.514,4.458-4.514s4.457,1.504,4.457,4.514 c0,2.971-1.486,4.457-4.457,4.457S33.042,15.3,33.042,12.329z\""
}
],
"children": []
},
{
"type": "Text",
"span": {
"start": 1526,
"end": 1528,
"ctxt": 0
},
"data": "\n\t",
"raw": "\n\t"
}
]
},
{
"type": "Text",
"span": {
"start": 1532,
"end": 1533,
"ctxt": 0
},
"data": "\n",
"raw": "\n"
}
]
},
{
"type": "Text",
"span": {
"start": 1537,
"end": 1538,
"ctxt": 0
},
"data": "\n",
"raw": "\n"
}
]
}
]
}

View File

@ -0,0 +1,225 @@
x Document
,-[$DIR/tests/fixture/svg/input.xml:1:1]
1 | ,-> <?xml version="1.0" encoding="UTF-8"?>
2 | | <!-- Generator: Adobe Illustrator 13.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 14948) -->
3 | | <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
4 | | <svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="64px" height="64px" viewBox="5.5 -3.5 64 64" enable-background="new 5.5 -3.5 64 64" xml:space="preserve">
5 | | <g>
6 | | <circle fill="#FFFFFF" cx="37.637" cy="28.806" r="28.276"/>
7 | | <g>
8 | | <path d="M37.443-3.5c8.988,0,16.57,3.085,22.742,9.257C66.393,11.967,69.5,19.548,69.5,28.5c0,8.991-3.049,16.476-9.145,22.456 C53.879,57.319,46.242,60.5,37.443,60.5c-8.649,0-16.153-3.144-22.514-9.43C8.644,44.784,5.5,37.262,5.5,28.5 c0-8.761,3.144-16.342,9.429-22.742C21.101-0.415,28.604-3.5,37.443-3.5z M37.557,2.272c-7.276,0-13.428,2.553-18.457,7.657 c-5.22,5.334-7.829,11.525-7.829,18.572c0,7.086,2.59,13.22,7.77,18.398c5.181,5.182,11.352,7.771,18.514,7.771 c7.123,0,13.334-2.607,18.629-7.828c5.029-4.838,7.543-10.952,7.543-18.343c0-7.276-2.553-13.465-7.656-18.571 C50.967,4.824,44.795,2.272,37.557,2.272z M46.129,20.557v13.085h-3.656v15.542h-9.944V33.643h-3.656V20.557 c0-0.572,0.2-1.057,0.599-1.457c0.401-0.399,0.887-0.6,1.457-0.6h13.144c0.533,0,1.01,0.2,1.428,0.6 C45.918,19.5,46.129,19.986,46.129,20.557z M33.042,12.329c0-3.008,1.485-4.514,4.458-4.514s4.457,1.504,4.457,4.514 c0,2.971-1.486,4.457-4.457,4.457S33.042,15.3,33.042,12.329z"/>
9 | | </g>
10 | | </g>
11 | `-> </svg>
`----
x Child
,-[$DIR/tests/fixture/svg/input.xml:1:1]
1 | <?xml version="1.0" encoding="UTF-8"?>
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x ProcessingInstruction
,-[$DIR/tests/fixture/svg/input.xml:1:1]
1 | <?xml version="1.0" encoding="UTF-8"?>
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x Child
,-[$DIR/tests/fixture/svg/input.xml:2:1]
2 | <!-- Generator: Adobe Illustrator 13.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 14948) -->
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x Comment
,-[$DIR/tests/fixture/svg/input.xml:2:1]
2 | <!-- Generator: Adobe Illustrator 13.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 14948) -->
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x Child
,-[$DIR/tests/fixture/svg/input.xml:3:1]
3 | <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x DocumentType
,-[$DIR/tests/fixture/svg/input.xml:3:1]
3 | <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x Child
,-[$DIR/tests/fixture/svg/input.xml:4:1]
4 | ,-> <svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="64px" height="64px" viewBox="5.5 -3.5 64 64" enable-background="new 5.5 -3.5 64 64" xml:space="preserve">
5 | | <g>
6 | | <circle fill="#FFFFFF" cx="37.637" cy="28.806" r="28.276"/>
7 | | <g>
8 | | <path d="M37.443-3.5c8.988,0,16.57,3.085,22.742,9.257C66.393,11.967,69.5,19.548,69.5,28.5c0,8.991-3.049,16.476-9.145,22.456 C53.879,57.319,46.242,60.5,37.443,60.5c-8.649,0-16.153-3.144-22.514-9.43C8.644,44.784,5.5,37.262,5.5,28.5 c0-8.761,3.144-16.342,9.429-22.742C21.101-0.415,28.604-3.5,37.443-3.5z M37.557,2.272c-7.276,0-13.428,2.553-18.457,7.657 c-5.22,5.334-7.829,11.525-7.829,18.572c0,7.086,2.59,13.22,7.77,18.398c5.181,5.182,11.352,7.771,18.514,7.771 c7.123,0,13.334-2.607,18.629-7.828c5.029-4.838,7.543-10.952,7.543-18.343c0-7.276-2.553-13.465-7.656-18.571 C50.967,4.824,44.795,2.272,37.557,2.272z M46.129,20.557v13.085h-3.656v15.542h-9.944V33.643h-3.656V20.557 c0-0.572,0.2-1.057,0.599-1.457c0.401-0.399,0.887-0.6,1.457-0.6h13.144c0.533,0,1.01,0.2,1.428,0.6 C45.918,19.5,46.129,19.986,46.129,20.557z M33.042,12.329c0-3.008,1.485-4.514,4.458-4.514s4.457,1.504,4.457,4.514 c0,2.971-1.486,4.457-4.457,4.457S33.042,15.3,33.042,12.329z"/>
9 | | </g>
10 | | </g>
11 | `-> </svg>
`----
x Element
,-[$DIR/tests/fixture/svg/input.xml:4:1]
4 | ,-> <svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="64px" height="64px" viewBox="5.5 -3.5 64 64" enable-background="new 5.5 -3.5 64 64" xml:space="preserve">
5 | | <g>
6 | | <circle fill="#FFFFFF" cx="37.637" cy="28.806" r="28.276"/>
7 | | <g>
8 | | <path d="M37.443-3.5c8.988,0,16.57,3.085,22.742,9.257C66.393,11.967,69.5,19.548,69.5,28.5c0,8.991-3.049,16.476-9.145,22.456 C53.879,57.319,46.242,60.5,37.443,60.5c-8.649,0-16.153-3.144-22.514-9.43C8.644,44.784,5.5,37.262,5.5,28.5 c0-8.761,3.144-16.342,9.429-22.742C21.101-0.415,28.604-3.5,37.443-3.5z M37.557,2.272c-7.276,0-13.428,2.553-18.457,7.657 c-5.22,5.334-7.829,11.525-7.829,18.572c0,7.086,2.59,13.22,7.77,18.398c5.181,5.182,11.352,7.771,18.514,7.771 c7.123,0,13.334-2.607,18.629-7.828c5.029-4.838,7.543-10.952,7.543-18.343c0-7.276-2.553-13.465-7.656-18.571 C50.967,4.824,44.795,2.272,37.557,2.272z M46.129,20.557v13.085h-3.656v15.542h-9.944V33.643h-3.656V20.557 c0-0.572,0.2-1.057,0.599-1.457c0.401-0.399,0.887-0.6,1.457-0.6h13.144c0.533,0,1.01,0.2,1.428,0.6 C45.918,19.5,46.129,19.986,46.129,20.557z M33.042,12.329c0-3.008,1.485-4.514,4.458-4.514s4.457,1.504,4.457,4.514 c0,2.971-1.486,4.457-4.457,4.457S33.042,15.3,33.042,12.329z"/>
9 | | </g>
10 | | </g>
11 | `-> </svg>
`----
x Attribute
x Child
,-[$DIR/tests/fixture/svg/input.xml:4:1]
4 | <svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="64px" height="64px" viewBox="5.5 -3.5 64 64" enable-background="new 5.5 -3.5 64 64" xml:space="preserve">
: ^
5 | <g>
`----
x Text
,-[$DIR/tests/fixture/svg/input.xml:4:1]
4 | <svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="64px" height="64px" viewBox="5.5 -3.5 64 64" enable-background="new 5.5 -3.5 64 64" xml:space="preserve">
: ^
5 | <g>
`----
x Child
,-[$DIR/tests/fixture/svg/input.xml:5:1]
5 | ,-> <g>
6 | | <circle fill="#FFFFFF" cx="37.637" cy="28.806" r="28.276"/>
7 | | <g>
8 | | <path d="M37.443-3.5c8.988,0,16.57,3.085,22.742,9.257C66.393,11.967,69.5,19.548,69.5,28.5c0,8.991-3.049,16.476-9.145,22.456 C53.879,57.319,46.242,60.5,37.443,60.5c-8.649,0-16.153-3.144-22.514-9.43C8.644,44.784,5.5,37.262,5.5,28.5 c0-8.761,3.144-16.342,9.429-22.742C21.101-0.415,28.604-3.5,37.443-3.5z M37.557,2.272c-7.276,0-13.428,2.553-18.457,7.657 c-5.22,5.334-7.829,11.525-7.829,18.572c0,7.086,2.59,13.22,7.77,18.398c5.181,5.182,11.352,7.771,18.514,7.771 c7.123,0,13.334-2.607,18.629-7.828c5.029-4.838,7.543-10.952,7.543-18.343c0-7.276-2.553-13.465-7.656-18.571 C50.967,4.824,44.795,2.272,37.557,2.272z M46.129,20.557v13.085h-3.656v15.542h-9.944V33.643h-3.656V20.557 c0-0.572,0.2-1.057,0.599-1.457c0.401-0.399,0.887-0.6,1.457-0.6h13.144c0.533,0,1.01,0.2,1.428,0.6 C45.918,19.5,46.129,19.986,46.129,20.557z M33.042,12.329c0-3.008,1.485-4.514,4.458-4.514s4.457,1.504,4.457,4.514 c0,2.971-1.486,4.457-4.457,4.457S33.042,15.3,33.042,12.329z"/>
9 | | </g>
10 | `-> </g>
`----
x Element
,-[$DIR/tests/fixture/svg/input.xml:5:1]
5 | ,-> <g>
6 | | <circle fill="#FFFFFF" cx="37.637" cy="28.806" r="28.276"/>
7 | | <g>
8 | | <path d="M37.443-3.5c8.988,0,16.57,3.085,22.742,9.257C66.393,11.967,69.5,19.548,69.5,28.5c0,8.991-3.049,16.476-9.145,22.456 C53.879,57.319,46.242,60.5,37.443,60.5c-8.649,0-16.153-3.144-22.514-9.43C8.644,44.784,5.5,37.262,5.5,28.5 c0-8.761,3.144-16.342,9.429-22.742C21.101-0.415,28.604-3.5,37.443-3.5z M37.557,2.272c-7.276,0-13.428,2.553-18.457,7.657 c-5.22,5.334-7.829,11.525-7.829,18.572c0,7.086,2.59,13.22,7.77,18.398c5.181,5.182,11.352,7.771,18.514,7.771 c7.123,0,13.334-2.607,18.629-7.828c5.029-4.838,7.543-10.952,7.543-18.343c0-7.276-2.553-13.465-7.656-18.571 C50.967,4.824,44.795,2.272,37.557,2.272z M46.129,20.557v13.085h-3.656v15.542h-9.944V33.643h-3.656V20.557 c0-0.572,0.2-1.057,0.599-1.457c0.401-0.399,0.887-0.6,1.457-0.6h13.144c0.533,0,1.01,0.2,1.428,0.6 C45.918,19.5,46.129,19.986,46.129,20.557z M33.042,12.329c0-3.008,1.485-4.514,4.458-4.514s4.457,1.504,4.457,4.514 c0,2.971-1.486,4.457-4.457,4.457S33.042,15.3,33.042,12.329z"/>
9 | | </g>
10 | `-> </g>
`----
x Child
,-[$DIR/tests/fixture/svg/input.xml:5:1]
5 | ,-> <g>
6 | `-> <circle fill="#FFFFFF" cx="37.637" cy="28.806" r="28.276"/>
`----
x Text
,-[$DIR/tests/fixture/svg/input.xml:5:1]
5 | ,-> <g>
6 | `-> <circle fill="#FFFFFF" cx="37.637" cy="28.806" r="28.276"/>
`----
x Child
,-[$DIR/tests/fixture/svg/input.xml:6:5]
6 | <circle fill="#FFFFFF" cx="37.637" cy="28.806" r="28.276"/>
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x Element
,-[$DIR/tests/fixture/svg/input.xml:6:5]
6 | <circle fill="#FFFFFF" cx="37.637" cy="28.806" r="28.276"/>
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x Child
,-[$DIR/tests/fixture/svg/input.xml:6:5]
6 | ,-> <circle fill="#FFFFFF" cx="37.637" cy="28.806" r="28.276"/>
7 | `-> <g>
`----
x Text
,-[$DIR/tests/fixture/svg/input.xml:6:5]
6 | ,-> <circle fill="#FFFFFF" cx="37.637" cy="28.806" r="28.276"/>
7 | `-> <g>
`----
x Child
,-[$DIR/tests/fixture/svg/input.xml:7:5]
7 | ,-> <g>
8 | | <path d="M37.443-3.5c8.988,0,16.57,3.085,22.742,9.257C66.393,11.967,69.5,19.548,69.5,28.5c0,8.991-3.049,16.476-9.145,22.456 C53.879,57.319,46.242,60.5,37.443,60.5c-8.649,0-16.153-3.144-22.514-9.43C8.644,44.784,5.5,37.262,5.5,28.5 c0-8.761,3.144-16.342,9.429-22.742C21.101-0.415,28.604-3.5,37.443-3.5z M37.557,2.272c-7.276,0-13.428,2.553-18.457,7.657 c-5.22,5.334-7.829,11.525-7.829,18.572c0,7.086,2.59,13.22,7.77,18.398c5.181,5.182,11.352,7.771,18.514,7.771 c7.123,0,13.334-2.607,18.629-7.828c5.029-4.838,7.543-10.952,7.543-18.343c0-7.276-2.553-13.465-7.656-18.571 C50.967,4.824,44.795,2.272,37.557,2.272z M46.129,20.557v13.085h-3.656v15.542h-9.944V33.643h-3.656V20.557 c0-0.572,0.2-1.057,0.599-1.457c0.401-0.399,0.887-0.6,1.457-0.6h13.144c0.533,0,1.01,0.2,1.428,0.6 C45.918,19.5,46.129,19.986,46.129,20.557z M33.042,12.329c0-3.008,1.485-4.514,4.458-4.514s4.457,1.504,4.457,4.514 c0,2.971-1.486,4.457-4.457,4.457S33.042,15.3,33.042,12.329z"/>
9 | `-> </g>
`----
x Element
,-[$DIR/tests/fixture/svg/input.xml:7:5]
7 | ,-> <g>
8 | | <path d="M37.443-3.5c8.988,0,16.57,3.085,22.742,9.257C66.393,11.967,69.5,19.548,69.5,28.5c0,8.991-3.049,16.476-9.145,22.456 C53.879,57.319,46.242,60.5,37.443,60.5c-8.649,0-16.153-3.144-22.514-9.43C8.644,44.784,5.5,37.262,5.5,28.5 c0-8.761,3.144-16.342,9.429-22.742C21.101-0.415,28.604-3.5,37.443-3.5z M37.557,2.272c-7.276,0-13.428,2.553-18.457,7.657 c-5.22,5.334-7.829,11.525-7.829,18.572c0,7.086,2.59,13.22,7.77,18.398c5.181,5.182,11.352,7.771,18.514,7.771 c7.123,0,13.334-2.607,18.629-7.828c5.029-4.838,7.543-10.952,7.543-18.343c0-7.276-2.553-13.465-7.656-18.571 C50.967,4.824,44.795,2.272,37.557,2.272z M46.129,20.557v13.085h-3.656v15.542h-9.944V33.643h-3.656V20.557 c0-0.572,0.2-1.057,0.599-1.457c0.401-0.399,0.887-0.6,1.457-0.6h13.144c0.533,0,1.01,0.2,1.428,0.6 C45.918,19.5,46.129,19.986,46.129,20.557z M33.042,12.329c0-3.008,1.485-4.514,4.458-4.514s4.457,1.504,4.457,4.514 c0,2.971-1.486,4.457-4.457,4.457S33.042,15.3,33.042,12.329z"/>
9 | `-> </g>
`----
x Child
,-[$DIR/tests/fixture/svg/input.xml:7:5]
7 | ,-> <g>
8 | `-> <path d="M37.443-3.5c8.988,0,16.57,3.085,22.742,9.257C66.393,11.967,69.5,19.548,69.5,28.5c0,8.991-3.049,16.476-9.145,22.456 C53.879,57.319,46.242,60.5,37.443,60.5c-8.649,0-16.153-3.144-22.514-9.43C8.644,44.784,5.5,37.262,5.5,28.5 c0-8.761,3.144-16.342,9.429-22.742C21.101-0.415,28.604-3.5,37.443-3.5z M37.557,2.272c-7.276,0-13.428,2.553-18.457,7.657 c-5.22,5.334-7.829,11.525-7.829,18.572c0,7.086,2.59,13.22,7.77,18.398c5.181,5.182,11.352,7.771,18.514,7.771 c7.123,0,13.334-2.607,18.629-7.828c5.029-4.838,7.543-10.952,7.543-18.343c0-7.276-2.553-13.465-7.656-18.571 C50.967,4.824,44.795,2.272,37.557,2.272z M46.129,20.557v13.085h-3.656v15.542h-9.944V33.643h-3.656V20.557 c0-0.572,0.2-1.057,0.599-1.457c0.401-0.399,0.887-0.6,1.457-0.6h13.144c0.533,0,1.01,0.2,1.428,0.6 C45.918,19.5,46.129,19.986,46.129,20.557z M33.042,12.329c0-3.008,1.485-4.514,4.458-4.514s4.457,1.504,4.457,4.514 c0,2.971-1.486,4.457-4.457,4.457S33.042,15.3,33.042,12.329z"/>
`----
x Text
,-[$DIR/tests/fixture/svg/input.xml:7:5]
7 | ,-> <g>
8 | `-> <path d="M37.443-3.5c8.988,0,16.57,3.085,22.742,9.257C66.393,11.967,69.5,19.548,69.5,28.5c0,8.991-3.049,16.476-9.145,22.456 C53.879,57.319,46.242,60.5,37.443,60.5c-8.649,0-16.153-3.144-22.514-9.43C8.644,44.784,5.5,37.262,5.5,28.5 c0-8.761,3.144-16.342,9.429-22.742C21.101-0.415,28.604-3.5,37.443-3.5z M37.557,2.272c-7.276,0-13.428,2.553-18.457,7.657 c-5.22,5.334-7.829,11.525-7.829,18.572c0,7.086,2.59,13.22,7.77,18.398c5.181,5.182,11.352,7.771,18.514,7.771 c7.123,0,13.334-2.607,18.629-7.828c5.029-4.838,7.543-10.952,7.543-18.343c0-7.276-2.553-13.465-7.656-18.571 C50.967,4.824,44.795,2.272,37.557,2.272z M46.129,20.557v13.085h-3.656v15.542h-9.944V33.643h-3.656V20.557 c0-0.572,0.2-1.057,0.599-1.457c0.401-0.399,0.887-0.6,1.457-0.6h13.144c0.533,0,1.01,0.2,1.428,0.6 C45.918,19.5,46.129,19.986,46.129,20.557z M33.042,12.329c0-3.008,1.485-4.514,4.458-4.514s4.457,1.504,4.457,4.514 c0,2.971-1.486,4.457-4.457,4.457S33.042,15.3,33.042,12.329z"/>
`----
x Child
,-[$DIR/tests/fixture/svg/input.xml:8:9]
8 | <path d="M37.443-3.5c8.988,0,16.57,3.085,22.742,9.257C66.393,11.967,69.5,19.548,69.5,28.5c0,8.991-3.049,16.476-9.145,22.456 C53.879,57.319,46.242,60.5,37.443,60.5c-8.649,0-16.153-3.144-22.514-9.43C8.644,44.784,5.5,37.262,5.5,28.5 c0-8.761,3.144-16.342,9.429-22.742C21.101-0.415,28.604-3.5,37.443-3.5z M37.557,2.272c-7.276,0-13.428,2.553-18.457,7.657 c-5.22,5.334-7.829,11.525-7.829,18.572c0,7.086,2.59,13.22,7.77,18.398c5.181,5.182,11.352,7.771,18.514,7.771 c7.123,0,13.334-2.607,18.629-7.828c5.029-4.838,7.543-10.952,7.543-18.343c0-7.276-2.553-13.465-7.656-18.571 C50.967,4.824,44.795,2.272,37.557,2.272z M46.129,20.557v13.085h-3.656v15.542h-9.944V33.643h-3.656V20.557 c0-0.572,0.2-1.057,0.599-1.457c0.401-0.399,0.887-0.6,1.457-0.6h13.144c0.533,0,1.01,0.2,1.428,0.6 C45.918,19.5,46.129,19.986,46.129,20.557z M33.042,12.329c0-3.008,1.485-4.514,4.458-4.514s4.457,1.504,4.457,4.514 c0,2.971-1.486,4.457-4.457,4.457S33.042,15.3,33.042,12.329z"/>
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x Element
,-[$DIR/tests/fixture/svg/input.xml:8:9]
8 | <path d="M37.443-3.5c8.988,0,16.57,3.085,22.742,9.257C66.393,11.967,69.5,19.548,69.5,28.5c0,8.991-3.049,16.476-9.145,22.456 C53.879,57.319,46.242,60.5,37.443,60.5c-8.649,0-16.153-3.144-22.514-9.43C8.644,44.784,5.5,37.262,5.5,28.5 c0-8.761,3.144-16.342,9.429-22.742C21.101-0.415,28.604-3.5,37.443-3.5z M37.557,2.272c-7.276,0-13.428,2.553-18.457,7.657 c-5.22,5.334-7.829,11.525-7.829,18.572c0,7.086,2.59,13.22,7.77,18.398c5.181,5.182,11.352,7.771,18.514,7.771 c7.123,0,13.334-2.607,18.629-7.828c5.029-4.838,7.543-10.952,7.543-18.343c0-7.276-2.553-13.465-7.656-18.571 C50.967,4.824,44.795,2.272,37.557,2.272z M46.129,20.557v13.085h-3.656v15.542h-9.944V33.643h-3.656V20.557 c0-0.572,0.2-1.057,0.599-1.457c0.401-0.399,0.887-0.6,1.457-0.6h13.144c0.533,0,1.01,0.2,1.428,0.6 C45.918,19.5,46.129,19.986,46.129,20.557z M33.042,12.329c0-3.008,1.485-4.514,4.458-4.514s4.457,1.504,4.457,4.514 c0,2.971-1.486,4.457-4.457,4.457S33.042,15.3,33.042,12.329z"/>
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x Child
,-[$DIR/tests/fixture/svg/input.xml:8:9]
8 | ,-> <path d="M37.443-3.5c8.988,0,16.57,3.085,22.742,9.257C66.393,11.967,69.5,19.548,69.5,28.5c0,8.991-3.049,16.476-9.145,22.456 C53.879,57.319,46.242,60.5,37.443,60.5c-8.649,0-16.153-3.144-22.514-9.43C8.644,44.784,5.5,37.262,5.5,28.5 c0-8.761,3.144-16.342,9.429-22.742C21.101-0.415,28.604-3.5,37.443-3.5z M37.557,2.272c-7.276,0-13.428,2.553-18.457,7.657 c-5.22,5.334-7.829,11.525-7.829,18.572c0,7.086,2.59,13.22,7.77,18.398c5.181,5.182,11.352,7.771,18.514,7.771 c7.123,0,13.334-2.607,18.629-7.828c5.029-4.838,7.543-10.952,7.543-18.343c0-7.276-2.553-13.465-7.656-18.571 C50.967,4.824,44.795,2.272,37.557,2.272z M46.129,20.557v13.085h-3.656v15.542h-9.944V33.643h-3.656V20.557 c0-0.572,0.2-1.057,0.599-1.457c0.401-0.399,0.887-0.6,1.457-0.6h13.144c0.533,0,1.01,0.2,1.428,0.6 C45.918,19.5,46.129,19.986,46.129,20.557z M33.042,12.329c0-3.008,1.485-4.514,4.458-4.514s4.457,1.504,4.457,4.514 c0,2.971-1.486,4.457-4.457,4.457S33.042,15.3,33.042,12.329z"/>
9 | `-> </g>
`----
x Text
,-[$DIR/tests/fixture/svg/input.xml:8:9]
8 | ,-> <path d="M37.443-3.5c8.988,0,16.57,3.085,22.742,9.257C66.393,11.967,69.5,19.548,69.5,28.5c0,8.991-3.049,16.476-9.145,22.456 C53.879,57.319,46.242,60.5,37.443,60.5c-8.649,0-16.153-3.144-22.514-9.43C8.644,44.784,5.5,37.262,5.5,28.5 c0-8.761,3.144-16.342,9.429-22.742C21.101-0.415,28.604-3.5,37.443-3.5z M37.557,2.272c-7.276,0-13.428,2.553-18.457,7.657 c-5.22,5.334-7.829,11.525-7.829,18.572c0,7.086,2.59,13.22,7.77,18.398c5.181,5.182,11.352,7.771,18.514,7.771 c7.123,0,13.334-2.607,18.629-7.828c5.029-4.838,7.543-10.952,7.543-18.343c0-7.276-2.553-13.465-7.656-18.571 C50.967,4.824,44.795,2.272,37.557,2.272z M46.129,20.557v13.085h-3.656v15.542h-9.944V33.643h-3.656V20.557 c0-0.572,0.2-1.057,0.599-1.457c0.401-0.399,0.887-0.6,1.457-0.6h13.144c0.533,0,1.01,0.2,1.428,0.6 C45.918,19.5,46.129,19.986,46.129,20.557z M33.042,12.329c0-3.008,1.485-4.514,4.458-4.514s4.457,1.504,4.457,4.514 c0,2.971-1.486,4.457-4.457,4.457S33.042,15.3,33.042,12.329z"/>
9 | `-> </g>
`----
x Child
,-[$DIR/tests/fixture/svg/input.xml:9:5]
9 | </g>
: ^
10 | </g>
`----
x Text
,-[$DIR/tests/fixture/svg/input.xml:9:5]
9 | </g>
: ^
10 | </g>
`----
x Child
,-[$DIR/tests/fixture/svg/input.xml:10:1]
10 | </g>
: ^
11 | </svg>
`----
x Text
,-[$DIR/tests/fixture/svg/input.xml:10:1]
10 | </g>
: ^
11 | </svg>
`----

View File

@ -0,0 +1,30 @@
| <root>
| "
"
| <z>
| <a>
| "
"
| <!-- start tag and end tag -->
| "
"
| <start-tag>
| "Start"
| "
"
| <!-- empty tag -->
| "
"
| <short-tag>
| "
"
| <test>
| "
"
| <!-- short tag -->
| "
"
| <test>
| "
"

View File

@ -0,0 +1,11 @@
<root>
<z></z></><a/>
<!-- start tag and end tag -->
<start-tag>Start</start-tag>
<!-- empty tag -->
<short-tag />
<test></test>
<!-- short tag -->
</>
<test></test>
</root>

View File

@ -0,0 +1,219 @@
{
"type": "Document",
"span": {
"start": 1,
"end": 174,
"ctxt": 0
},
"children": [
{
"type": "Element",
"span": {
"start": 1,
"end": 174,
"ctxt": 0
},
"tagName": "root",
"attributes": [],
"children": [
{
"type": "Text",
"span": {
"start": 7,
"end": 8,
"ctxt": 0
},
"data": "\n",
"raw": "\n"
},
{
"type": "Element",
"span": {
"start": 8,
"end": 15,
"ctxt": 0
},
"tagName": "z",
"attributes": [],
"children": []
},
{
"type": "Element",
"span": {
"start": 15,
"end": 22,
"ctxt": 0
},
"tagName": "a",
"attributes": [],
"children": []
},
{
"type": "Text",
"span": {
"start": 22,
"end": 23,
"ctxt": 0
},
"data": "\n",
"raw": "\n"
},
{
"type": "Comment",
"span": {
"start": 23,
"end": 53,
"ctxt": 0
},
"data": " start tag and end tag ",
"raw": "<!-- start tag and end tag -->"
},
{
"type": "Text",
"span": {
"start": 53,
"end": 54,
"ctxt": 0
},
"data": "\n",
"raw": "\n"
},
{
"type": "Element",
"span": {
"start": 54,
"end": 82,
"ctxt": 0
},
"tagName": "start-tag",
"attributes": [],
"children": [
{
"type": "Text",
"span": {
"start": 65,
"end": 70,
"ctxt": 0
},
"data": "Start",
"raw": "Start"
}
]
},
{
"type": "Text",
"span": {
"start": 82,
"end": 83,
"ctxt": 0
},
"data": "\n",
"raw": "\n"
},
{
"type": "Comment",
"span": {
"start": 83,
"end": 101,
"ctxt": 0
},
"data": " empty tag ",
"raw": "<!-- empty tag -->"
},
{
"type": "Text",
"span": {
"start": 101,
"end": 102,
"ctxt": 0
},
"data": "\n",
"raw": "\n"
},
{
"type": "Element",
"span": {
"start": 102,
"end": 115,
"ctxt": 0
},
"tagName": "short-tag",
"attributes": [],
"children": []
},
{
"type": "Text",
"span": {
"start": 115,
"end": 116,
"ctxt": 0
},
"data": "\n",
"raw": "\n"
},
{
"type": "Element",
"span": {
"start": 116,
"end": 129,
"ctxt": 0
},
"tagName": "test",
"attributes": [],
"children": []
},
{
"type": "Text",
"span": {
"start": 129,
"end": 130,
"ctxt": 0
},
"data": "\n",
"raw": "\n"
},
{
"type": "Comment",
"span": {
"start": 130,
"end": 148,
"ctxt": 0
},
"data": " short tag ",
"raw": "<!-- short tag -->"
},
{
"type": "Text",
"span": {
"start": 148,
"end": 153,
"ctxt": 0
},
"data": "\n\n",
"raw": "\n\n"
},
{
"type": "Element",
"span": {
"start": 153,
"end": 166,
"ctxt": 0
},
"tagName": "test",
"attributes": [],
"children": []
},
{
"type": "Text",
"span": {
"start": 166,
"end": 167,
"ctxt": 0
},
"data": "\n",
"raw": "\n"
}
]
}
]
}

View File

@ -0,0 +1,291 @@
x Document
,-[$DIR/tests/fixture/tags/input.xml:1:1]
1 | ,-> <root>
2 | | <z></z></><a/>
3 | | <!-- start tag and end tag -->
4 | | <start-tag>Start</start-tag>
5 | | <!-- empty tag -->
6 | | <short-tag />
7 | | <test></test>
8 | | <!-- short tag -->
9 | | </>
10 | | <test></test>
11 | `-> </root>
`----
x Child
,-[$DIR/tests/fixture/tags/input.xml:1:1]
1 | ,-> <root>
2 | | <z></z></><a/>
3 | | <!-- start tag and end tag -->
4 | | <start-tag>Start</start-tag>
5 | | <!-- empty tag -->
6 | | <short-tag />
7 | | <test></test>
8 | | <!-- short tag -->
9 | | </>
10 | | <test></test>
11 | `-> </root>
`----
x Element
,-[$DIR/tests/fixture/tags/input.xml:1:1]
1 | ,-> <root>
2 | | <z></z></><a/>
3 | | <!-- start tag and end tag -->
4 | | <start-tag>Start</start-tag>
5 | | <!-- empty tag -->
6 | | <short-tag />
7 | | <test></test>
8 | | <!-- short tag -->
9 | | </>
10 | | <test></test>
11 | `-> </root>
`----
x Child
,-[$DIR/tests/fixture/tags/input.xml:1:1]
1 | <root>
: ^
2 | <z></z></><a/>
`----
x Text
,-[$DIR/tests/fixture/tags/input.xml:1:1]
1 | <root>
: ^
2 | <z></z></><a/>
`----
x Child
,-[$DIR/tests/fixture/tags/input.xml:2:1]
2 | <z></z></><a/>
: ^^^^^^^
`----
x Element
,-[$DIR/tests/fixture/tags/input.xml:2:1]
2 | <z></z></><a/>
: ^^^^^^^
`----
x Child
,-[$DIR/tests/fixture/tags/input.xml:2:1]
2 | <z></z></><a/>
: ^^^^^^^
`----
x Element
,-[$DIR/tests/fixture/tags/input.xml:2:1]
2 | <z></z></><a/>
: ^^^^^^^
`----
x Child
,-[$DIR/tests/fixture/tags/input.xml:2:1]
2 | <z></z></><a/>
: ^
3 | <!-- start tag and end tag -->
`----
x Text
,-[$DIR/tests/fixture/tags/input.xml:2:1]
2 | <z></z></><a/>
: ^
3 | <!-- start tag and end tag -->
`----
x Child
,-[$DIR/tests/fixture/tags/input.xml:3:1]
3 | <!-- start tag and end tag -->
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x Comment
,-[$DIR/tests/fixture/tags/input.xml:3:1]
3 | <!-- start tag and end tag -->
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x Child
,-[$DIR/tests/fixture/tags/input.xml:3:1]
3 | <!-- start tag and end tag -->
: ^
4 | <start-tag>Start</start-tag>
`----
x Text
,-[$DIR/tests/fixture/tags/input.xml:3:1]
3 | <!-- start tag and end tag -->
: ^
4 | <start-tag>Start</start-tag>
`----
x Child
,-[$DIR/tests/fixture/tags/input.xml:4:1]
4 | <start-tag>Start</start-tag>
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x Element
,-[$DIR/tests/fixture/tags/input.xml:4:1]
4 | <start-tag>Start</start-tag>
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x Child
,-[$DIR/tests/fixture/tags/input.xml:4:1]
4 | <start-tag>Start</start-tag>
: ^^^^^
`----
x Text
,-[$DIR/tests/fixture/tags/input.xml:4:1]
4 | <start-tag>Start</start-tag>
: ^^^^^
`----
x Child
,-[$DIR/tests/fixture/tags/input.xml:4:1]
4 | <start-tag>Start</start-tag>
: ^
5 | <!-- empty tag -->
`----
x Text
,-[$DIR/tests/fixture/tags/input.xml:4:1]
4 | <start-tag>Start</start-tag>
: ^
5 | <!-- empty tag -->
`----
x Child
,-[$DIR/tests/fixture/tags/input.xml:5:1]
5 | <!-- empty tag -->
: ^^^^^^^^^^^^^^^^^^
`----
x Comment
,-[$DIR/tests/fixture/tags/input.xml:5:1]
5 | <!-- empty tag -->
: ^^^^^^^^^^^^^^^^^^
`----
x Child
,-[$DIR/tests/fixture/tags/input.xml:5:1]
5 | <!-- empty tag -->
: ^
6 | <short-tag />
`----
x Text
,-[$DIR/tests/fixture/tags/input.xml:5:1]
5 | <!-- empty tag -->
: ^
6 | <short-tag />
`----
x Child
,-[$DIR/tests/fixture/tags/input.xml:6:1]
6 | <short-tag />
: ^^^^^^^^^^^^^
`----
x Element
,-[$DIR/tests/fixture/tags/input.xml:6:1]
6 | <short-tag />
: ^^^^^^^^^^^^^
`----
x Child
,-[$DIR/tests/fixture/tags/input.xml:6:1]
6 | <short-tag />
: ^
7 | <test></test>
`----
x Text
,-[$DIR/tests/fixture/tags/input.xml:6:1]
6 | <short-tag />
: ^
7 | <test></test>
`----
x Child
,-[$DIR/tests/fixture/tags/input.xml:7:1]
7 | <test></test>
: ^^^^^^^^^^^^^
`----
x Element
,-[$DIR/tests/fixture/tags/input.xml:7:1]
7 | <test></test>
: ^^^^^^^^^^^^^
`----
x Child
,-[$DIR/tests/fixture/tags/input.xml:7:1]
7 | <test></test>
: ^
8 | <!-- short tag -->
`----
x Text
,-[$DIR/tests/fixture/tags/input.xml:7:1]
7 | <test></test>
: ^
8 | <!-- short tag -->
`----
x Child
,-[$DIR/tests/fixture/tags/input.xml:8:1]
8 | <!-- short tag -->
: ^^^^^^^^^^^^^^^^^^
`----
x Comment
,-[$DIR/tests/fixture/tags/input.xml:8:1]
8 | <!-- short tag -->
: ^^^^^^^^^^^^^^^^^^
`----
x Child
,-[$DIR/tests/fixture/tags/input.xml:8:1]
8 | ,-> <!-- short tag -->
9 | `-> </>
10 | <test></test>
`----
x Text
,-[$DIR/tests/fixture/tags/input.xml:8:1]
8 | ,-> <!-- short tag -->
9 | `-> </>
10 | <test></test>
`----
x Child
,-[$DIR/tests/fixture/tags/input.xml:10:1]
10 | <test></test>
: ^^^^^^^^^^^^^
`----
x Element
,-[$DIR/tests/fixture/tags/input.xml:10:1]
10 | <test></test>
: ^^^^^^^^^^^^^
`----
x Child
,-[$DIR/tests/fixture/tags/input.xml:10:1]
10 | <test></test>
: ^
11 | </root>
`----
x Text
,-[$DIR/tests/fixture/tags/input.xml:10:1]
10 | <test></test>
: ^
11 | </root>
`----

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8">
| <note>
| "
"
| <to>
| "Tove"
| "
"
| <from>
| "Jani"
| "
"
| <heading>
| "Reminder
"
| <body>
| "Don't forget me this weekend!"
| "
"

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</pheading>
<body>Don't forget me this weekend!</body>
</note>

View File

@ -0,0 +1,160 @@
{
"type": "Document",
"span": {
"start": 1,
"end": 174,
"ctxt": 0
},
"children": [
{
"type": "ProcessingInstruction",
"span": {
"start": 1,
"end": 39,
"ctxt": 0
},
"target": "xml",
"data": "version=\"1.0\" encoding=\"UTF-8\""
},
{
"type": "Element",
"span": {
"start": 40,
"end": 174,
"ctxt": 0
},
"tagName": "note",
"attributes": [],
"children": [
{
"type": "Text",
"span": {
"start": 46,
"end": 51,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Element",
"span": {
"start": 51,
"end": 64,
"ctxt": 0
},
"tagName": "to",
"attributes": [],
"children": [
{
"type": "Text",
"span": {
"start": 55,
"end": 59,
"ctxt": 0
},
"data": "Tove",
"raw": "Tove"
}
]
},
{
"type": "Text",
"span": {
"start": 64,
"end": 69,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Element",
"span": {
"start": 69,
"end": 86,
"ctxt": 0
},
"tagName": "from",
"attributes": [],
"children": [
{
"type": "Text",
"span": {
"start": 75,
"end": 79,
"ctxt": 0
},
"data": "Jani",
"raw": "Jani"
}
]
},
{
"type": "Text",
"span": {
"start": 86,
"end": 91,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Element",
"span": {
"start": 91,
"end": 167,
"ctxt": 0
},
"tagName": "heading",
"attributes": [],
"children": [
{
"type": "Text",
"span": {
"start": 100,
"end": 124,
"ctxt": 0
},
"data": "Reminder\n ",
"raw": "Reminder\n "
},
{
"type": "Element",
"span": {
"start": 124,
"end": 166,
"ctxt": 0
},
"tagName": "body",
"attributes": [],
"children": [
{
"type": "Text",
"span": {
"start": 130,
"end": 159,
"ctxt": 0
},
"data": "Don't forget me this weekend!",
"raw": "Don't forget me this weekend!"
}
]
},
{
"type": "Text",
"span": {
"start": 166,
"end": 167,
"ctxt": 0
},
"data": "\n",
"raw": "\n"
}
]
}
]
}
]
}

View File

@ -0,0 +1,12 @@
x Opening and ending tag mismatch
,-[$DIR/tests/recovery/basic/input.xml:5:5]
5 | <heading>Reminder</pheading>
: ^^^^^^^^^^^
`----
x Opening and ending tag mismatch
,-[$DIR/tests/recovery/basic/input.xml:7:1]
7 | </note>
: ^^^^^^^
`----

View File

@ -0,0 +1,191 @@
x Document
,-[$DIR/tests/recovery/basic/input.xml:1:1]
1 | ,-> <?xml version="1.0" encoding="UTF-8"?>
2 | | <note>
3 | | <to>Tove</to>
4 | | <from>Jani</from>
5 | | <heading>Reminder</pheading>
6 | | <body>Don't forget me this weekend!</body>
7 | `-> </note>
`----
x Child
,-[$DIR/tests/recovery/basic/input.xml:1:1]
1 | <?xml version="1.0" encoding="UTF-8"?>
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x ProcessingInstruction
,-[$DIR/tests/recovery/basic/input.xml:1:1]
1 | <?xml version="1.0" encoding="UTF-8"?>
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x Child
,-[$DIR/tests/recovery/basic/input.xml:2:1]
2 | ,-> <note>
3 | | <to>Tove</to>
4 | | <from>Jani</from>
5 | | <heading>Reminder</pheading>
6 | | <body>Don't forget me this weekend!</body>
7 | `-> </note>
`----
x Element
,-[$DIR/tests/recovery/basic/input.xml:2:1]
2 | ,-> <note>
3 | | <to>Tove</to>
4 | | <from>Jani</from>
5 | | <heading>Reminder</pheading>
6 | | <body>Don't forget me this weekend!</body>
7 | `-> </note>
`----
x Child
,-[$DIR/tests/recovery/basic/input.xml:2:1]
2 | ,-> <note>
3 | `-> <to>Tove</to>
`----
x Text
,-[$DIR/tests/recovery/basic/input.xml:2:1]
2 | ,-> <note>
3 | `-> <to>Tove</to>
`----
x Child
,-[$DIR/tests/recovery/basic/input.xml:3:5]
3 | <to>Tove</to>
: ^^^^^^^^^^^^^
`----
x Element
,-[$DIR/tests/recovery/basic/input.xml:3:5]
3 | <to>Tove</to>
: ^^^^^^^^^^^^^
`----
x Child
,-[$DIR/tests/recovery/basic/input.xml:3:5]
3 | <to>Tove</to>
: ^^^^
`----
x Text
,-[$DIR/tests/recovery/basic/input.xml:3:5]
3 | <to>Tove</to>
: ^^^^
`----
x Child
,-[$DIR/tests/recovery/basic/input.xml:3:5]
3 | ,-> <to>Tove</to>
4 | `-> <from>Jani</from>
`----
x Text
,-[$DIR/tests/recovery/basic/input.xml:3:5]
3 | ,-> <to>Tove</to>
4 | `-> <from>Jani</from>
`----
x Child
,-[$DIR/tests/recovery/basic/input.xml:4:5]
4 | <from>Jani</from>
: ^^^^^^^^^^^^^^^^^
`----
x Element
,-[$DIR/tests/recovery/basic/input.xml:4:5]
4 | <from>Jani</from>
: ^^^^^^^^^^^^^^^^^
`----
x Child
,-[$DIR/tests/recovery/basic/input.xml:4:5]
4 | <from>Jani</from>
: ^^^^
`----
x Text
,-[$DIR/tests/recovery/basic/input.xml:4:5]
4 | <from>Jani</from>
: ^^^^
`----
x Child
,-[$DIR/tests/recovery/basic/input.xml:4:5]
4 | ,-> <from>Jani</from>
5 | `-> <heading>Reminder</pheading>
`----
x Text
,-[$DIR/tests/recovery/basic/input.xml:4:5]
4 | ,-> <from>Jani</from>
5 | `-> <heading>Reminder</pheading>
`----
x Child
,-[$DIR/tests/recovery/basic/input.xml:5:5]
5 | ,-> <heading>Reminder</pheading>
6 | `-> <body>Don't forget me this weekend!</body>
7 | </note>
`----
x Element
,-[$DIR/tests/recovery/basic/input.xml:5:5]
5 | ,-> <heading>Reminder</pheading>
6 | `-> <body>Don't forget me this weekend!</body>
7 | </note>
`----
x Child
,-[$DIR/tests/recovery/basic/input.xml:5:5]
5 | ,-> <heading>Reminder</pheading>
6 | `-> <body>Don't forget me this weekend!</body>
`----
x Text
,-[$DIR/tests/recovery/basic/input.xml:5:5]
5 | ,-> <heading>Reminder</pheading>
6 | `-> <body>Don't forget me this weekend!</body>
`----
x Child
,-[$DIR/tests/recovery/basic/input.xml:6:5]
6 | <body>Don't forget me this weekend!</body>
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x Element
,-[$DIR/tests/recovery/basic/input.xml:6:5]
6 | <body>Don't forget me this weekend!</body>
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x Child
,-[$DIR/tests/recovery/basic/input.xml:6:5]
6 | <body>Don't forget me this weekend!</body>
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x Text
,-[$DIR/tests/recovery/basic/input.xml:6:5]
6 | <body>Don't forget me this weekend!</body>
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x Child
,-[$DIR/tests/recovery/basic/input.xml:6:5]
6 | <body>Don't forget me this weekend!</body>
: ^
7 | </note>
`----
x Text
,-[$DIR/tests/recovery/basic/input.xml:6:5]
6 | <body>Don't forget me this weekend!</body>
: ^
7 | </note>
`----

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8">
| <note>
| "
"
| <to>
| "Tove"
| "
"
| <from>
| "Jani"
| "
"
| <heading>
| foo="bar>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>"

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<note>
<to>Tove</to>
<from>Jani</from>
<heading foo="bar>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>

View File

@ -0,0 +1,132 @@
{
"type": "Document",
"span": {
"start": 1,
"end": 182,
"ctxt": 0
},
"children": [
{
"type": "ProcessingInstruction",
"span": {
"start": 1,
"end": 39,
"ctxt": 0
},
"target": "xml",
"data": "version=\"1.0\" encoding=\"UTF-8\""
},
{
"type": "Element",
"span": {
"start": 40,
"end": 182,
"ctxt": 0
},
"tagName": "note",
"attributes": [],
"children": [
{
"type": "Text",
"span": {
"start": 46,
"end": 51,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Element",
"span": {
"start": 51,
"end": 64,
"ctxt": 0
},
"tagName": "to",
"attributes": [],
"children": [
{
"type": "Text",
"span": {
"start": 55,
"end": 59,
"ctxt": 0
},
"data": "Tove",
"raw": "Tove"
}
]
},
{
"type": "Text",
"span": {
"start": 64,
"end": 69,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Element",
"span": {
"start": 69,
"end": 86,
"ctxt": 0
},
"tagName": "from",
"attributes": [],
"children": [
{
"type": "Text",
"span": {
"start": 75,
"end": 79,
"ctxt": 0
},
"data": "Jani",
"raw": "Jani"
}
]
},
{
"type": "Text",
"span": {
"start": 86,
"end": 91,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Element",
"span": {
"start": 91,
"end": 182,
"ctxt": 0
},
"tagName": "heading",
"attributes": [
{
"type": "Attribute",
"span": {
"start": 0,
"end": 0,
"ctxt": 0
},
"namespace": null,
"prefix": null,
"name": "foo",
"rawName": "foo",
"value": "bar>Reminder</heading>\n <body>Don't forget me this weekend!</body>\n</note>",
"rawValue": "\"bar>Reminder</heading>\n <body>Don't forget me this weekend!</body>\n</note>"
}
],
"children": []
}
]
}
]
}

View File

@ -0,0 +1,12 @@
x Eof in tag
,-[$DIR/tests/recovery/no-quotes/input.xml:7:1]
7 | </note>
: ^
`----
x Unexpected end of file in main phase
,-[$DIR/tests/recovery/no-quotes/input.xml:7:1]
7 | </note>
: ^
`----

View File

@ -0,0 +1,143 @@
x Document
,-[$DIR/tests/recovery/no-quotes/input.xml:1:1]
1 | ,-> <?xml version="1.0" encoding="UTF-8"?>
2 | | <note>
3 | | <to>Tove</to>
4 | | <from>Jani</from>
5 | | <heading foo="bar>Reminder</heading>
6 | | <body>Don't forget me this weekend!</body>
7 | `-> </note>
`----
x Child
,-[$DIR/tests/recovery/no-quotes/input.xml:1:1]
1 | <?xml version="1.0" encoding="UTF-8"?>
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x ProcessingInstruction
,-[$DIR/tests/recovery/no-quotes/input.xml:1:1]
1 | <?xml version="1.0" encoding="UTF-8"?>
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x Child
,-[$DIR/tests/recovery/no-quotes/input.xml:2:1]
2 | ,-> <note>
3 | | <to>Tove</to>
4 | | <from>Jani</from>
5 | | <heading foo="bar>Reminder</heading>
6 | | <body>Don't forget me this weekend!</body>
7 | `-> </note>
`----
x Element
,-[$DIR/tests/recovery/no-quotes/input.xml:2:1]
2 | ,-> <note>
3 | | <to>Tove</to>
4 | | <from>Jani</from>
5 | | <heading foo="bar>Reminder</heading>
6 | | <body>Don't forget me this weekend!</body>
7 | `-> </note>
`----
x Child
,-[$DIR/tests/recovery/no-quotes/input.xml:2:1]
2 | ,-> <note>
3 | `-> <to>Tove</to>
`----
x Text
,-[$DIR/tests/recovery/no-quotes/input.xml:2:1]
2 | ,-> <note>
3 | `-> <to>Tove</to>
`----
x Child
,-[$DIR/tests/recovery/no-quotes/input.xml:3:5]
3 | <to>Tove</to>
: ^^^^^^^^^^^^^
`----
x Element
,-[$DIR/tests/recovery/no-quotes/input.xml:3:5]
3 | <to>Tove</to>
: ^^^^^^^^^^^^^
`----
x Child
,-[$DIR/tests/recovery/no-quotes/input.xml:3:5]
3 | <to>Tove</to>
: ^^^^
`----
x Text
,-[$DIR/tests/recovery/no-quotes/input.xml:3:5]
3 | <to>Tove</to>
: ^^^^
`----
x Child
,-[$DIR/tests/recovery/no-quotes/input.xml:3:5]
3 | ,-> <to>Tove</to>
4 | `-> <from>Jani</from>
`----
x Text
,-[$DIR/tests/recovery/no-quotes/input.xml:3:5]
3 | ,-> <to>Tove</to>
4 | `-> <from>Jani</from>
`----
x Child
,-[$DIR/tests/recovery/no-quotes/input.xml:4:5]
4 | <from>Jani</from>
: ^^^^^^^^^^^^^^^^^
`----
x Element
,-[$DIR/tests/recovery/no-quotes/input.xml:4:5]
4 | <from>Jani</from>
: ^^^^^^^^^^^^^^^^^
`----
x Child
,-[$DIR/tests/recovery/no-quotes/input.xml:4:5]
4 | <from>Jani</from>
: ^^^^
`----
x Text
,-[$DIR/tests/recovery/no-quotes/input.xml:4:5]
4 | <from>Jani</from>
: ^^^^
`----
x Child
,-[$DIR/tests/recovery/no-quotes/input.xml:4:5]
4 | ,-> <from>Jani</from>
5 | `-> <heading foo="bar>Reminder</heading>
`----
x Text
,-[$DIR/tests/recovery/no-quotes/input.xml:4:5]
4 | ,-> <from>Jani</from>
5 | `-> <heading foo="bar>Reminder</heading>
`----
x Child
,-[$DIR/tests/recovery/no-quotes/input.xml:5:5]
5 | ,-> <heading foo="bar>Reminder</heading>
6 | | <body>Don't forget me this weekend!</body>
7 | `-> </note>
`----
x Element
,-[$DIR/tests/recovery/no-quotes/input.xml:5:5]
5 | ,-> <heading foo="bar>Reminder</heading>
6 | | <body>Don't forget me this weekend!</body>
7 | `-> </note>
`----
x Attribute

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8">
| <note>
| "
"
| <to>
| "Tove"
| "
"
| <from>
| "Jani"
| "
"
| <heading>
| "Reminder"
| "
"
| <body>
| "Don't forget me this weekend!"
| "
"

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>a

View File

@ -0,0 +1,170 @@
{
"type": "Document",
"span": {
"start": 1,
"end": 175,
"ctxt": 0
},
"children": [
{
"type": "ProcessingInstruction",
"span": {
"start": 1,
"end": 39,
"ctxt": 0
},
"target": "xml",
"data": "version=\"1.0\" encoding=\"UTF-8\""
},
{
"type": "Element",
"span": {
"start": 40,
"end": 173,
"ctxt": 0
},
"tagName": "note",
"attributes": [],
"children": [
{
"type": "Text",
"span": {
"start": 46,
"end": 51,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Element",
"span": {
"start": 51,
"end": 64,
"ctxt": 0
},
"tagName": "to",
"attributes": [],
"children": [
{
"type": "Text",
"span": {
"start": 55,
"end": 59,
"ctxt": 0
},
"data": "Tove",
"raw": "Tove"
}
]
},
{
"type": "Text",
"span": {
"start": 64,
"end": 69,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Element",
"span": {
"start": 69,
"end": 86,
"ctxt": 0
},
"tagName": "from",
"attributes": [],
"children": [
{
"type": "Text",
"span": {
"start": 75,
"end": 79,
"ctxt": 0
},
"data": "Jani",
"raw": "Jani"
}
]
},
{
"type": "Text",
"span": {
"start": 86,
"end": 91,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Element",
"span": {
"start": 91,
"end": 118,
"ctxt": 0
},
"tagName": "heading",
"attributes": [],
"children": [
{
"type": "Text",
"span": {
"start": 100,
"end": 108,
"ctxt": 0
},
"data": "Reminder",
"raw": "Reminder"
}
]
},
{
"type": "Text",
"span": {
"start": 118,
"end": 123,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Element",
"span": {
"start": 123,
"end": 165,
"ctxt": 0
},
"tagName": "body",
"attributes": [],
"children": [
{
"type": "Text",
"span": {
"start": 129,
"end": 158,
"ctxt": 0
},
"data": "Don't forget me this weekend!",
"raw": "Don't forget me this weekend!"
}
]
},
{
"type": "Text",
"span": {
"start": 165,
"end": 166,
"ctxt": 0
},
"data": "\n",
"raw": "\n"
}
]
}
]
}

View File

@ -0,0 +1,6 @@
x Unexpected character, only whitespace character allowed
,-[$DIR/tests/recovery/non-whitespace-after/input.xml:7:1]
7 | </note>a
: ^
`----

View File

@ -0,0 +1,201 @@
x Document
,-[$DIR/tests/recovery/non-whitespace-after/input.xml:1:1]
1 | ,-> <?xml version="1.0" encoding="UTF-8"?>
2 | | <note>
3 | | <to>Tove</to>
4 | | <from>Jani</from>
5 | | <heading>Reminder</heading>
6 | | <body>Don't forget me this weekend!</body>
7 | `-> </note>a
`----
x Child
,-[$DIR/tests/recovery/non-whitespace-after/input.xml:1:1]
1 | <?xml version="1.0" encoding="UTF-8"?>
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x ProcessingInstruction
,-[$DIR/tests/recovery/non-whitespace-after/input.xml:1:1]
1 | <?xml version="1.0" encoding="UTF-8"?>
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x Child
,-[$DIR/tests/recovery/non-whitespace-after/input.xml:2:1]
2 | ,-> <note>
3 | | <to>Tove</to>
4 | | <from>Jani</from>
5 | | <heading>Reminder</heading>
6 | | <body>Don't forget me this weekend!</body>
7 | `-> </note>a
`----
x Element
,-[$DIR/tests/recovery/non-whitespace-after/input.xml:2:1]
2 | ,-> <note>
3 | | <to>Tove</to>
4 | | <from>Jani</from>
5 | | <heading>Reminder</heading>
6 | | <body>Don't forget me this weekend!</body>
7 | `-> </note>a
`----
x Child
,-[$DIR/tests/recovery/non-whitespace-after/input.xml:2:1]
2 | ,-> <note>
3 | `-> <to>Tove</to>
`----
x Text
,-[$DIR/tests/recovery/non-whitespace-after/input.xml:2:1]
2 | ,-> <note>
3 | `-> <to>Tove</to>
`----
x Child
,-[$DIR/tests/recovery/non-whitespace-after/input.xml:3:5]
3 | <to>Tove</to>
: ^^^^^^^^^^^^^
`----
x Element
,-[$DIR/tests/recovery/non-whitespace-after/input.xml:3:5]
3 | <to>Tove</to>
: ^^^^^^^^^^^^^
`----
x Child
,-[$DIR/tests/recovery/non-whitespace-after/input.xml:3:5]
3 | <to>Tove</to>
: ^^^^
`----
x Text
,-[$DIR/tests/recovery/non-whitespace-after/input.xml:3:5]
3 | <to>Tove</to>
: ^^^^
`----
x Child
,-[$DIR/tests/recovery/non-whitespace-after/input.xml:3:5]
3 | ,-> <to>Tove</to>
4 | `-> <from>Jani</from>
`----
x Text
,-[$DIR/tests/recovery/non-whitespace-after/input.xml:3:5]
3 | ,-> <to>Tove</to>
4 | `-> <from>Jani</from>
`----
x Child
,-[$DIR/tests/recovery/non-whitespace-after/input.xml:4:5]
4 | <from>Jani</from>
: ^^^^^^^^^^^^^^^^^
`----
x Element
,-[$DIR/tests/recovery/non-whitespace-after/input.xml:4:5]
4 | <from>Jani</from>
: ^^^^^^^^^^^^^^^^^
`----
x Child
,-[$DIR/tests/recovery/non-whitespace-after/input.xml:4:5]
4 | <from>Jani</from>
: ^^^^
`----
x Text
,-[$DIR/tests/recovery/non-whitespace-after/input.xml:4:5]
4 | <from>Jani</from>
: ^^^^
`----
x Child
,-[$DIR/tests/recovery/non-whitespace-after/input.xml:4:5]
4 | ,-> <from>Jani</from>
5 | `-> <heading>Reminder</heading>
`----
x Text
,-[$DIR/tests/recovery/non-whitespace-after/input.xml:4:5]
4 | ,-> <from>Jani</from>
5 | `-> <heading>Reminder</heading>
`----
x Child
,-[$DIR/tests/recovery/non-whitespace-after/input.xml:5:5]
5 | <heading>Reminder</heading>
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x Element
,-[$DIR/tests/recovery/non-whitespace-after/input.xml:5:5]
5 | <heading>Reminder</heading>
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x Child
,-[$DIR/tests/recovery/non-whitespace-after/input.xml:5:5]
5 | <heading>Reminder</heading>
: ^^^^^^^^
`----
x Text
,-[$DIR/tests/recovery/non-whitespace-after/input.xml:5:5]
5 | <heading>Reminder</heading>
: ^^^^^^^^
`----
x Child
,-[$DIR/tests/recovery/non-whitespace-after/input.xml:5:5]
5 | ,-> <heading>Reminder</heading>
6 | `-> <body>Don't forget me this weekend!</body>
`----
x Text
,-[$DIR/tests/recovery/non-whitespace-after/input.xml:5:5]
5 | ,-> <heading>Reminder</heading>
6 | `-> <body>Don't forget me this weekend!</body>
`----
x Child
,-[$DIR/tests/recovery/non-whitespace-after/input.xml:6:5]
6 | <body>Don't forget me this weekend!</body>
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x Element
,-[$DIR/tests/recovery/non-whitespace-after/input.xml:6:5]
6 | <body>Don't forget me this weekend!</body>
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x Child
,-[$DIR/tests/recovery/non-whitespace-after/input.xml:6:5]
6 | <body>Don't forget me this weekend!</body>
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x Text
,-[$DIR/tests/recovery/non-whitespace-after/input.xml:6:5]
6 | <body>Don't forget me this weekend!</body>
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x Child
,-[$DIR/tests/recovery/non-whitespace-after/input.xml:6:5]
6 | <body>Don't forget me this weekend!</body>
: ^
7 | </note>a
`----
x Text
,-[$DIR/tests/recovery/non-whitespace-after/input.xml:6:5]
6 | <body>Don't forget me this weekend!</body>
: ^
7 | </note>a
`----

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8">
| <note>
| "
"
| <to>
| "Tove"
| "
"
| <from>
| "Jani"
| "
"
| <heading>
| "Reminder"
| "
"
| <body>
| "Don't forget me this weekend!"
| "
"

View File

@ -0,0 +1,7 @@
a<?xml version="1.0" encoding="UTF-8"?>
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>

View File

@ -0,0 +1,170 @@
{
"type": "Document",
"span": {
"start": 1,
"end": 175,
"ctxt": 0
},
"children": [
{
"type": "ProcessingInstruction",
"span": {
"start": 2,
"end": 40,
"ctxt": 0
},
"target": "xml",
"data": "version=\"1.0\" encoding=\"UTF-8\""
},
{
"type": "Element",
"span": {
"start": 41,
"end": 174,
"ctxt": 0
},
"tagName": "note",
"attributes": [],
"children": [
{
"type": "Text",
"span": {
"start": 47,
"end": 52,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Element",
"span": {
"start": 52,
"end": 65,
"ctxt": 0
},
"tagName": "to",
"attributes": [],
"children": [
{
"type": "Text",
"span": {
"start": 56,
"end": 60,
"ctxt": 0
},
"data": "Tove",
"raw": "Tove"
}
]
},
{
"type": "Text",
"span": {
"start": 65,
"end": 70,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Element",
"span": {
"start": 70,
"end": 87,
"ctxt": 0
},
"tagName": "from",
"attributes": [],
"children": [
{
"type": "Text",
"span": {
"start": 76,
"end": 80,
"ctxt": 0
},
"data": "Jani",
"raw": "Jani"
}
]
},
{
"type": "Text",
"span": {
"start": 87,
"end": 92,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Element",
"span": {
"start": 92,
"end": 119,
"ctxt": 0
},
"tagName": "heading",
"attributes": [],
"children": [
{
"type": "Text",
"span": {
"start": 101,
"end": 109,
"ctxt": 0
},
"data": "Reminder",
"raw": "Reminder"
}
]
},
{
"type": "Text",
"span": {
"start": 119,
"end": 124,
"ctxt": 0
},
"data": "\n ",
"raw": "\n "
},
{
"type": "Element",
"span": {
"start": 124,
"end": 166,
"ctxt": 0
},
"tagName": "body",
"attributes": [],
"children": [
{
"type": "Text",
"span": {
"start": 130,
"end": 159,
"ctxt": 0
},
"data": "Don't forget me this weekend!",
"raw": "Don't forget me this weekend!"
}
]
},
{
"type": "Text",
"span": {
"start": 166,
"end": 167,
"ctxt": 0
},
"data": "\n",
"raw": "\n"
}
]
}
]
}

View File

@ -0,0 +1,6 @@
x Unexpected character, only whitespace character allowed
,-[$DIR/tests/recovery/non-whitespace-before/input.xml:1:1]
1 | a<?xml version="1.0" encoding="UTF-8"?>
: ^
`----

View File

@ -0,0 +1,201 @@
x Document
,-[$DIR/tests/recovery/non-whitespace-before/input.xml:1:1]
1 | ,-> a<?xml version="1.0" encoding="UTF-8"?>
2 | | <note>
3 | | <to>Tove</to>
4 | | <from>Jani</from>
5 | | <heading>Reminder</heading>
6 | | <body>Don't forget me this weekend!</body>
7 | `-> </note>
`----
x Child
,-[$DIR/tests/recovery/non-whitespace-before/input.xml:1:1]
1 | a<?xml version="1.0" encoding="UTF-8"?>
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x ProcessingInstruction
,-[$DIR/tests/recovery/non-whitespace-before/input.xml:1:1]
1 | a<?xml version="1.0" encoding="UTF-8"?>
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x Child
,-[$DIR/tests/recovery/non-whitespace-before/input.xml:2:1]
2 | ,-> <note>
3 | | <to>Tove</to>
4 | | <from>Jani</from>
5 | | <heading>Reminder</heading>
6 | | <body>Don't forget me this weekend!</body>
7 | `-> </note>
`----
x Element
,-[$DIR/tests/recovery/non-whitespace-before/input.xml:2:1]
2 | ,-> <note>
3 | | <to>Tove</to>
4 | | <from>Jani</from>
5 | | <heading>Reminder</heading>
6 | | <body>Don't forget me this weekend!</body>
7 | `-> </note>
`----
x Child
,-[$DIR/tests/recovery/non-whitespace-before/input.xml:2:1]
2 | ,-> <note>
3 | `-> <to>Tove</to>
`----
x Text
,-[$DIR/tests/recovery/non-whitespace-before/input.xml:2:1]
2 | ,-> <note>
3 | `-> <to>Tove</to>
`----
x Child
,-[$DIR/tests/recovery/non-whitespace-before/input.xml:3:5]
3 | <to>Tove</to>
: ^^^^^^^^^^^^^
`----
x Element
,-[$DIR/tests/recovery/non-whitespace-before/input.xml:3:5]
3 | <to>Tove</to>
: ^^^^^^^^^^^^^
`----
x Child
,-[$DIR/tests/recovery/non-whitespace-before/input.xml:3:5]
3 | <to>Tove</to>
: ^^^^
`----
x Text
,-[$DIR/tests/recovery/non-whitespace-before/input.xml:3:5]
3 | <to>Tove</to>
: ^^^^
`----
x Child
,-[$DIR/tests/recovery/non-whitespace-before/input.xml:3:5]
3 | ,-> <to>Tove</to>
4 | `-> <from>Jani</from>
`----
x Text
,-[$DIR/tests/recovery/non-whitespace-before/input.xml:3:5]
3 | ,-> <to>Tove</to>
4 | `-> <from>Jani</from>
`----
x Child
,-[$DIR/tests/recovery/non-whitespace-before/input.xml:4:5]
4 | <from>Jani</from>
: ^^^^^^^^^^^^^^^^^
`----
x Element
,-[$DIR/tests/recovery/non-whitespace-before/input.xml:4:5]
4 | <from>Jani</from>
: ^^^^^^^^^^^^^^^^^
`----
x Child
,-[$DIR/tests/recovery/non-whitespace-before/input.xml:4:5]
4 | <from>Jani</from>
: ^^^^
`----
x Text
,-[$DIR/tests/recovery/non-whitespace-before/input.xml:4:5]
4 | <from>Jani</from>
: ^^^^
`----
x Child
,-[$DIR/tests/recovery/non-whitespace-before/input.xml:4:5]
4 | ,-> <from>Jani</from>
5 | `-> <heading>Reminder</heading>
`----
x Text
,-[$DIR/tests/recovery/non-whitespace-before/input.xml:4:5]
4 | ,-> <from>Jani</from>
5 | `-> <heading>Reminder</heading>
`----
x Child
,-[$DIR/tests/recovery/non-whitespace-before/input.xml:5:5]
5 | <heading>Reminder</heading>
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x Element
,-[$DIR/tests/recovery/non-whitespace-before/input.xml:5:5]
5 | <heading>Reminder</heading>
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x Child
,-[$DIR/tests/recovery/non-whitespace-before/input.xml:5:5]
5 | <heading>Reminder</heading>
: ^^^^^^^^
`----
x Text
,-[$DIR/tests/recovery/non-whitespace-before/input.xml:5:5]
5 | <heading>Reminder</heading>
: ^^^^^^^^
`----
x Child
,-[$DIR/tests/recovery/non-whitespace-before/input.xml:5:5]
5 | ,-> <heading>Reminder</heading>
6 | `-> <body>Don't forget me this weekend!</body>
`----
x Text
,-[$DIR/tests/recovery/non-whitespace-before/input.xml:5:5]
5 | ,-> <heading>Reminder</heading>
6 | `-> <body>Don't forget me this weekend!</body>
`----
x Child
,-[$DIR/tests/recovery/non-whitespace-before/input.xml:6:5]
6 | <body>Don't forget me this weekend!</body>
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x Element
,-[$DIR/tests/recovery/non-whitespace-before/input.xml:6:5]
6 | <body>Don't forget me this weekend!</body>
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x Child
,-[$DIR/tests/recovery/non-whitespace-before/input.xml:6:5]
6 | <body>Don't forget me this weekend!</body>
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x Text
,-[$DIR/tests/recovery/non-whitespace-before/input.xml:6:5]
6 | <body>Don't forget me this weekend!</body>
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
`----
x Child
,-[$DIR/tests/recovery/non-whitespace-before/input.xml:6:5]
6 | <body>Don't forget me this weekend!</body>
: ^
7 | </note>
`----
x Text
,-[$DIR/tests/recovery/non-whitespace-before/input.xml:6:5]
6 | <body>Don't forget me this weekend!</body>
: ^
7 | </note>
`----

View File

@ -0,0 +1,27 @@
[package]
authors = ["강동윤 <kdy1997.dev@gmail.com>", "Alexander Akait <sheo13666q@gmail.com>"]
description = "Visitor for xml"
documentation = "https://rustdoc.swc.rs/swc_xml_visit/"
edition = "2021"
license = "Apache-2.0"
name = "swc_xml_visit"
repository = "https://github.com/swc-project/swc.git"
version = "0.1.0"
[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]
[lib]
bench = false
[features]
default = ["serde"]
path = []
[dependencies]
serde = {version = "1", optional = true}
swc_atoms = {version = "0.3.0", path = "../swc_atoms"}
swc_common = {version = "0.26.0", path = "../swc_common"}
swc_xml_ast = {version = "0.1.0", path = "../swc_xml_ast"}
swc_visit = {version = "0.5.1", path = "../swc_visit"}

View File

@ -0,0 +1,86 @@
#![cfg_attr(docsrs, feature(doc_cfg))]
#![deny(clippy::all)]
#![allow(clippy::ptr_arg)]
use swc_atoms::JsWord;
use swc_common::Span;
use swc_visit::define;
use swc_xml_ast::*;
/// Visitable nodes.
pub trait Node {}
define!({
pub struct Document {
pub span: Span,
pub children: Vec<Child>,
}
pub enum DocumentMode {
NoQuirks,
LimitedQuirks,
Quirks,
}
pub enum Child {
DocumentType(DocumentType),
Element(Element),
Text(Text),
Comment(Comment),
ProcessingInstruction(ProcessingInstruction),
}
pub struct DocumentType {
pub span: Span,
pub name: Option<JsWord>,
pub public_id: Option<JsWord>,
pub system_id: Option<JsWord>,
pub raw: Option<JsWord>,
}
pub enum Namespace {
HTML,
MATHML,
SVG,
XLINK,
XML,
XMLNS,
}
pub struct Element {
pub span: Span,
pub tag_name: JsWord,
pub attributes: Vec<Attribute>,
pub children: Vec<Child>,
}
pub struct Attribute {
pub span: Span,
pub namespace: Option<Namespace>,
pub prefix: Option<JsWord>,
pub name: JsWord,
pub raw_name: Option<JsWord>,
pub value: Option<JsWord>,
pub raw_value: Option<JsWord>,
}
pub struct Text {
pub span: Span,
pub data: JsWord,
pub raw: Option<JsWord>,
}
pub struct ProcessingInstruction {
pub span: Span,
pub target: JsWord,
pub data: JsWord,
}
pub struct Comment {
pub span: Span,
pub data: JsWord,
pub raw: Option<JsWord>,
}
});
impl<T: ?Sized> Node for T {}