svg_conform 0.2.1 → 0.2.3
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/.github/workflows/release.yml +14 -10
- data/CLAUDE.md +1 -1
- data/Gemfile +1 -0
- data/lib/svg_conform/document.rb +17 -10
- data/lib/svg_conform/document_analyzer.rb +2 -2
- data/lib/svg_conform/interfaces/requirement_interface.rb +2 -2
- data/lib/svg_conform/node_helpers.rb +12 -1
- data/lib/svg_conform/profile.rb +1 -1
- data/lib/svg_conform/quality_metrics/complexity_metrics.rb +4 -1
- data/lib/svg_conform/quality_metrics/error_breakdown.rb +4 -1
- data/lib/svg_conform/quality_metrics/feature_flags.rb +4 -1
- data/lib/svg_conform/quality_metrics/quality_result.rb +4 -1
- data/lib/svg_conform/quality_metrics/quality_score.rb +4 -1
- data/lib/svg_conform/remediations/namespace_attribute_remediation.rb +6 -4
- data/lib/svg_conform/remediations/namespace_remediation.rb +5 -2
- data/lib/svg_conform/requirements/allowed_elements_requirement.rb +5 -0
- data/lib/svg_conform/requirements/namespace_attributes_requirement.rb +1 -1
- data/lib/svg_conform/sax_document.rb +2 -2
- data/lib/svg_conform/sax_validation_handler.rb +4 -4
- data/lib/svg_conform/semantic_comparator.rb +3 -3
- data/lib/svg_conform/validator.rb +4 -4
- data/lib/svg_conform/version.rb +1 -1
- data/lib/svg_conform.rb +1 -1
- data/spec/svg_conform/requirements/id_reference_state_spec.rb +2 -2
- data/spec/svg_conform/validator_input_types_spec.rb +15 -15
- data/spec/svgcheck_compatibility_spec.rb +2 -2
- data/svg_conform.gemspec +1 -1
- metadata +4 -10
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b84a6929a5ff16f9cbe74d86c862a15487f5d76276972975cbd0ac9a99d027d9
|
|
4
|
+
data.tar.gz: ff3df290c1ce16e466f5a43527b664bb19a29af8ae80c7b8332dee172bb0c11f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b7e28c31a41dd1b98b3ac98f7a97185a153d78b6303002b578a6540d7e53ffc3243777ec408feca823d4dd4395c4831630e1aed2562e64d6c4cf2595ee33baa6
|
|
7
|
+
data.tar.gz: 5c67c533db3ba7261c2a10998c2cd34bff00521ea43ae125fe369d5a7bea14cc3771662b8a545bba5a0f2eb427b9b25ab7fe2d35d23825e8242f40744d5f638f
|
|
@@ -1,12 +1,9 @@
|
|
|
1
|
-
#
|
|
2
|
-
#
|
|
1
|
+
# Trusted publishing (OIDC) release — matches lutaml-model/.github/workflows/release.yml.
|
|
2
|
+
# metanorma/ci switches to OIDC when the rubygems-api-key secret is omitted;
|
|
3
|
+
# each gem must be registered for trusted publishing on rubygems.org
|
|
4
|
+
# (owner=claricle, workflow=release.yml).
|
|
3
5
|
name: release
|
|
4
6
|
|
|
5
|
-
permissions:
|
|
6
|
-
contents: write
|
|
7
|
-
packages: write
|
|
8
|
-
id-token: write
|
|
9
|
-
|
|
10
7
|
on:
|
|
11
8
|
workflow_dispatch:
|
|
12
9
|
inputs:
|
|
@@ -18,11 +15,18 @@ on:
|
|
|
18
15
|
repository_dispatch:
|
|
19
16
|
types: [ do-release ]
|
|
20
17
|
|
|
18
|
+
# Least-privilege ceiling for the called rubygems-release.yml: its release job
|
|
19
|
+
# needs contents:write (git tag push) and id-token:write (OIDC Trusted Publishing).
|
|
20
|
+
permissions:
|
|
21
|
+
contents: write
|
|
22
|
+
id-token: write
|
|
23
|
+
|
|
24
|
+
concurrency:
|
|
25
|
+
group: release
|
|
26
|
+
cancel-in-progress: false
|
|
27
|
+
|
|
21
28
|
jobs:
|
|
22
29
|
release:
|
|
23
30
|
uses: metanorma/ci/.github/workflows/rubygems-release.yml@main
|
|
24
31
|
with:
|
|
25
32
|
next_version: ${{ github.event.inputs.next_version }}
|
|
26
|
-
secrets:
|
|
27
|
-
rubygems-api-key: ${{ secrets.CLARICLE_CI_RUBYGEMS_API_KEY }}
|
|
28
|
-
pat_token: ${{ secrets.GITHUB_TOKEN }}
|
data/CLAUDE.md
CHANGED
|
@@ -97,7 +97,7 @@ Profiles support `import` to inherit from other profiles (e.g., `metanorma` impo
|
|
|
97
97
|
|
|
98
98
|
The `Validator` accepts multiple input types and always uses SAX:
|
|
99
99
|
- String (XML content) → parsed directly with SAX
|
|
100
|
-
- Moxml/
|
|
100
|
+
- Moxml/leptris documents → serialized once, then SAX validated
|
|
101
101
|
- Document/Element objects → same serialization approach
|
|
102
102
|
|
|
103
103
|
This ensures memory safety for large files regardless of input type.
|
data/Gemfile
CHANGED
data/lib/svg_conform/document.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "moxml"
|
|
4
|
-
require "
|
|
4
|
+
require "leptris" if defined?(Leptris)
|
|
5
5
|
|
|
6
6
|
module SvgConform
|
|
7
7
|
# Wrapper around Moxml document for SVG validation
|
|
@@ -29,7 +29,7 @@ module SvgConform
|
|
|
29
29
|
new(content)
|
|
30
30
|
end
|
|
31
31
|
|
|
32
|
-
# Create Document from an already-parsed node (
|
|
32
|
+
# Create Document from an already-parsed node (leptris or Moxml)
|
|
33
33
|
# Avoids re-parsing when input is already a DOM object
|
|
34
34
|
def self.from_node(node)
|
|
35
35
|
doc = allocate
|
|
@@ -42,15 +42,15 @@ module SvgConform
|
|
|
42
42
|
doc.instance_variable_set(:@content, nil) # Don't store XML string
|
|
43
43
|
doc.instance_variable_set(:@moxml_document,
|
|
44
44
|
node.is_a?(Moxml::Document) ? node : wrap_moxml_element(node))
|
|
45
|
-
elsif defined?(
|
|
46
|
-
#
|
|
45
|
+
elsif defined?(Leptris) && node.is_a?(Leptris::XML::Node)
|
|
46
|
+
# leptris node - must serialize to convert to Moxml
|
|
47
47
|
# This is unavoidable due to different DOM implementations
|
|
48
48
|
xml_string = node.to_xml
|
|
49
49
|
doc.instance_variable_set(:@content, xml_string)
|
|
50
50
|
doc.send(:parse_document)
|
|
51
51
|
else
|
|
52
52
|
raise ArgumentError,
|
|
53
|
-
"Invalid input type: #{node.class}. Expected Moxml or
|
|
53
|
+
"Invalid input type: #{node.class}. Expected Moxml or leptris DOM node."
|
|
54
54
|
end
|
|
55
55
|
|
|
56
56
|
doc
|
|
@@ -72,8 +72,11 @@ module SvgConform
|
|
|
72
72
|
end
|
|
73
73
|
|
|
74
74
|
def xpath(path, namespaces = {})
|
|
75
|
-
|
|
76
|
-
|
|
75
|
+
# No memoization: cached node sets go stale the moment any
|
|
76
|
+
# remediation mutates the tree, and validation then reads
|
|
77
|
+
# pre-remediation state (watch: style promotions silently
|
|
78
|
+
# "not applied" on revalidation).
|
|
79
|
+
@moxml_document.xpath(path, namespaces)
|
|
77
80
|
end
|
|
78
81
|
|
|
79
82
|
def traverse(&)
|
|
@@ -110,7 +113,7 @@ module SvgConform
|
|
|
110
113
|
|
|
111
114
|
def remove_namespace_declarations(xml, prefixes)
|
|
112
115
|
# Remove xmlns:prefix="uri" declarations from the XML string
|
|
113
|
-
# This works around Moxml
|
|
116
|
+
# This works around Moxml's inability to remove namespace declarations
|
|
114
117
|
prefixes.reduce(xml) do |result, prefix|
|
|
115
118
|
# Match xmlns:prefix="..." with various quote styles and surrounding whitespace
|
|
116
119
|
# The pattern matches: xmlns:prefix="uri" or xmlns:prefix='uri'
|
|
@@ -237,8 +240,12 @@ module SvgConform
|
|
|
237
240
|
|
|
238
241
|
def parse_document
|
|
239
242
|
begin
|
|
240
|
-
# Create a Moxml context and parse the document
|
|
241
|
-
|
|
243
|
+
# Create a Moxml context and parse the document. The DOM is
|
|
244
|
+
# pinned to the Nokogiri adapter: the leptris adapter segfaults
|
|
245
|
+
# natively in attribute traversal on path-heavy SVGs
|
|
246
|
+
# (leptris#1712), and this gem's remediation passes are exactly
|
|
247
|
+
# that workload.
|
|
248
|
+
context = Moxml.new(:nokogiri)
|
|
242
249
|
@moxml_document = context.parse(@content)
|
|
243
250
|
rescue StandardError => e
|
|
244
251
|
raise ParseError, "Failed to parse SVG document: #{e.message}"
|
|
@@ -20,7 +20,7 @@ module SvgConform
|
|
|
20
20
|
return nil unless node.respond_to?(:name) && node.name
|
|
21
21
|
|
|
22
22
|
# Use native.object_id as cache key since wrapper object_id changes
|
|
23
|
-
# across traverses but underlying
|
|
23
|
+
# across traverses but underlying leptris node identity is stable
|
|
24
24
|
native_id = node.native.object_id
|
|
25
25
|
@cache[native_id] ||= compute_and_cache_path(node)
|
|
26
26
|
end
|
|
@@ -107,7 +107,7 @@ module SvgConform
|
|
|
107
107
|
|
|
108
108
|
# Count this node's position among siblings with same name
|
|
109
109
|
# Use native.object_id comparison since wrapper objects differ
|
|
110
|
-
# across traverses but underlying
|
|
110
|
+
# across traverses but underlying leptris nodes are stable
|
|
111
111
|
position = 0
|
|
112
112
|
native_id = node.native.object_id
|
|
113
113
|
parent.children.each do |child|
|
|
@@ -28,7 +28,7 @@ module SvgConform
|
|
|
28
28
|
# This is the main validation method called for each node that passes
|
|
29
29
|
# the should_check_node? filter during DOM-based validation.
|
|
30
30
|
#
|
|
31
|
-
# @param node [Moxml::Node,
|
|
31
|
+
# @param node [Moxml::Node, Leptris::XML::Node] The node to validate
|
|
32
32
|
# @param context [ValidationContext] The validation context for reporting errors
|
|
33
33
|
# @return [void]
|
|
34
34
|
# @raise [NotImplementedError] If not implemented by subclass
|
|
@@ -143,7 +143,7 @@ module SvgConform
|
|
|
143
143
|
#
|
|
144
144
|
# Override this to add additional filtering logic.
|
|
145
145
|
#
|
|
146
|
-
# @param node [Moxml::Node,
|
|
146
|
+
# @param node [Moxml::Node, Leptris::XML::Node, ElementProxy] The node to check
|
|
147
147
|
# @param context [ValidationContext, nil] The validation context (may be nil in some cases)
|
|
148
148
|
# @return [Boolean] true if the node should be validated
|
|
149
149
|
def should_check_node?(node, context = nil)
|
|
@@ -57,7 +57,18 @@ module SvgConform
|
|
|
57
57
|
# @param name [String] attribute name
|
|
58
58
|
# @return [Boolean] true if successful
|
|
59
59
|
def remove_attribute(node, name)
|
|
60
|
-
if node.respond_to?(:
|
|
60
|
+
if node.respond_to?(:attributes)
|
|
61
|
+
# Remove via the attribute wrapper: node-level remove_attribute is
|
|
62
|
+
# a silent no-op for namespace-prefixed names (moxml#378), while
|
|
63
|
+
# the wrapper's #remove works on every adapter.
|
|
64
|
+
attr = Array(node.attributes).find do |a|
|
|
65
|
+
a.respond_to?(:name) && a.name == name && a.respond_to?(:remove)
|
|
66
|
+
end
|
|
67
|
+
return false unless attr
|
|
68
|
+
|
|
69
|
+
attr.remove
|
|
70
|
+
true
|
|
71
|
+
elsif node.respond_to?(:remove_attribute)
|
|
61
72
|
node.remove_attribute(name)
|
|
62
73
|
true
|
|
63
74
|
elsif node.respond_to?(:[]=) && node.respond_to?(:[])
|
data/lib/svg_conform/profile.rb
CHANGED
|
@@ -132,7 +132,7 @@ module SvgConform
|
|
|
132
132
|
ValidationResult.new(document, self, context)
|
|
133
133
|
elsif document.respond_to?(:to_xml)
|
|
134
134
|
# For other document objects, serialize and use SAX for safety
|
|
135
|
-
# (This handles
|
|
135
|
+
# (This handles leptris/Moxml documents that aren't wrapped in Document)
|
|
136
136
|
content = document.to_xml
|
|
137
137
|
sax_doc = SaxDocument.from_content(content)
|
|
138
138
|
sax_doc.validate_with_profile(self)
|
|
@@ -23,7 +23,10 @@ module SvgConform
|
|
|
23
23
|
attribute :has_clip_paths, :boolean, default: false
|
|
24
24
|
attribute :has_external_refs, :boolean, default: false
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
def initialize(**args)
|
|
27
|
+
super(args)
|
|
28
|
+
freeze
|
|
29
|
+
end
|
|
27
30
|
|
|
28
31
|
# Value equality
|
|
29
32
|
def ==(other)
|
|
@@ -32,7 +32,7 @@ module SvgConform
|
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
# Second pass: remove unused namespace declarations
|
|
35
|
-
#
|
|
35
|
+
# Moxml adapters cannot remove namespace declarations via DOM,
|
|
36
36
|
# so we use string manipulation + reparse
|
|
37
37
|
if removed_namespaces.any? || disallowed_namespaces.any?
|
|
38
38
|
changes.concat(remove_namespace_declarations(document,
|
|
@@ -51,7 +51,7 @@ module SvgConform
|
|
|
51
51
|
attributes_to_remove = []
|
|
52
52
|
|
|
53
53
|
if node.respond_to?(:attribute_nodes)
|
|
54
|
-
# Use attribute_nodes if available (
|
|
54
|
+
# Use attribute_nodes if available (nokogiri-compatible API style)
|
|
55
55
|
node.attribute_nodes.each do |attr|
|
|
56
56
|
namespace_uri = attr.namespace&.href
|
|
57
57
|
next unless namespace_uri
|
|
@@ -82,7 +82,9 @@ module SvgConform
|
|
|
82
82
|
# Array case
|
|
83
83
|
attributes.each do |attr|
|
|
84
84
|
if should_remove_moxml_attribute?(attr, node, removed_namespaces)
|
|
85
|
-
|
|
85
|
+
local_name = attr.respond_to?(:name) ? attr.name : attr.to_s
|
|
86
|
+
ns_prefix = attr.respond_to?(:namespace) && attr.namespace.respond_to?(:prefix) ? attr.namespace.prefix : nil
|
|
87
|
+
attr_name = ns_prefix && !ns_prefix.empty? ? "#{ns_prefix}:#{local_name}" : local_name
|
|
86
88
|
attributes_to_remove << attr_name
|
|
87
89
|
end
|
|
88
90
|
end
|
|
@@ -132,7 +134,7 @@ module SvgConform
|
|
|
132
134
|
|
|
133
135
|
# Reparse the document to update the internal DOM
|
|
134
136
|
# This is necessary because namespace declarations cannot be removed
|
|
135
|
-
# from the DOM directly in
|
|
137
|
+
# from the DOM directly in moxml adapters
|
|
136
138
|
if changes.any?
|
|
137
139
|
context = Moxml.new
|
|
138
140
|
new_moxml_doc = context.parse(xml_str)
|
|
@@ -59,7 +59,10 @@ module SvgConform
|
|
|
59
59
|
|
|
60
60
|
node.attributes.each do |attr_name, attr_value|
|
|
61
61
|
# Handle both string keys and Moxml::Attribute objects
|
|
62
|
-
|
|
62
|
+
local_name = attr_name.respond_to?(:name) ? attr_name.name : attr_name.to_s
|
|
63
|
+
# Include namespace prefix for namespaced attributes (e.g. "custom:id")
|
|
64
|
+
ns_prefix = attr_name.respond_to?(:namespace) && attr_name.namespace.respond_to?(:prefix) ? attr_name.namespace.prefix : nil
|
|
65
|
+
name_str = ns_prefix && !ns_prefix.empty? ? "#{ns_prefix}:#{local_name}" : local_name
|
|
63
66
|
|
|
64
67
|
# For root SVG element, remove xmlns declarations for disallowed namespaces
|
|
65
68
|
if remove_declarations && node.name == "svg" && name_str.start_with?("xmlns:")
|
|
@@ -107,7 +110,7 @@ module SvgConform
|
|
|
107
110
|
end
|
|
108
111
|
|
|
109
112
|
# Clean up unused namespace declarations
|
|
110
|
-
# Note: Moxml
|
|
113
|
+
# Note: Moxml doesn't support removing namespace declarations directly,
|
|
111
114
|
# so we mark the document for post-processing during serialization
|
|
112
115
|
cleanup_unused_namespace_declarations(document)
|
|
113
116
|
|
|
@@ -33,7 +33,7 @@ module SvgConform
|
|
|
33
33
|
|
|
34
34
|
# Try to get attributes using different methods depending on what's available
|
|
35
35
|
if node.respond_to?(:attribute_nodes)
|
|
36
|
-
# Use attribute_nodes if available (
|
|
36
|
+
# Use attribute_nodes if available (nokogiri-compatible API style)
|
|
37
37
|
check_attribute_nodes(node, context)
|
|
38
38
|
elsif node.respond_to?(:attributes)
|
|
39
39
|
# Fallback to attributes method (Moxml style)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "
|
|
3
|
+
require "leptris"
|
|
4
4
|
require_relative "sax_validation_handler"
|
|
5
5
|
|
|
6
6
|
module SvgConform
|
|
@@ -26,7 +26,7 @@ module SvgConform
|
|
|
26
26
|
# Validate using SAX streaming parser
|
|
27
27
|
def validate_with_profile(profile)
|
|
28
28
|
handler = SaxValidationHandler.new(profile)
|
|
29
|
-
parser =
|
|
29
|
+
parser = Leptris::XML::SAX::Parser.new(handler)
|
|
30
30
|
|
|
31
31
|
begin
|
|
32
32
|
parser.parse(@content)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "
|
|
3
|
+
require "leptris"
|
|
4
4
|
require_relative "element_proxy"
|
|
5
5
|
require_relative "validation_context"
|
|
6
6
|
require_relative "validation/error_tracker"
|
|
@@ -38,7 +38,7 @@ module SvgConform
|
|
|
38
38
|
# - Each validation creates a fresh SaxValidationHandler with fresh ValidationContext
|
|
39
39
|
# - ValidationContext creates fresh State instances for deferred requirements
|
|
40
40
|
# - No state pollution occurs across validations
|
|
41
|
-
class SaxValidationHandler <
|
|
41
|
+
class SaxValidationHandler < Leptris::XML::SAX::Document
|
|
42
42
|
attr_reader :result, :context
|
|
43
43
|
|
|
44
44
|
def initialize(profile)
|
|
@@ -134,8 +134,8 @@ module SvgConform
|
|
|
134
134
|
end
|
|
135
135
|
|
|
136
136
|
# SAX Event: Parse error
|
|
137
|
-
def error(
|
|
138
|
-
@parse_errors <<
|
|
137
|
+
def error(message, _line = 0, _column = 0)
|
|
138
|
+
@parse_errors << message
|
|
139
139
|
end
|
|
140
140
|
|
|
141
141
|
# SAX Event: Warning
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "
|
|
3
|
+
require "leptris"
|
|
4
4
|
|
|
5
5
|
module SvgConform
|
|
6
6
|
# Semantic comparison engine for comparing validation results and remediated content
|
|
@@ -553,8 +553,8 @@ repair_mode = false, _mixed_mode = false)
|
|
|
553
553
|
def self.parse_svg_safely(content)
|
|
554
554
|
return nil if content.nil? || content.strip.empty?
|
|
555
555
|
|
|
556
|
-
|
|
557
|
-
rescue
|
|
556
|
+
Leptris::XML.parse(content)
|
|
557
|
+
rescue Leptris::XML::ParseError
|
|
558
558
|
nil
|
|
559
559
|
end
|
|
560
560
|
|
|
@@ -35,7 +35,7 @@ module SvgConform
|
|
|
35
35
|
# Accepts:
|
|
36
36
|
# - String (XML content) → uses SAX for efficient parsing
|
|
37
37
|
# - Moxml::Document or Moxml::Element → serializes once, then SAX validates
|
|
38
|
-
# -
|
|
38
|
+
# - leptris::XML::Document or leptris::XML::Element → serializes once, then SAX validates
|
|
39
39
|
# - Any adapter document object (Ox, Oga, REXML, LibXML) → serializes once, then SAX validates
|
|
40
40
|
#
|
|
41
41
|
# IMPORTANT: Always uses SAX validation to safely handle large SVG files.
|
|
@@ -110,8 +110,8 @@ module SvgConform
|
|
|
110
110
|
return input.to_xml
|
|
111
111
|
end
|
|
112
112
|
|
|
113
|
-
# Check for
|
|
114
|
-
if defined?(
|
|
113
|
+
# Check for leptris document or element
|
|
114
|
+
if defined?(Leptris) && input.is_a?(Leptris::XML::Node)
|
|
115
115
|
return input.to_xml
|
|
116
116
|
end
|
|
117
117
|
|
|
@@ -123,7 +123,7 @@ module SvgConform
|
|
|
123
123
|
# If we can't convert, raise an error
|
|
124
124
|
raise ArgumentError,
|
|
125
125
|
"Invalid input type: #{input.class}. " \
|
|
126
|
-
"Expected String, Moxml document,
|
|
126
|
+
"Expected String, Moxml document, leptris document, or adapter document object. " \
|
|
127
127
|
"Input must respond to #to_xml or be a valid XML string."
|
|
128
128
|
end
|
|
129
129
|
|
data/lib/svg_conform/version.rb
CHANGED
data/lib/svg_conform.rb
CHANGED
|
@@ -4,7 +4,7 @@ require "lutaml/model"
|
|
|
4
4
|
|
|
5
5
|
# Configure Lutaml::Model adapters
|
|
6
6
|
Lutaml::Model::Config.configure do |config|
|
|
7
|
-
config.xml_adapter_type = :
|
|
7
|
+
config.xml_adapter_type = :leptris
|
|
8
8
|
config.json_adapter_type = :standard_json
|
|
9
9
|
config.yaml_adapter_type = :standard_yaml
|
|
10
10
|
end
|
|
@@ -34,7 +34,7 @@ RSpec.describe "IdReferenceRequirement" do
|
|
|
34
34
|
|
|
35
35
|
# Verify first validation caught the error
|
|
36
36
|
expect(result1.errors.map(&:message)).to include(
|
|
37
|
-
|
|
37
|
+
include("Reference to undefined ID 'missing_id'"),
|
|
38
38
|
)
|
|
39
39
|
|
|
40
40
|
# Second validation: SVG without reference errors
|
|
@@ -68,7 +68,7 @@ RSpec.describe "IdReferenceRequirement" do
|
|
|
68
68
|
if i.even?
|
|
69
69
|
# Should have error (svg_with_error)
|
|
70
70
|
expect(result.errors.map(&:message)).to include(
|
|
71
|
-
|
|
71
|
+
include("Reference to undefined ID 'missing_id'"),
|
|
72
72
|
)
|
|
73
73
|
else
|
|
74
74
|
# Should NOT have error about missing_id (svg_without_error)
|
|
@@ -66,19 +66,19 @@ RSpec.describe SvgConform::Validator do
|
|
|
66
66
|
end
|
|
67
67
|
end
|
|
68
68
|
|
|
69
|
-
context "with
|
|
70
|
-
it "validates
|
|
71
|
-
|
|
69
|
+
context "with leptris input (metanorm use case)" do
|
|
70
|
+
it "validates a leptris document" do
|
|
71
|
+
leptris_doc = Leptris::XML.parse(simple_svg)
|
|
72
72
|
|
|
73
|
-
result = validator.validate(
|
|
73
|
+
result = validator.validate(leptris_doc, profile: :metanorma)
|
|
74
74
|
|
|
75
75
|
expect(result).to be_a(SvgConform::ValidationResult)
|
|
76
76
|
expect(result.valid?).to be true
|
|
77
77
|
end
|
|
78
78
|
|
|
79
|
-
it "validates
|
|
80
|
-
|
|
81
|
-
svg_element =
|
|
79
|
+
it "validates a leptris element" do
|
|
80
|
+
leptris_doc = Leptris::XML.parse(simple_svg)
|
|
81
|
+
svg_element = leptris_doc.root
|
|
82
82
|
|
|
83
83
|
# This is the metanorma use case - passing element directly
|
|
84
84
|
result = validator.validate(svg_element, profile: :metanorma)
|
|
@@ -87,9 +87,9 @@ RSpec.describe SvgConform::Validator do
|
|
|
87
87
|
expect(result.valid?).to be true
|
|
88
88
|
end
|
|
89
89
|
|
|
90
|
-
it "serializes
|
|
91
|
-
|
|
92
|
-
svg_element =
|
|
90
|
+
it "serializes leptris element once for SAX validation" do
|
|
91
|
+
leptris_doc = Leptris::XML.parse(simple_svg)
|
|
92
|
+
svg_element = leptris_doc.root
|
|
93
93
|
|
|
94
94
|
# Should call to_xml once for SAX validation
|
|
95
95
|
# (SAX mode is memory-safe for large SVGs)
|
|
@@ -126,9 +126,9 @@ RSpec.describe SvgConform::Validator do
|
|
|
126
126
|
SVG
|
|
127
127
|
end
|
|
128
128
|
|
|
129
|
-
it "builds reference manifest from
|
|
130
|
-
|
|
131
|
-
svg_element =
|
|
129
|
+
it "builds reference manifest from leptris element" do
|
|
130
|
+
leptris_doc = Leptris::XML.parse(svg_with_refs)
|
|
131
|
+
svg_element = leptris_doc.root
|
|
132
132
|
|
|
133
133
|
result = validator.validate(svg_element, profile: :metanorma)
|
|
134
134
|
|
|
@@ -159,8 +159,8 @@ RSpec.describe SvgConform::Validator do
|
|
|
159
159
|
end
|
|
160
160
|
|
|
161
161
|
it "applies remediation when using document object input" do
|
|
162
|
-
|
|
163
|
-
svg_element =
|
|
162
|
+
leptris_doc = Leptris::XML.parse(invalid_svg)
|
|
163
|
+
svg_element = leptris_doc.root
|
|
164
164
|
|
|
165
165
|
result = validator.validate(svg_element, profile: :svg_1_2_rfc, fix: true)
|
|
166
166
|
|
data/svg_conform.gemspec
CHANGED
|
@@ -30,7 +30,7 @@ Gem::Specification.new do |spec|
|
|
|
30
30
|
spec.require_paths = ["lib"]
|
|
31
31
|
|
|
32
32
|
spec.add_dependency "lutaml-model", "~> 0.8.0"
|
|
33
|
-
spec.add_dependency "moxml", "~> 0.
|
|
33
|
+
spec.add_dependency "moxml", "~> 0.5"
|
|
34
34
|
spec.add_dependency "rainbow"
|
|
35
35
|
spec.add_dependency "table_tennis"
|
|
36
36
|
spec.add_dependency "thor"
|
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.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-10-16 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: lutaml-model
|
|
@@ -30,20 +30,14 @@ dependencies:
|
|
|
30
30
|
requirements:
|
|
31
31
|
- - "~>"
|
|
32
32
|
- !ruby/object:Gem::Version
|
|
33
|
-
version: '0.
|
|
34
|
-
- - ">="
|
|
35
|
-
- !ruby/object:Gem::Version
|
|
36
|
-
version: 0.1.10
|
|
33
|
+
version: '0.5'
|
|
37
34
|
type: :runtime
|
|
38
35
|
prerelease: false
|
|
39
36
|
version_requirements: !ruby/object:Gem::Requirement
|
|
40
37
|
requirements:
|
|
41
38
|
- - "~>"
|
|
42
39
|
- !ruby/object:Gem::Version
|
|
43
|
-
version: '0.
|
|
44
|
-
- - ">="
|
|
45
|
-
- !ruby/object:Gem::Version
|
|
46
|
-
version: 0.1.10
|
|
40
|
+
version: '0.5'
|
|
47
41
|
- !ruby/object:Gem::Dependency
|
|
48
42
|
name: rainbow
|
|
49
43
|
requirement: !ruby/object:Gem::Requirement
|