svg_conform 0.2.0 → 0.2.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/config/profiles/metanorma.yml +14 -14
- data/docs/profiles.adoc +30 -0
- data/docs/requirements.adoc +55 -0
- data/lib/svg_conform/version.rb +1 -1
- data/spec/svg_conform/requirements/allowed_elements_requirement_spec.rb +120 -0
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 136c672fbb6005495a240d2d8b7f30000fae008cd16fff6bfe51a74e7dbe2262
|
|
4
|
+
data.tar.gz: 679452859b709b2e9ef78916918ea9e58040ebfb382291b8c6543b9062a5ee09
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 26a32728202834b61e892d78ef87bb6bae0030e768414985cfe0bfa208da9fa21828035fe6f247225c6cd37a299dff6fe91863c70137c528d7e24a9aade3250e
|
|
7
|
+
data.tar.gz: 47b4ba1d348244438817269403a2b5b09019687024849e691ff6fe4dcbb9d4fed1a322f132758af38f8ba1310fb0666cc5d9dbaeef93192a8edaf19df66bb1c9
|
|
@@ -21,7 +21,7 @@ requirements:
|
|
|
21
21
|
element_configs:
|
|
22
22
|
# Direct encoding from svgcheck word_properties.py elements dictionary
|
|
23
23
|
- tag: "svg"
|
|
24
|
-
attributes: ["version", "baseProfile", "width", "viewBox", "preserveAspectRatio", "snapshotTime", "height", "id", "role", "break", "color-rendering", "fill-rule", "overflow", "data-name"]
|
|
24
|
+
attributes: ["version", "baseProfile", "width", "viewBox", "preserveAspectRatio", "snapshotTime", "height", "id", "role", "break", "color-rendering", "fill-rule", "overflow", "data-name", "clip-path", "mask"]
|
|
25
25
|
required_attributes: ["version", "baseProfile"]
|
|
26
26
|
attribute_values:
|
|
27
27
|
version: ["1.2"]
|
|
@@ -34,37 +34,37 @@ requirements:
|
|
|
34
34
|
attributes: ["id", "role", "shape-rendering", "text-rendering", "buffered-rendering", "visibility", "base", "lang", "class", "rel", "rev", "typeof", "content", "datatype", "resource", "about", "property", "space", "fill-rule"]
|
|
35
35
|
allowed_children: ["text"]
|
|
36
36
|
- tag: "path"
|
|
37
|
-
attributes: ["d", "pathLength", "stroke-miterlimit", "id", "role", "fill", "style", "transform", "font-size", "fill-rule", "base", "lang", "class", "rel", "rev", "typeof", "content", "datatype", "resource", "about", "property", "space"]
|
|
37
|
+
attributes: ["d", "pathLength", "stroke-miterlimit", "id", "role", "fill", "style", "transform", "font-size", "fill-rule", "base", "lang", "class", "rel", "rev", "typeof", "content", "datatype", "resource", "about", "property", "space", "clip-path", "mask"]
|
|
38
38
|
allowed_children: ["title", "desc"]
|
|
39
39
|
- tag: "rect"
|
|
40
|
-
attributes: ["x", "y", "width", "height", "rx", "ry", "stroke-miterlimit", "id", "role", "fill", "style", "transform", "fill-rule", "base", "lang", "class", "rel", "rev", "typeof", "content", "datatype", "resource", "about", "property", "space"]
|
|
40
|
+
attributes: ["x", "y", "width", "height", "rx", "ry", "stroke-miterlimit", "id", "role", "fill", "style", "transform", "fill-rule", "base", "lang", "class", "rel", "rev", "typeof", "content", "datatype", "resource", "about", "property", "space", "clip-path", "mask"]
|
|
41
41
|
allowed_children: ["title", "desc"]
|
|
42
42
|
- tag: "circle"
|
|
43
|
-
attributes: ["cx", "cy", "r", "id", "role", "fill", "style", "transform", "fill-rule", "base", "lang", "class", "rel", "rev", "typeof", "content", "datatype", "resource", "about", "property", "space"]
|
|
43
|
+
attributes: ["cx", "cy", "r", "id", "role", "fill", "style", "transform", "fill-rule", "base", "lang", "class", "rel", "rev", "typeof", "content", "datatype", "resource", "about", "property", "space", "clip-path", "mask"]
|
|
44
44
|
allowed_children: ["title", "desc"]
|
|
45
45
|
- tag: "line"
|
|
46
|
-
attributes: ["x1", "y1", "x2", "y2", "id", "role", "fill", "transform", "fill-rule", "base", "lang", "class", "rel", "rev", "typeof", "content", "datatype", "resource", "about", "property", "space"]
|
|
46
|
+
attributes: ["x1", "y1", "x2", "y2", "id", "role", "fill", "transform", "fill-rule", "base", "lang", "class", "rel", "rev", "typeof", "content", "datatype", "resource", "about", "property", "space", "clip-path", "mask"]
|
|
47
47
|
allowed_children: ["title", "desc"]
|
|
48
48
|
- tag: "ellipse"
|
|
49
|
-
attributes: ["cx", "cy", "rx", "ry", "id", "role", "fill", "style", "transform", "fill-rule", "base", "lang", "class", "rel", "rev", "typeof", "content", "datatype", "resource", "about", "property", "space"]
|
|
49
|
+
attributes: ["cx", "cy", "rx", "ry", "id", "role", "fill", "style", "transform", "fill-rule", "base", "lang", "class", "rel", "rev", "typeof", "content", "datatype", "resource", "about", "property", "space", "clip-path", "mask"]
|
|
50
50
|
allowed_children: ["title", "desc"]
|
|
51
51
|
- tag: "polyline"
|
|
52
|
-
attributes: ["points", "id", "role", "fill", "transform", "fill-rule", "base", "lang", "class", "rel", "rev", "typeof", "content", "datatype", "resource", "about", "property", "space"]
|
|
52
|
+
attributes: ["points", "id", "role", "fill", "transform", "fill-rule", "base", "lang", "class", "rel", "rev", "typeof", "content", "datatype", "resource", "about", "property", "space", "clip-path", "mask"]
|
|
53
53
|
allowed_children: ["title", "desc"]
|
|
54
54
|
- tag: "polygon"
|
|
55
|
-
attributes: ["points", "id", "role", "fill", "style", "transform", "fill-rule", "base", "lang", "class", "rel", "rev", "typeof", "content", "datatype", "resource", "about", "property", "space"]
|
|
55
|
+
attributes: ["points", "id", "role", "fill", "style", "transform", "fill-rule", "base", "lang", "class", "rel", "rev", "typeof", "content", "datatype", "resource", "about", "property", "space", "clip-path", "mask"]
|
|
56
56
|
allowed_children: ["title", "desc"]
|
|
57
57
|
- tag: "solidColor"
|
|
58
|
-
attributes: ["id", "role", "fill", "fill-rule", "base", "lang", "class", "rel", "rev", "typeof", "content", "datatype", "resource", "about", "property", "space"]
|
|
58
|
+
attributes: ["id", "role", "fill", "fill-rule", "base", "lang", "class", "rel", "rev", "typeof", "content", "datatype", "resource", "about", "property", "space", "clip-path", "mask"]
|
|
59
59
|
allowed_children: ["title", "desc"]
|
|
60
60
|
- tag: "textArea"
|
|
61
|
-
attributes: ["x", "y", "width", "height", "auto", "id", "role", "fill", "transform", "fill-rule", "base", "lang", "class", "rel", "rev", "typeof", "content", "datatype", "resource", "about", "property", "space"]
|
|
61
|
+
attributes: ["x", "y", "width", "height", "auto", "id", "role", "fill", "transform", "fill-rule", "base", "lang", "class", "rel", "rev", "typeof", "content", "datatype", "resource", "about", "property", "space", "clip-path", "mask"]
|
|
62
62
|
allowed_children: ["desc", "title", "tspan", "text", "a"]
|
|
63
63
|
- tag: "text"
|
|
64
|
-
attributes: ["x", "y", "rotate", "id", "role", "fill", "style", "transform", "font-size", "fill-rule", "base", "lang", "class", "rel", "rev", "typeof", "content", "datatype", "resource", "about", "property", "space", "font-stretch", "writing-mode", "text-decoration"]
|
|
64
|
+
attributes: ["x", "y", "rotate", "id", "role", "fill", "style", "transform", "font-size", "fill-rule", "base", "lang", "class", "rel", "rev", "typeof", "content", "datatype", "resource", "about", "property", "space", "font-stretch", "writing-mode", "text-decoration", "clip-path", "mask"]
|
|
65
65
|
allowed_children: ["desc", "title", "tspan", "text", "a"]
|
|
66
66
|
- tag: "g"
|
|
67
|
-
attributes: ["label", "class", "id", "role", "fill", "style", "transform", "fill-rule", "visibility", "base", "lang", "rel", "rev", "typeof", "content", "datatype", "resource", "about", "property", "space", "data-name"]
|
|
67
|
+
attributes: ["label", "class", "id", "role", "fill", "style", "transform", "fill-rule", "visibility", "base", "lang", "rel", "rev", "typeof", "content", "datatype", "resource", "about", "property", "space", "data-name", "clip-path", "mask"]
|
|
68
68
|
allowed_children: ["title", "path", "rect", "circle", "line", "ellipse", "polyline", "polygon", "solidColor", "textArea", "text", "g", "defs", "use", "a", "tspan", "desc", "image"]
|
|
69
69
|
- tag: "defs"
|
|
70
70
|
attributes: ["id", "role", "fill", "fill-rule", "base", "lang", "class", "rel", "rev", "typeof", "content", "datatype", "resource", "about", "property", "space"]
|
|
@@ -97,7 +97,7 @@ requirements:
|
|
|
97
97
|
attributes: ["type", "media", "title", "id", "class"]
|
|
98
98
|
allowed_children: []
|
|
99
99
|
- tag: "use"
|
|
100
|
-
attributes: ["x", "y", "href", "xlink:href", "id", "role", "fill", "transform", "fill-rule", "base", "lang", "class", "rel", "rev", "typeof", "content", "datatype", "resource", "about", "property", "space"]
|
|
100
|
+
attributes: ["x", "y", "href", "xlink:href", "id", "role", "fill", "transform", "fill-rule", "base", "lang", "class", "rel", "rev", "typeof", "content", "datatype", "resource", "about", "property", "space", "clip-path", "mask"]
|
|
101
101
|
allowed_children: ["title", "desc"]
|
|
102
102
|
- tag: "a"
|
|
103
103
|
attributes: ["id", "role", "fill", "transform", "fill-rule", "target", "base", "lang", "class", "rel", "rev", "typeof", "content", "datatype", "resource", "about", "property", "space"]
|
|
@@ -108,7 +108,7 @@ requirements:
|
|
|
108
108
|
- tag: "tbreak"
|
|
109
109
|
attributes: ["id", "role", "base", "lang", "class", "rel", "rev", "typeof", "content", "datatype", "resource", "about", "property", "space"]
|
|
110
110
|
- tag: "image"
|
|
111
|
-
attributes: ["x", "y", "width", "height", "href", "xlink:href", "preserveAspectRatio", "id", "class", "style", "transform"]
|
|
111
|
+
attributes: ["x", "y", "width", "height", "href", "xlink:href", "preserveAspectRatio", "id", "class", "style", "transform", "clip-path", "mask"]
|
|
112
112
|
allowed_children: ["title", "desc"]
|
|
113
113
|
check_attributes: true
|
|
114
114
|
check_invalid_attributes: true
|
data/docs/profiles.adoc
CHANGED
|
@@ -269,6 +269,7 @@ See link:remediation.adoc#namespace-attribute-remediation[NamespaceAttributeReme
|
|
|
269
269
|
* **Flexible fonts**: Any font families allowed (unlike RFC 7996 generic-only restriction)
|
|
270
270
|
* **Flexible styles**: Any CSS styles allowed
|
|
271
271
|
* **Event handlers allowed**: Supports event attributes (`on*`) for interactivity
|
|
272
|
+
* **Clipping and masking**: `clip-path` and `mask` presentation attributes allowed
|
|
272
273
|
* **Self-contained resources**: All CSS and fonts must be embedded
|
|
273
274
|
* **Structural compliance**: Proper namespaces and viewBox required
|
|
274
275
|
* **No external dependencies**: External CSS and fonts strictly prohibited
|
|
@@ -286,6 +287,31 @@ requirements:
|
|
|
286
287
|
- "on*" # Allow all event handler attributes
|
|
287
288
|
----
|
|
288
289
|
|
|
290
|
+
**Clipping and Masking Support**:
|
|
291
|
+
|
|
292
|
+
The metanorma profile allows `clip-path` and `mask` presentation attributes on all SVG elements. These are fundamental features for technical documentation:
|
|
293
|
+
|
|
294
|
+
* **`clip-path`**: Restricts rendering to a defined region (e.g., gaps around wire annotations)
|
|
295
|
+
* **`mask`**: Applies opacity/transparency effects (e.g., hatching patterns, image compositing)
|
|
296
|
+
|
|
297
|
+
These are allowed via the `GLOBAL_PROPERTIES` constant in `AllowedElementsRequirement`:
|
|
298
|
+
|
|
299
|
+
[source,yaml]
|
|
300
|
+
----
|
|
301
|
+
# clip-path and mask are global properties - allowed on any element
|
|
302
|
+
# No explicit configuration needed - included by default
|
|
303
|
+
----
|
|
304
|
+
|
|
305
|
+
**Use cases**:
|
|
306
|
+
|
|
307
|
+
* **Wire annotations**: Draw unbroken traces, then clip around text labels
|
|
308
|
+
* **Hatching**: Apply cross-hatching via `<mask>` elements for technical drawings
|
|
309
|
+
* **Compositing**: Build complex graphics from multiple source images with masking
|
|
310
|
+
* **Layer gaps**: Create precise gaps between elements using clipping paths
|
|
311
|
+
|
|
312
|
+
This support was added in response to issue #80 (https://github.com/claricle/svg_conform/issues/80)
|
|
313
|
+
to address real-world technical documentation workflows.
|
|
314
|
+
|
|
289
315
|
**Requirements**:
|
|
290
316
|
[source,yaml]
|
|
291
317
|
----
|
|
@@ -334,6 +360,10 @@ See link:remediation.adoc#viewbox-remediation[ViewboxRemediation], link:remediat
|
|
|
334
360
|
|Restricted property set
|
|
335
361
|
|Any styles allowed
|
|
336
362
|
|
|
363
|
+
|Clipping and Masking
|
|
364
|
+
|Not allowed (rejected as invalid attributes)
|
|
365
|
+
|`clip-path` and `mask` allowed on all elements
|
|
366
|
+
|
|
337
367
|
|External CSS
|
|
338
368
|
|Implicitly prohibited
|
|
339
369
|
|Explicitly prohibited with requirement
|
data/docs/requirements.adoc
CHANGED
|
@@ -308,6 +308,61 @@ hardcoding
|
|
|
308
308
|
* Structural invalidity tracking: Invalid elements marked to skip descendant
|
|
309
309
|
validation
|
|
310
310
|
* Zero hardcoding: All element and namespace handling configuration-driven
|
|
311
|
+
* Clipping and masking support: `clip-path` and `mask` presentation attributes
|
|
312
|
+
allowed globally on all elements
|
|
313
|
+
|
|
314
|
+
==== Clipping and Masking Support
|
|
315
|
+
|
|
316
|
+
The `AllowedElementsRequirement` allows `clip-path` and `mask` attributes as global
|
|
317
|
+
presentation attributes on any SVG element. These are defined in `GLOBAL_PROPERTIES`
|
|
318
|
+
and are allowed regardless of element-specific attribute configurations.
|
|
319
|
+
|
|
320
|
+
**What are `clip-path` and `mask`?**
|
|
321
|
+
|
|
322
|
+
* **`clip-path`**: References a `<clipPath>` element to restrict rendering to a
|
|
323
|
+
defined region. Used for creating gaps around annotations, masking out areas,
|
|
324
|
+
or compositing shapes.
|
|
325
|
+
|
|
326
|
+
* **`mask`**: References a `<mask>` element to apply opacity/transparency effects.
|
|
327
|
+
Used for hatching patterns, fading, or advanced compositing.
|
|
328
|
+
|
|
329
|
+
These attributes use URL references (e.g., `clip-path="url(#myClip)"`) to point to
|
|
330
|
+
`<clipPath>` and `<mask>` elements defined in the document.
|
|
331
|
+
|
|
332
|
+
**Example usage**:
|
|
333
|
+
|
|
334
|
+
[source,xml]
|
|
335
|
+
----
|
|
336
|
+
<svg viewBox="0 0 100 100">
|
|
337
|
+
<defs>
|
|
338
|
+
<clipPath id="clip1">
|
|
339
|
+
<rect x="0" y="0" width="50" height="50"/>
|
|
340
|
+
</clipPath>
|
|
341
|
+
<mask id="mask1">
|
|
342
|
+
<rect x="0" y="0" width="50" height="50" fill="white"/>
|
|
343
|
+
</mask>
|
|
344
|
+
</defs>
|
|
345
|
+
<g clip-path="url(#clip1)" mask="url(#mask1)">
|
|
346
|
+
<rect x="10" y="10" width="30" height="30" fill="red"/>
|
|
347
|
+
</g>
|
|
348
|
+
</svg>
|
|
349
|
+
----
|
|
350
|
+
|
|
351
|
+
**ID reference validation**: While `clip-path` and `mask` attributes are allowed,
|
|
352
|
+
the `IdReferenceRequirement` still validates that referenced IDs exist. Broken
|
|
353
|
+
references (e.g., `clip-path="url(#nonexistent)"`) will be flagged as errors.
|
|
354
|
+
|
|
355
|
+
**Why allow these attributes?**
|
|
356
|
+
|
|
357
|
+
Clipping and masking are fundamental SVG features used in technical documentation:
|
|
358
|
+
|
|
359
|
+
* **Wire annotations**: Draw traces without breaks, then clip around text
|
|
360
|
+
* **Hatching patterns**: Apply hatching via mask elements for cross-hatching
|
|
361
|
+
* **Image compositing**: Build complex graphics from multiple source images
|
|
362
|
+
* **Layer management**: Control visibility with precision
|
|
363
|
+
|
|
364
|
+
These were not supported in the original svgcheck reference implementation but are
|
|
365
|
+
part of the SVG specification and commonly used in professional technical diagrams.
|
|
311
366
|
|
|
312
367
|
==== Related remediation
|
|
313
368
|
|
data/lib/svg_conform/version.rb
CHANGED
|
@@ -94,6 +94,126 @@ RSpec.describe SvgConform::Requirements::AllowedElementsRequirement do
|
|
|
94
94
|
end
|
|
95
95
|
end
|
|
96
96
|
|
|
97
|
+
describe "clip-path and mask global properties" do
|
|
98
|
+
let(:base_requirement) do
|
|
99
|
+
described_class.new(
|
|
100
|
+
id: "test_global_props",
|
|
101
|
+
description: "Test global properties",
|
|
102
|
+
check_attributes: true,
|
|
103
|
+
)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
it "allows clip-path attribute on any element" do
|
|
107
|
+
svg = <<~SVG
|
|
108
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
|
|
109
|
+
<defs>
|
|
110
|
+
<clipPath id="clip1">
|
|
111
|
+
<rect x="0" y="0" width="50" height="50"/>
|
|
112
|
+
</clipPath>
|
|
113
|
+
</defs>
|
|
114
|
+
<g clip-path="url(#clip1)">
|
|
115
|
+
<rect x="10" y="10" width="30" height="30" fill="red"/>
|
|
116
|
+
</g>
|
|
117
|
+
</svg>
|
|
118
|
+
SVG
|
|
119
|
+
|
|
120
|
+
document = SvgConform::Document.from_content(svg)
|
|
121
|
+
context = SvgConform::ValidationContext.new(document, nil)
|
|
122
|
+
base_requirement.validate_document(document, context)
|
|
123
|
+
|
|
124
|
+
# clip-path should be allowed - no attribute errors
|
|
125
|
+
clip_path_errors = context.errors.select { |e| e.message.include?("clip-path") }
|
|
126
|
+
expect(clip_path_errors).to be_empty
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
it "allows mask attribute on any element" do
|
|
130
|
+
svg = <<~SVG
|
|
131
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
|
|
132
|
+
<defs>
|
|
133
|
+
<mask id="mask1">
|
|
134
|
+
<rect x="0" y="0" width="50" height="50" fill="white"/>
|
|
135
|
+
</mask>
|
|
136
|
+
</defs>
|
|
137
|
+
<g mask="url(#mask1)">
|
|
138
|
+
<rect x="10" y="10" width="30" height="30" fill="red"/>
|
|
139
|
+
</g>
|
|
140
|
+
</svg>
|
|
141
|
+
SVG
|
|
142
|
+
|
|
143
|
+
document = SvgConform::Document.from_content(svg)
|
|
144
|
+
context = SvgConform::ValidationContext.new(document, nil)
|
|
145
|
+
base_requirement.validate_document(document, context)
|
|
146
|
+
|
|
147
|
+
# mask should be allowed - no attribute errors
|
|
148
|
+
mask_errors = context.errors.select { |e| e.message.include?("mask") }
|
|
149
|
+
expect(mask_errors).to be_empty
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
it "allows both clip-path and mask on same element" do
|
|
153
|
+
svg = <<~SVG
|
|
154
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
|
|
155
|
+
<defs>
|
|
156
|
+
<clipPath id="clip1">
|
|
157
|
+
<rect x="0" y="0" width="50" height="50"/>
|
|
158
|
+
</clipPath>
|
|
159
|
+
<mask id="mask1">
|
|
160
|
+
<rect x="0" y="0" width="50" height="50" fill="white"/>
|
|
161
|
+
</mask>
|
|
162
|
+
</defs>
|
|
163
|
+
<g clip-path="url(#clip1)" mask="url(#mask1)">
|
|
164
|
+
<rect x="10" y="10" width="30" height="30" fill="red"/>
|
|
165
|
+
</g>
|
|
166
|
+
</svg>
|
|
167
|
+
SVG
|
|
168
|
+
|
|
169
|
+
document = SvgConform::Document.from_content(svg)
|
|
170
|
+
context = SvgConform::ValidationContext.new(document, nil)
|
|
171
|
+
base_requirement.validate_document(document, context)
|
|
172
|
+
|
|
173
|
+
expect(context.errors).to be_empty
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
it "allows clip-path on svg root element" do
|
|
177
|
+
svg = <<~SVG
|
|
178
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" clip-path="url(#rootClip)">
|
|
179
|
+
<defs>
|
|
180
|
+
<clipPath id="rootClip">
|
|
181
|
+
<rect x="0" y="0" width="100" height="100"/>
|
|
182
|
+
</clipPath>
|
|
183
|
+
</defs>
|
|
184
|
+
<rect x="10" y="10" width="80" height="80" fill="red"/>
|
|
185
|
+
</svg>
|
|
186
|
+
SVG
|
|
187
|
+
|
|
188
|
+
document = SvgConform::Document.from_content(svg)
|
|
189
|
+
context = SvgConform::ValidationContext.new(document, nil)
|
|
190
|
+
base_requirement.validate_document(document, context)
|
|
191
|
+
|
|
192
|
+
clip_path_errors = context.errors.select { |e| e.message.include?("clip-path") }
|
|
193
|
+
expect(clip_path_errors).to be_empty
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
it "allows mask on rect element" do
|
|
197
|
+
svg = <<~SVG
|
|
198
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
|
|
199
|
+
<defs>
|
|
200
|
+
<mask id="mask1">
|
|
201
|
+
<rect x="0" y="0" width="100" height="100" fill="white"/>
|
|
202
|
+
</mask>
|
|
203
|
+
</defs>
|
|
204
|
+
<rect x="10" y="10" width="80" height="80" fill="red" mask="url(#mask1)"/>
|
|
205
|
+
</svg>
|
|
206
|
+
SVG
|
|
207
|
+
|
|
208
|
+
document = SvgConform::Document.from_content(svg)
|
|
209
|
+
context = SvgConform::ValidationContext.new(document, nil)
|
|
210
|
+
base_requirement.validate_document(document, context)
|
|
211
|
+
|
|
212
|
+
mask_errors = context.errors.select { |e| e.message.include?("mask") }
|
|
213
|
+
expect(mask_errors).to be_empty
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
|
|
97
217
|
describe "configuration" do
|
|
98
218
|
it "accepts custom allowed elements list" do
|
|
99
219
|
requirement = described_class.new(
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: svg_conform
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2.
|
|
4
|
+
version: 0.2.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-04-
|
|
11
|
+
date: 2026-04-11 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: lutaml-model
|