svg_conform 0.1.6 → 0.1.7

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a9ecc9cf94ec2791168aba3939afb43f456b86c596912339ea2947162c5f738d
4
- data.tar.gz: 32671c37c920fdb2cb36666183d1e965d803c6c706dc4e98e97a581e2cf49e4d
3
+ metadata.gz: a671b1d69dd6498470fc03cdaf2488bd3180187a39ef505cef2cb67d76de1725
4
+ data.tar.gz: c915d4ed0894b35293d78ea4a71f326e8985190dac8ae8df55c55b8eb10d1696
5
5
  SHA512:
6
- metadata.gz: 1d849f548dfff6df9b81c624430323459cd33f12756c64c9fe04e4cf801bf7a1a45d94bcbbb632423c5eeefac4040733eea9a3133bfcdd75d11a64568d74413e
7
- data.tar.gz: d22c6710edadb75a1346a8e56f835f9f18d9113018c719bbc8362f04ea6288c6a17b6142144a9388c03b838a350217d59b797ceea3850dba232e0f388b7ee275
6
+ metadata.gz: a32f6b36b517598e1a5f95612457c4e9a5386f64a15d6383dfb2e63052a2c58354a24afc730ad3a27b3ce6165c52447872e759655ef33ba8c546c12de2b16fbc
7
+ data.tar.gz: 1f22474906b51fe86cdeadac2817a66b2695bf7b1685370e25e058ed6c66dc9d09b2f95e26526b5a7937b493f2a7e51b3cf7a97b036c4ec0c8a7f7b0d1494801
data/Gemfile CHANGED
@@ -5,8 +5,8 @@ source "https://rubygems.org"
5
5
  # Specify your gem's dependencies in svg_conform.gemspec
6
6
  gemspec
7
7
 
8
- gem "canon"
9
- gem "openssl"
8
+ gem "canon", "~>0.1.10"
9
+ gem "openssl", "~> 3.0"
10
10
  gem "rake"
11
11
  gem "rspec"
12
12
  gem "rubocop"
@@ -92,7 +92,28 @@ module SvgConform
92
92
  def to_xml
93
93
  # Always generate from current moxml_document state
94
94
  # This ensures modifications are reflected in the output
