selma 0.4.15 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Cargo.lock +145 -179
- data/README.md +1 -0
- data/ext/selma/Cargo.toml +1 -1
- data/ext/selma/src/html/element.rs +68 -15
- data/ext/selma/src/html/end_tag.rs +3 -2
- data/ext/selma/src/html/text_chunk.rs +13 -11
- data/ext/selma/src/html.rs +3 -6
- data/ext/selma/src/lib.rs +7 -4
- data/ext/selma/src/native_ref_wrap.rs +1 -1
- data/ext/selma/src/rewriter.rs +103 -103
- data/ext/selma/src/sanitizer.rs +20 -20
- data/ext/selma/src/selector.rs +15 -15
- data/lib/selma/version.rb +1 -1
- metadata +2 -2
data/ext/selma/Cargo.toml
CHANGED
|
@@ -2,7 +2,7 @@ use std::cell::RefCell;
|
|
|
2
2
|
|
|
3
3
|
use crate::native_ref_wrap::NativeRefWrap;
|
|
4
4
|
use lol_html::html_content::Element;
|
|
5
|
-
use magnus::{
|
|
5
|
+
use magnus::{method, Error, Module, RArray, RClass, RHash, Ruby, Value};
|
|
6
6
|
|
|
7
7
|
struct HTMLElement {
|
|
8
8
|
element: NativeRefWrap<Element<'static, 'static>>,
|
|
@@ -29,7 +29,7 @@ impl SelmaHTMLElement {
|
|
|
29
29
|
match binding.element.get() {
|
|
30
30
|
Ok(e) => Ok(e.tag_name().to_string()),
|
|
31
31
|
Err(_) => Err(Error::new(
|
|
32
|
-
|
|
32
|
+
Ruby::get().unwrap().exception_runtime_error(),
|
|
33
33
|
"`tag_name` is not available",
|
|
34
34
|
)),
|
|
35
35
|
}
|
|
@@ -37,15 +37,19 @@ impl SelmaHTMLElement {
|
|
|
37
37
|
|
|
38
38
|
fn set_tag_name(&self, name: String) -> Result<(), Error> {
|
|
39
39
|
let mut binding = self.0.borrow_mut();
|
|
40
|
+
let ruby = Ruby::get().unwrap();
|
|
40
41
|
|
|
41
42
|
if let Ok(element) = binding.element.get_mut() {
|
|
42
43
|
match element.set_tag_name(&name) {
|
|
43
44
|
Ok(_) => Ok(()),
|
|
44
|
-
Err(err) => Err(Error::new(
|
|
45
|
+
Err(err) => Err(Error::new(
|
|
46
|
+
ruby.exception_runtime_error(),
|
|
47
|
+
format!("{err:?}"),
|
|
48
|
+
)),
|
|
45
49
|
}
|
|
46
50
|
} else {
|
|
47
51
|
Err(Error::new(
|
|
48
|
-
|
|
52
|
+
ruby.exception_runtime_error(),
|
|
49
53
|
"`set_tag_name` is not available",
|
|
50
54
|
))
|
|
51
55
|
}
|
|
@@ -58,7 +62,7 @@ impl SelmaHTMLElement {
|
|
|
58
62
|
Ok(e.is_self_closing())
|
|
59
63
|
} else {
|
|
60
64
|
Err(Error::new(
|
|
61
|
-
|
|
65
|
+
Ruby::get().unwrap().exception_runtime_error(),
|
|
62
66
|
"`is_self_closing` is not available",
|
|
63
67
|
))
|
|
64
68
|
}
|
|
@@ -71,7 +75,7 @@ impl SelmaHTMLElement {
|
|
|
71
75
|
Ok(e.has_attribute(&attr))
|
|
72
76
|
} else {
|
|
73
77
|
Err(Error::new(
|
|
74
|
-
|
|
78
|
+
Ruby::get().unwrap().exception_runtime_error(),
|
|
75
79
|
"`is_self_closing` is not available",
|
|
76
80
|
))
|
|
77
81
|
}
|
|
@@ -85,17 +89,18 @@ impl SelmaHTMLElement {
|
|
|
85
89
|
|
|
86
90
|
fn set_attribute(&self, attr: String, value: String) -> Result<String, Error> {
|
|
87
91
|
let mut binding = self.0.borrow_mut();
|
|
92
|
+
let ruby = Ruby::get().unwrap();
|
|
88
93
|
if let Ok(element) = binding.element.get_mut() {
|
|
89
94
|
match element.set_attribute(&attr, &value) {
|
|
90
95
|
Ok(_) => Ok(value),
|
|
91
96
|
Err(err) => Err(Error::new(
|
|
92
|
-
|
|
97
|
+
ruby.exception_runtime_error(),
|
|
93
98
|
format!("AttributeNameError: {err:?}"),
|
|
94
99
|
)),
|
|
95
100
|
}
|
|
96
101
|
} else {
|
|
97
102
|
Err(Error::new(
|
|
98
|
-
|
|
103
|
+
ruby.exception_runtime_error(),
|
|
99
104
|
"`tag_name` is not available",
|
|
100
105
|
))
|
|
101
106
|
}
|
|
@@ -109,9 +114,51 @@ impl SelmaHTMLElement {
|
|
|
109
114
|
}
|
|
110
115
|
}
|
|
111
116
|
|
|
117
|
+
fn get_attribute_source_location(&self, attr: String) -> Result<Option<RHash>, Error> {
|
|
118
|
+
let binding = self.0.borrow();
|
|
119
|
+
let ruby = Ruby::get().unwrap();
|
|
120
|
+
|
|
121
|
+
let Ok(e) = binding.element.get() else {
|
|
122
|
+
return Ok(None);
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
let lowered = attr.to_lowercase();
|
|
126
|
+
let attrs = e.attributes();
|
|
127
|
+
let Some(attribute) = attrs.iter().find(|a| a.name() == lowered) else {
|
|
128
|
+
return Ok(None);
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
let Some(name_loc) = attribute.name_source_location() else {
|
|
132
|
+
return Ok(None);
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
let hash = ruby.hash_new();
|
|
136
|
+
let name_range = name_loc.bytes();
|
|
137
|
+
hash.aset(
|
|
138
|
+
ruby.to_symbol("name"),
|
|
139
|
+
ruby.range_new(name_range.start, name_range.end, true)?,
|
|
140
|
+
)?;
|
|
141
|
+
|
|
142
|
+
match attribute.value_source_location() {
|
|
143
|
+
Some(loc) => {
|
|
144
|
+
let r = loc.bytes();
|
|
145
|
+
hash.aset(
|
|
146
|
+
ruby.to_symbol("value"),
|
|
147
|
+
ruby.range_new(r.start, r.end, true)?,
|
|
148
|
+
)?;
|
|
149
|
+
}
|
|
150
|
+
None => {
|
|
151
|
+
hash.aset(ruby.to_symbol("value"), ruby.qnil())?;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
Ok(Some(hash))
|
|
156
|
+
}
|
|
157
|
+
|
|
112
158
|
fn get_attributes(&self) -> Result<RHash, Error> {
|
|
113
159
|
let binding = self.0.borrow();
|
|
114
|
-
let
|
|
160
|
+
let ruby = Ruby::get().unwrap();
|
|
161
|
+
let hash = ruby.hash_new();
|
|
115
162
|
|
|
116
163
|
if let Ok(e) = binding.element.get() {
|
|
117
164
|
e.attributes()
|
|
@@ -121,7 +168,7 @@ impl SelmaHTMLElement {
|
|
|
121
168
|
Err(err) => panic!(
|
|
122
169
|
"{:?}",
|
|
123
170
|
Error::new(
|
|
124
|
-
|
|
171
|
+
ruby.exception_runtime_error(),
|
|
125
172
|
format!("AttributeNameError: {err:?}"),
|
|
126
173
|
)
|
|
127
174
|
),
|
|
@@ -132,17 +179,18 @@ impl SelmaHTMLElement {
|
|
|
132
179
|
|
|
133
180
|
fn get_ancestors(&self) -> Result<RArray, Error> {
|
|
134
181
|
let binding = self.0.borrow();
|
|
135
|
-
let
|
|
182
|
+
let ruby = Ruby::get().unwrap();
|
|
183
|
+
let array = ruby.ary_new();
|
|
136
184
|
|
|
137
185
|
binding
|
|
138
186
|
.ancestors
|
|
139
187
|
.iter()
|
|
140
|
-
.for_each(|ancestor| match array.push(
|
|
188
|
+
.for_each(|ancestor| match array.push(ruby.str_new(ancestor)) {
|
|
141
189
|
Ok(_) => {}
|
|
142
190
|
Err(err) => {
|
|
143
191
|
panic!(
|
|
144
192
|
"{:?}",
|
|
145
|
-
Error::new(
|
|
193
|
+
Error::new(ruby.exception_runtime_error(), format!("{err:?}"))
|
|
146
194
|
)
|
|
147
195
|
}
|
|
148
196
|
});
|
|
@@ -244,7 +292,7 @@ impl SelmaHTMLElement {
|
|
|
244
292
|
match binding.element.get() {
|
|
245
293
|
Ok(e) => Ok(e.removed()),
|
|
246
294
|
Err(_) => Err(Error::new(
|
|
247
|
-
|
|
295
|
+
Ruby::get().unwrap().exception_runtime_error(),
|
|
248
296
|
"`is_removed` is not available",
|
|
249
297
|
)),
|
|
250
298
|
}
|
|
@@ -252,8 +300,9 @@ impl SelmaHTMLElement {
|
|
|
252
300
|
}
|
|
253
301
|
|
|
254
302
|
pub fn init(c_html: RClass) -> Result<(), Error> {
|
|
303
|
+
let ruby = Ruby::get().unwrap();
|
|
255
304
|
let c_element = c_html
|
|
256
|
-
.define_class("Element",
|
|
305
|
+
.define_class("Element", ruby.class_object())
|
|
257
306
|
.expect("cannot define class Selma::HTML::Element");
|
|
258
307
|
|
|
259
308
|
c_element.define_method("tag_name", method!(SelmaHTMLElement::tag_name, 0))?;
|
|
@@ -273,6 +322,10 @@ pub fn init(c_html: RClass) -> Result<(), Error> {
|
|
|
273
322
|
method!(SelmaHTMLElement::has_attribute, 1),
|
|
274
323
|
)?;
|
|
275
324
|
c_element.define_method("attributes", method!(SelmaHTMLElement::get_attributes, 0))?;
|
|
325
|
+
c_element.define_method(
|
|
326
|
+
"attribute_source_location",
|
|
327
|
+
method!(SelmaHTMLElement::get_attribute_source_location, 1),
|
|
328
|
+
)?;
|
|
276
329
|
c_element.define_method("ancestors", method!(SelmaHTMLElement::get_ancestors, 0))?;
|
|
277
330
|
|
|
278
331
|
c_element.define_method("before", method!(SelmaHTMLElement::before, -1))?;
|
|
@@ -2,7 +2,7 @@ use std::cell::RefCell;
|
|
|
2
2
|
|
|
3
3
|
use crate::native_ref_wrap::NativeRefWrap;
|
|
4
4
|
use lol_html::html_content::EndTag;
|
|
5
|
-
use magnus::{method, Error, Module, RClass};
|
|
5
|
+
use magnus::{method, Error, Module, RClass, Ruby};
|
|
6
6
|
|
|
7
7
|
struct HTMLEndTag {
|
|
8
8
|
end_tag: NativeRefWrap<EndTag<'static>>,
|
|
@@ -25,8 +25,9 @@ impl SelmaHTMLEndTag {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
pub fn init(c_html: RClass) -> Result<(), Error> {
|
|
28
|
+
let ruby = Ruby::get().unwrap();
|
|
28
29
|
let c_end_tag = c_html
|
|
29
|
-
.define_class("EndTag",
|
|
30
|
+
.define_class("EndTag", ruby.class_object())
|
|
30
31
|
.expect("cannot define class Selma::HTML::EndTag");
|
|
31
32
|
|
|
32
33
|
c_end_tag.define_method("tag_name", method!(SelmaHTMLEndTag::tag_name, 0))?;
|
|
@@ -2,7 +2,7 @@ use std::cell::RefCell;
|
|
|
2
2
|
|
|
3
3
|
use crate::native_ref_wrap::NativeRefWrap;
|
|
4
4
|
use lol_html::html_content::{TextChunk, TextType};
|
|
5
|
-
use magnus::{
|
|
5
|
+
use magnus::{method, Error, Module, RClass, Ruby, Symbol, Value};
|
|
6
6
|
|
|
7
7
|
struct HTMLTextChunk {
|
|
8
8
|
text_chunk: NativeRefWrap<TextChunk<'static>>,
|
|
@@ -49,7 +49,7 @@ impl SelmaHTMLTextChunk {
|
|
|
49
49
|
Ok(tc.as_str().to_string())
|
|
50
50
|
} else {
|
|
51
51
|
Err(Error::new(
|
|
52
|
-
|
|
52
|
+
Ruby::get().unwrap().exception_runtime_error(),
|
|
53
53
|
"`to_s` is not available",
|
|
54
54
|
))
|
|
55
55
|
}
|
|
@@ -57,19 +57,20 @@ impl SelmaHTMLTextChunk {
|
|
|
57
57
|
|
|
58
58
|
fn text_type(&self) -> Result<Symbol, Error> {
|
|
59
59
|
let binding = self.0.borrow();
|
|
60
|
+
let ruby = Ruby::get().unwrap();
|
|
60
61
|
|
|
61
62
|
if let Ok(tc) = binding.text_chunk.get() {
|
|
62
63
|
match tc.text_type() {
|
|
63
|
-
TextType::Data => Ok(
|
|
64
|
-
TextType::PlainText => Ok(
|
|
65
|
-
TextType::RawText => Ok(
|
|
66
|
-
TextType::ScriptData => Ok(
|
|
67
|
-
TextType::RCData => Ok(
|
|
68
|
-
TextType::CDataSection => Ok(
|
|
64
|
+
TextType::Data => Ok(ruby.to_symbol("data")),
|
|
65
|
+
TextType::PlainText => Ok(ruby.to_symbol("plain_text")),
|
|
66
|
+
TextType::RawText => Ok(ruby.to_symbol("raw_text")),
|
|
67
|
+
TextType::ScriptData => Ok(ruby.to_symbol("script")),
|
|
68
|
+
TextType::RCData => Ok(ruby.to_symbol("rc_data")),
|
|
69
|
+
TextType::CDataSection => Ok(ruby.to_symbol("cdata_section")),
|
|
69
70
|
}
|
|
70
71
|
} else {
|
|
71
72
|
Err(Error::new(
|
|
72
|
-
|
|
73
|
+
ruby.exception_runtime_error(),
|
|
73
74
|
"`text_type` is not available",
|
|
74
75
|
))
|
|
75
76
|
}
|
|
@@ -81,7 +82,7 @@ impl SelmaHTMLTextChunk {
|
|
|
81
82
|
match binding.text_chunk.get() {
|
|
82
83
|
Ok(tc) => Ok(tc.removed()),
|
|
83
84
|
Err(_) => Err(Error::new(
|
|
84
|
-
|
|
85
|
+
Ruby::get().unwrap().exception_runtime_error(),
|
|
85
86
|
"`is_removed` is not available",
|
|
86
87
|
)),
|
|
87
88
|
}
|
|
@@ -140,8 +141,9 @@ impl SelmaHTMLTextChunk {
|
|
|
140
141
|
}
|
|
141
142
|
|
|
142
143
|
pub fn init(c_html: RClass) -> Result<(), Error> {
|
|
144
|
+
let ruby = Ruby::get().unwrap();
|
|
143
145
|
let c_text_chunk = c_html
|
|
144
|
-
.define_class("TextChunk",
|
|
146
|
+
.define_class("TextChunk", ruby.class_object())
|
|
145
147
|
.expect("cannot define class Selma::HTML::TextChunk");
|
|
146
148
|
|
|
147
149
|
c_text_chunk.define_method("to_s", method!(SelmaHTMLTextChunk::to_s, 0))?;
|
data/ext/selma/src/html.rs
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
|
-
use magnus::{Error, Module, RModule};
|
|
2
|
-
|
|
3
|
-
#[derive(Clone, Debug)]
|
|
4
|
-
#[magnus::wrap(class = "Selma::HTML")]
|
|
5
|
-
pub(crate) struct SelmaHTML {}
|
|
1
|
+
use magnus::{Error, Module, RModule, Ruby};
|
|
6
2
|
|
|
7
3
|
pub fn init(m_selma: RModule) -> Result<(), Error> {
|
|
4
|
+
let ruby = Ruby::get().unwrap();
|
|
8
5
|
let c_html = m_selma
|
|
9
|
-
.define_class("HTML",
|
|
6
|
+
.define_class("HTML", ruby.class_object())
|
|
10
7
|
.expect("cannot define class Selma::HTML");
|
|
11
8
|
|
|
12
9
|
element::init(c_html).expect("cannot define Selma::HTML::Element class");
|
data/ext/selma/src/lib.rs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
extern crate core;
|
|
2
2
|
|
|
3
3
|
use lol_html::html_content::ContentType;
|
|
4
|
-
use magnus::{
|
|
4
|
+
use magnus::{scan_args, Error, Ruby, Symbol, Value};
|
|
5
5
|
|
|
6
6
|
pub mod html;
|
|
7
7
|
pub mod native_ref_wrap;
|
|
@@ -27,8 +27,9 @@ fn scan_text_args(args: &[Value]) -> Result<(String, ContentType), magnus::Error
|
|
|
27
27
|
} else if as_sym_str == "html" {
|
|
28
28
|
ContentType::Html
|
|
29
29
|
} else {
|
|
30
|
+
let ruby = Ruby::get().unwrap();
|
|
30
31
|
return Err(Error::new(
|
|
31
|
-
|
|
32
|
+
ruby.exception_runtime_error(),
|
|
32
33
|
format!("unknown symbol `{as_sym_str:?}`"),
|
|
33
34
|
));
|
|
34
35
|
};
|
|
@@ -37,8 +38,10 @@ fn scan_text_args(args: &[Value]) -> Result<(String, ContentType), magnus::Error
|
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
#[magnus::init]
|
|
40
|
-
fn init() -> Result<(), Error> {
|
|
41
|
-
let m_selma =
|
|
41
|
+
fn init(ruby: &Ruby) -> Result<(), Error> {
|
|
42
|
+
let m_selma = ruby
|
|
43
|
+
.define_module("Selma")
|
|
44
|
+
.expect("cannot define ::Selma module");
|
|
42
45
|
|
|
43
46
|
sanitizer::init(m_selma).expect("cannot define Selma::Sanitizer class");
|
|
44
47
|
rewriter::init(m_selma).expect("cannot define Selma::Rewriter class");
|
|
@@ -39,7 +39,7 @@ pub struct NativeRefWrap<R> {
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
impl<R> NativeRefWrap<R> {
|
|
42
|
-
pub fn wrap<I>(inner: &mut I) -> (Self, Anchor) {
|
|
42
|
+
pub fn wrap<I>(inner: &mut I) -> (Self, Anchor<'_>) {
|
|
43
43
|
let wrap = NativeRefWrap {
|
|
44
44
|
inner_ptr: inner as *mut I as *mut R,
|
|
45
45
|
poisoned: Arc::new(Mutex::new(false)),
|