svg_conform 0.1.2 → 0.1.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.
Files changed (28) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop_todo.yml +192 -32
  3. data/README.adoc +55 -0
  4. data/lib/svg_conform/element_proxy.rb +10 -10
  5. data/lib/svg_conform/fast_document_analyzer.rb +22 -22
  6. data/lib/svg_conform/node_index_builder.rb +1 -0
  7. data/lib/svg_conform/requirements/allowed_elements_requirement.rb +29 -9
  8. data/lib/svg_conform/requirements/color_restrictions_requirement.rb +8 -6
  9. data/lib/svg_conform/requirements/font_family_requirement.rb +6 -2
  10. data/lib/svg_conform/requirements/forbidden_content_requirement.rb +2 -2
  11. data/lib/svg_conform/requirements/id_reference_requirement.rb +10 -7
  12. data/lib/svg_conform/requirements/invalid_id_references_requirement.rb +7 -6
  13. data/lib/svg_conform/requirements/link_validation_requirement.rb +2 -2
  14. data/lib/svg_conform/requirements/namespace_attributes_requirement.rb +16 -10
  15. data/lib/svg_conform/requirements/namespace_requirement.rb +11 -10
  16. data/lib/svg_conform/requirements/no_external_css_requirement.rb +4 -4
  17. data/lib/svg_conform/requirements/no_external_fonts_requirement.rb +2 -2
  18. data/lib/svg_conform/requirements/no_external_images_requirement.rb +2 -2
  19. data/lib/svg_conform/requirements/style_promotion_requirement.rb +7 -0
  20. data/lib/svg_conform/requirements/viewbox_required_requirement.rb +7 -7
  21. data/lib/svg_conform/sax_document.rb +2 -2
  22. data/lib/svg_conform/sax_validation_handler.rb +14 -10
  23. data/lib/svg_conform/validation_context.rb +9 -7
  24. data/lib/svg_conform/validator.rb +2 -2
  25. data/lib/svg_conform/version.rb +1 -1
  26. data/spec/spec_helper.rb +3 -0
  27. data/spec/support/shared_examples_for_validation_modes.rb +71 -0
  28. metadata +3 -2
@@ -26,7 +26,7 @@ module SvgConform
26
26
  # Also marks all descendants as invalid since they'll be removed with the parent
27
27
  def mark_node_structurally_invalid(node)
28
28
  node_id = generate_node_id(node)
29
- return if node_id.nil? # Safety check
29
+ return if node_id.nil? # Safety check
30
30
 
31
31
  @structurally_invalid_node_ids.add(node_id)
32
32
 
@@ -36,11 +36,13 @@ module SvgConform
36
36
 
37
37
  # Mark all descendants of a node as structurally invalid
38
38
  def mark_descendants_invalid(node)
39
- return unless node.respond_to?(:children)
39
+ # In SAX mode, ElementProxy doesn't have children yet
40
+ # Children will be validated individually and will check parent validity
41
+ return unless node.respond_to?(:children) && node.children
40
42
 
41
43
  node.children.each do |child|
42
44
  child_id = generate_node_id(child)
43
- return if child_id.nil? # Safety check
45
+ next if child_id.nil? # Skip if can't generate ID
44
46
 
45
47
  @structurally_invalid_node_ids.add(child_id)
46
48
  # Recursively mark descendants
@@ -51,7 +53,7 @@ module SvgConform
51
53
  # Check if a node is structurally invalid
52
54
  def node_structurally_invalid?(node)
53
55
  node_id = generate_node_id(node)
54
- return false if node_id.nil? # Safety check
56
+ return false if node_id.nil? # Safety check
55
57
 
56
58
  @structurally_invalid_node_ids.include?(node_id)
57
59
  end
@@ -152,7 +154,7 @@ requirement_id: nil, severity: nil, fix: nil, data: {})
152
154
  # Populate cache for all nodes using document.traverse with parent tracking
153
155
  def populate_node_id_cache
154
156
  parent_stack = []
155
- counter_stack = [{}] # Stack of {element_name => count} hashes
157
+ counter_stack = [{}] # Stack of {element_name => count} hashes
156
158
 
157
159
  @document.traverse do |node|
158
160
  next unless node.respond_to?(:name) && node.name
@@ -161,7 +163,7 @@ requirement_id: nil, severity: nil, fix: nil, data: {})
161
163
  current_parent = node.respond_to?(:parent) ? node.parent : nil
162
164
 
163
165
  # Adjust stack based on actual parent
164
- while parent_stack.size > 0 && !parent_stack.last.equal?(current_parent)
166
+ while parent_stack.size.positive? && !parent_stack.last.equal?(current_parent)
165
167
  parent_stack.pop
166
168
  counter_stack.pop
167
169
  end
@@ -187,7 +189,7 @@ requirement_id: nil, severity: nil, fix: nil, data: {})
187
189
  return unless node.respond_to?(:name) && node.name
188
190
 
189
191
  # Increment counter for this node name at current level
190
- sibling_counters[node.name] ||= 0
192
+ sibling_counters[node.name] ||= 0
191
193
  sibling_counters[node.name] += 1