95
- @moxml_document.to_xml
95
+ xml = @moxml_document.to_xml
96
+
97
+ # Clean up unused namespace declarations if marked by remediations
98
+ if instance_variable_defined?(:@unused_namespace_prefixes)
99
+ prefixes = @unused_namespace_prefixes
100
+ xml = remove_namespace_declarations(xml, prefixes) if prefixes && !prefixes.empty?
101
+ # Clear the marker after cleanup
102
+ remove_instance_variable(:@unused_namespace_prefixes)
103
+ end
104
+
105
+ xml
106
+ end
107
+
108
+ def remove_namespace_declarations(xml, prefixes)
109
+ # Remove xmlns:prefix="uri" declarations from the XML string
110
+ # This works around Moxml/Nokogiri's inability to remove namespace declarations
111
+ prefixes.reduce(xml) do |result, prefix|
112
+ # Match xmlns:prefix="..." with various quote styles and surrounding whitespace
113
+ # The pattern matches: xmlns:prefix="uri" or xmlns:prefix='uri'
114
+ # It captures leading whitespace to remove it too
115
+ result.gsub(%r{\s+xmlns:#{prefix}=["'][^"']*["']}, "")
116
+ end
96
117
  end
97
118
 
98
119
  def dup
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SvgConform
4
+ # Shared helper methods for working with XML nodes
5
+ #
6
+ # This module provides common utilities used by both requirements
7
+ # and remediations to avoid code duplication and ensure consistency.
8
+ module NodeHelpers
9
+ # Check if a node is an element
10
+ # @param node [Object] the node to check
11
+ # @return [Boolean] true if the node is an element
12
+ def element?(node)
13
+ node.respond_to?(:name) && !node.name.nil?
14
+ end
15
+
16
+ # Check if a node is text
17
+ # @param node [Object] the node to check
18
+ # @return [Boolean] true if the node is text
19
+ def text?(node)
20
+ node.respond_to?(:text?) && node.text?
21
+ end
22
+
23
+ # Get attribute value from a node
24
+ # @param node [Object] the node
25
+ # @param name [String] attribute name
26
+ # @return [String, nil] attribute value or nil
27
+ def get_attribute(node, name)
28
+ return nil unless node.respond_to?(:[])
29
+
30
+ node[name]
31
+ end
32
+
33
+ # Set attribute value on a node
34
+ # @param node [Object] the node
35
+ # @param name [String] attribute name
36
+ # @param value [String] attribute value
37
+ # @return [Boolean] true if successful
38
+ def set_attribute(node, name, value)
39
+ return unless node.respond_to?(:[]=)
40
+
41
+ node[name] = value
42
+ true
43
+ end
44
+
45
+ # Check if node has an attribute
46
+ # @param node [Object] the node
47
+ # @param name [String] attribute name
48
+ # @return [Boolean] true if attribute exists
49
+ def has_attribute?(node, name)
50
+ return false unless node.respond_to?(:[])
51
+
52
+ !node[name].nil?
53
+ end
54
+
55
+ # Remove attribute from a node
56
+ # @param node [Object] the node
57
+ # @param name [String] attribute name
58
+ # @return [Boolean] true if successful
59
+ def remove_attribute(node, name)
60
+ if node.respond_to?(:remove_attribute)
61
+ node.remove_attribute(name)
62
+ true
63
+ elsif node.respond_to?(:[]=) && node.respond_to?(:[])
64
+ # Fallback for bracket notation
65
+ node[name] = nil
66
+ true
67
+ else
68
+ false
69
+ end
70
+ end
71
+ end
72
+ end
@@ -2,11 +2,14 @@
2
2
 
3
3
  require "lutaml/model"
4
4
  require_relative "../remediation_result"
5
+ require_relative "../node_helpers"
5
6
 
6
7
  module SvgConform
7
8
  module Remediations
8
9
  # Base class for all remediations using lutaml-model serialization
9
10
  class BaseRemediation < Lutaml::Model::Serializable
11
+ include SvgConform::NodeHelpers
12
+
10
13
  attribute :id, :string
11
14
  attribute :description, :string
12
15
  attribute :targets, :string, collection: true
@@ -72,27 +75,8 @@ module SvgConform
72
75
 
73
76
  protected
74
77
 
75
- def element?(node)
76
- node.respond_to?(:name) && node.name
77
- end
78
-
79
- def get_attribute(node, attr_name)
80
- return nil unless node.respond_to?(:[])
81
-
82
- node[attr_name]
83
- end
84
-
85
- def set_attribute(node, attr_name, value)
86
- return unless node.respond_to?(:[]=)
87
-
88
- node[attr_name] = value
89
- end
90
-
91
- def has_attribute?(node, attr_name)
92
- return false unless node.respond_to?(:[])
93
-
94
- !node[attr_name].nil?
95
- end
78
+ # Helper methods for node manipulation included via NodeHelpers module:
79
+ # element?, text?, get_attribute, set_attribute, has_attribute?, remove_attribute
96
80
 
97
81
  def find_nodes(document, &)
98
82
  nodes = []
@@ -100,20 +84,6 @@ module SvgConform
100
84
  nodes
101
85
  end
102
86
 
103
- # Helper method to remove attribute
104
- def remove_attribute(node, name)
105
- if node.respond_to?(:remove_attribute)
106
- node.remove_attribute(name)
107
- true
108
- elsif node.respond_to?(:[]=) && node.respond_to?(:[])
109
- # Fallback for different implementations
110
- node[name] = nil
111
- true
112
- else
113
- false
114
- end
115
- end
116
-
117
87
  # Helper method to remove node
118
88
  def remove_node(node)
119
89
  return false unless node.respond_to?(:remove)
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "base_remediation"
4
+ require "set"
4
5
 
5
6
  module SvgConform
6
7
  module Remediations
@@ -105,6 +106,11 @@ module SvgConform
105
106
  remove_node(node)
106
107
  end
107
108
 
109
+ # Clean up unused namespace declarations
110
+ # Note: Moxml/Nokogiri don't support removing namespace declarations directly,
111
+ # so we mark the document for post-processing during serialization
112
+ cleanup_unused_namespace_declarations(document)
113
+
108
114
  changes
109
115
  end
110
116
 
@@ -146,6 +152,60 @@ module SvgConform
146
152
  # Same logic as find_namespace_uri_for_prefix
147
153
  find_namespace_uri_for_prefix(node, prefix)
148
154
  end
155
+
156
+ def cleanup_unused_namespace_declarations(document)
157
+ # Find which namespace prefixes are still in use
158
+ used_prefixes = find_used_namespace_prefixes(document)
159
+
160
+ # Get the root element
161
+ root = document.respond_to?(:root) ? document.root : document
162
+ return unless root.respond_to?(:namespace_definitions)
163
+
164
+ # Get disallowed namespace prefixes
165
+ disallowed_prefixes = root.namespace_definitions.filter_map do |ns|
166
+ prefix = ns.respond_to?(:prefix) ? ns.prefix : nil
167
+ # Extract namespace URI from Moxml::Namespace object
168
+ uri = ns.respond_to?(:uri) ? ns.uri : nil
169
+ next if prefix.nil? || prefix.empty? # Skip default namespace
170
+ next if allowed_namespaces.include?(uri) # Keep allowed namespaces
171
+
172
+ next if used_prefixes.include?(prefix) # Keep prefixes still in use
173
+
174
+ prefix
175
+ end
176
+
177
+ # Store the prefixes to remove on the document for later serialization
178
+ # Try to store on Document wrapper first, fallback to moxml_document
179
+ target = document.respond_to?(:instance_variable_set) ? document : root.document
180
+ target&.instance_variable_set(:@unused_namespace_prefixes, disallowed_prefixes)
181
+ end
182
+
183
+ def find_used_namespace_prefixes(document)
184
+ used_prefixes = Set.new(["xml"]) # xml prefix is always reserved
185
+
186
+ document.traverse do |node|
187
+ next unless node.respond_to?(:name)
188
+
189
+ # Check element name for namespace prefix
190
+ if node.name.include?(":")
191
+ prefix = node.name.split(":").first
192
+ used_prefixes << prefix
193
+ end
194
+
195
+ # Check attributes for namespace prefixes
196
+ if node.respond_to?(:attributes)
197
+ node.attributes.each do |attr|
198
+ attr_name = attr.respond_to?(:name) ? attr.name : attr.to_s
199
+ if attr_name.include?(":")
200
+ prefix = attr_name.split(":").first
201
+ used_prefixes << prefix
202
+ end
203
+ end
204
+ end
205
+ end
206
+
207
+ used_prefixes
208
+ end
149
209
  end
150
210
  end
151
211
  end
@@ -1,9 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "../node_helpers"
4
+
3
5
  module SvgConform
4
6
  module Requirements
5
7
  # Base class for all validation requirements
6
8
  class BaseRequirement < Lutaml::Model::Serializable
9
+ include SvgConform::NodeHelpers
10
+
7
11
  attribute :id, :string
8
12
  attribute :description, :string
9
13
  attribute :type, :string, polymorphic_class: true, default: -> {
@@ -65,48 +69,8 @@ module SvgConform
65
69
  true
66
70
  end
67
71
 
68
- # Helper method to check if a node is an element
69
- def element?(node)
70
- node.respond_to?(:name) && !node.name.nil?
71
- end
72
-
73
- # Helper method to check if a node is text
74
- def text?(node)
75
- node.respond_to?(:text?) && node.text?
76
- end
77
-
78
- # Helper method to get attribute value
79
- def get_attribute(node, name)
80
- return nil unless node.respond_to?(:attribute)
81
-
82
- attr = node.attribute(name)
83
- attr&.value
84
- end
85
-
86
- # Helper method to set attribute value
87
- def set_attribute(node, name, value)
88
- return false unless node.respond_to?(:set_attribute)
89
-
90
- node.set_attribute(name, value)
91
- true
92
- end
93
-
94
- # Helper method to remove attribute
95
- def remove_attribute(node, name)
96
- return false unless node.respond_to?(:remove_attribute)
97
-
98
- node.remove_attribute(name)
99
- true
100
- end
101
-
102
- # Helper method to check if attribute exists
103
- def has_attribute?(node, name)
104
- return false unless node.respond_to?(:attribute)
105
-
106
- !node.attribute(name).nil?
107
- end
108
-
109
72
  # Helper method to get all attributes
73
+ # Note: Other attribute helpers are included via NodeHelpers module
110
74
  def get_attributes(node)
111
75
  return {} unless node.respond_to?(:attributes)
112
76
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SvgConform
4
- VERSION = "0.1.6"
4
+ VERSION = "0.1.7"
5
5
  end
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.1.6
4
+ version: 0.1.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-11-26 00:00:00.000000000 Z
11
+ date: 2026-01-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: lutaml-model
@@ -144,6 +144,7 @@ files:
144
144
  - lib/svg_conform/external_checkers/svgcheck/validation_pipeline.rb
145
145
  - lib/svg_conform/fast_document_analyzer.rb
146
146
  - lib/svg_conform/fixer.rb
147
+ - lib/svg_conform/node_helpers.rb
147
148
  - lib/svg_conform/node_index_builder.rb
148
149
  - lib/svg_conform/profile.rb
149
150
  - lib/svg_conform/profiles.rb