192
194
  position = sibling_counters[node.name]
193
195
 
@@ -9,7 +9,7 @@ module SvgConform
9
9
  @options = {
10
10
  fix: false,
11
11
  strict: false,
12
- mode: :auto # :auto, :dom, or :sax
12
+ mode: :sax, # Testing SAX mode
13
13
  }.merge(options)
14
14
  end
15
15
 
@@ -152,7 +152,7 @@ module SvgConform
152
152
  warnings: [],
153
153
  file_path: file_path,
154
154
  error?: true,
155
- to_s: -> { "Error processing #{file_path}: #{error.message}" }
155
+ to_s: -> { "Error processing #{file_path}: #{error.message}" },
156
156
  )
157
157
  end
158
158
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SvgConform
4
- VERSION = "0.1.2"
4
+ VERSION = "0.1.3"
5
5
  end
data/spec/spec_helper.rb CHANGED
@@ -3,6 +3,9 @@
3
3
  require "svg_conform"
4
4
  require "canon"
5
5
 
6
+ # Load shared examples
7
+ Dir[File.expand_path("support/**/*.rb", __dir__)].each { |f| require f }
8
+
6
9
  RSpec.configure do |config|
7
10
  # Enable flags like --only-failures and --next-failure
8
11
  config.example_status_persistence_file_path = ".rspec_status"
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Shared examples for testing both DOM and SAX validation modes
4
+ RSpec.shared_examples "validates in both DOM and SAX modes" do |file_path, profile_name|
5
+ let(:file_path) { file_path }
6
+ let(:profile) { profile_name }
7
+
8
+ it "produces identical results in DOM and SAX modes" do
9
+ dom_result = SvgConform::Validator.new(mode: :dom).validate_file(file_path,
10
+ profile: profile)
11
+ sax_result = SvgConform::Validator.new(mode: :sax).validate_file(file_path,
12
+ profile: profile)
13
+
14
+ expect(sax_result.errors.size).to eq(dom_result.errors.size),
15
+ "SAX mode should produce same error count as DOM mode (DOM: #{dom_result.errors.size}, SAX: #{sax_result.errors.size})"
16
+
17
+ expect(sax_result.warnings.size).to eq(dom_result.warnings.size),
18
+ "SAX mode should produce same warning count as DOM mode"
19
+
20
+ expect(sax_result.valid?).to eq(dom_result.valid?),
21
+ "SAX mode should have same validity as DOM mode"
22
+ end
23
+
24
+ it "DOM mode validates correctly" do
25
+ result = SvgConform::Validator.new(mode: :dom).validate_file(file_path,
26
+ profile: profile)
27
+ expect(result).to be_a(SvgConform::ValidationResult)
28
+ end
29
+
30
+ it "SAX mode validates correctly" do
31
+ result = SvgConform::Validator.new(mode: :sax).validate_file(file_path,
32
+ profile: profile)
33
+ expect(result).to be_a(SvgConform::ValidationResult)
34
+ end
35
+
36
+ describe "performance comparison" do
37
+ it "SAX mode is faster than or equal to DOM mode" do
38
+ skip "Performance test - run manually for large files"
39
+
40
+ dom_time = Benchmark.realtime do
41
+ SvgConform::Validator.new(mode: :dom).validate_file(file_path,
42
+ profile: profile)
43
+ end
44
+
45
+ sax_time = Benchmark.realtime do
46
+ SvgConform::Validator.new(mode: :sax).validate_file(file_path,
47
+ profile: profile)
48
+ end
49
+
50
+ expect(sax_time).to be <= dom_time
51
+ end
52
+ end
53
+ end
54
+
55
+ RSpec.shared_examples "validates content in both modes" do |svg_content, profile_name|
56
+ let(:content) { svg_content }
57
+ let(:profile) { profile_name }
58
+
59
+ it "produces identical results for content validation" do
60
+ dom_result = SvgConform::Validator.new(mode: :dom).validate(content,
61
+ profile: profile)
62
+ sax_result = SvgConform::Validator.new(mode: :sax).validate(content,
63
+ profile: profile)
64
+
65
+ expect(sax_result.errors.size).to eq(dom_result.errors.size),
66
+ "SAX mode should produce same error count as DOM mode (DOM: #{dom_result.errors.size}, SAX: #{sax_result.errors.size})"
67
+
68
+ expect(sax_result.valid?).to eq(dom_result.valid?),
69
+ "SAX mode should have same validity as DOM mode"
70
+ end
71
+ 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.2
4
+ version: 0.1.3
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-18 00:00:00.000000000 Z
11
+ date: 2025-11-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: lutaml-model
@@ -372,6 +372,7 @@ files:
372
372
  - spec/fixtures/viewbox_required/inputs/missing_viewbox.svg
373
373
  - spec/fixtures/viewbox_required/repair/missing_viewbox.svg
374
374
  - spec/spec_helper.rb
375
+ - spec/support/shared_examples_for_validation_modes.rb
375
376
  - spec/svg_conform/batch_report_spec.rb
376
377
  - spec/svg_conform/commands/check_command_spec.rb
377
378
  - spec/svg_conform/commands/profiles_command_spec.rb