svg_conform 0.1.4 → 0.1.5

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 (38) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop_todo.yml +182 -21
  3. data/README.adoc +391 -989
  4. data/config/profiles/metanorma.yml +5 -0
  5. data/docs/api_reference.adoc +1355 -0
  6. data/docs/cli_guide.adoc +846 -0
  7. data/docs/reference_manifest.adoc +370 -0
  8. data/docs/requirements.adoc +68 -1
  9. data/examples/document_input_demo.rb +102 -0
  10. data/lib/svg_conform/document.rb +40 -1
  11. data/lib/svg_conform/profile.rb +15 -9
  12. data/lib/svg_conform/references/base_reference.rb +130 -0
  13. data/lib/svg_conform/references/id_definition.rb +38 -0
  14. data/lib/svg_conform/references/reference_classifier.rb +45 -0
  15. data/lib/svg_conform/references/reference_manifest.rb +129 -0
  16. data/lib/svg_conform/references.rb +11 -0
  17. data/lib/svg_conform/remediations/namespace_attribute_remediation.rb +34 -43
  18. data/lib/svg_conform/requirements/id_collection_requirement.rb +38 -0
  19. data/lib/svg_conform/requirements/id_reference_requirement.rb +11 -0
  20. data/lib/svg_conform/requirements/invalid_id_references_requirement.rb +3 -0
  21. data/lib/svg_conform/requirements/link_validation_requirement.rb +114 -31
  22. data/lib/svg_conform/requirements/no_external_css_requirement.rb +5 -2
  23. data/lib/svg_conform/requirements.rb +11 -9
  24. data/lib/svg_conform/sax_validation_handler.rb +16 -1
  25. data/lib/svg_conform/validation_context.rb +67 -1
  26. data/lib/svg_conform/validation_result.rb +43 -2
  27. data/lib/svg_conform/validator.rb +56 -16
  28. data/lib/svg_conform/version.rb +1 -1
  29. data/lib/svg_conform.rb +11 -2
  30. data/spec/svg_conform/commands/svgcheck_compare_command_spec.rb +1 -0
  31. data/spec/svg_conform/commands/svgcheck_compatibility_command_spec.rb +1 -0
  32. data/spec/svg_conform/commands/svgcheck_generate_command_spec.rb +1 -0
  33. data/spec/svg_conform/references/integration_spec.rb +206 -0
  34. data/spec/svg_conform/references/reference_classifier_spec.rb +142 -0
  35. data/spec/svg_conform/references/reference_manifest_spec.rb +307 -0
  36. data/spec/svg_conform/requirements/id_reference_state_spec.rb +93 -0
  37. data/spec/svg_conform/validator_input_types_spec.rb +172 -0
  38. metadata +17 -2
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe "IdReferenceRequirement" do
6
+ let(:validator) { SvgConform::Validator.new(mode: :sax) }
7
+
8
+ # SVG with a reference to undefined ID 'missing_id'
9
+ let(:svg_with_error) do
10
+ <<~SVG
11
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
12
+ <a href="#missing_id">
13
+ <rect x="10" y="10" width="80" height="80"/>
14
+ </a>
15
+ </svg>
16
+ SVG
17
+ end
18
+
19
+ # SVG with valid references only
20
+ let(:svg_without_error) do
21
+ <<~SVG
22
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
23
+ <rect id="valid_id" x="10" y="10" width="80" height="80"/>
24
+ <a href="#valid_id">
25
+ <text x="50" y="50">Link</text>
26
+ </a>
27
+ </svg>
28
+ SVG
29
+ end
30
+
31
+ it "does not leak state from first validation to second validation" do
32
+ # First validation: SVG with reference error
33
+ result1 = validator.validate(svg_with_error, profile: :metanorma)
34
+
35
+ # Verify first validation caught the error
36
+ expect(result1.errors.map(&:message)).to include(
37
+ match(/Reference to undefined ID 'missing_id'/),
38
+ )
39
+
40
+ # Second validation: SVG without reference errors
41
+ result2 = validator.validate(svg_without_error, profile: :metanorma)
42
+
43
+ # Verify second validation does NOT report errors from first validation
44
+ error_messages = result2.errors.map(&:message).join("\n")
45
+ expect(error_messages).not_to include("missing_id"),
46
+ "State leaked from first validation! Second validation should not mention 'missing_id'"
47
+
48
+ # Second validation should have no errors (or at least no reference errors)
49
+ reference_errors = result2.errors.select do |e|
50
+ e.message.include?("Reference to undefined")
51
+ end
52
+ expect(reference_errors).to be_empty,
53
+ "Second validation should have no reference errors, but got: #{reference_errors.map(&:message)}"
54
+ end
55
+
56
+ it "handles multiple sequential validations correctly" do
57
+ # Run multiple validations to ensure state resets each time
58
+ results = []
59
+
60
+ # Alternate between error and no-error SVGs
61
+ 3.times do
62
+ results << validator.validate(svg_with_error, profile: :metanorma)
63
+ results << validator.validate(svg_without_error, profile: :metanorma)
64
+ end
65
+
66
+ # Check that error pattern is consistent
67
+ results.each_with_index do |result, i|
68
+ if i.even?
69
+ # Should have error (svg_with_error)
70
+ expect(result.errors.map(&:message)).to include(
71
+ match(/Reference to undefined ID 'missing_id'/),
72
+ )
73
+ else
74
+ # Should NOT have error about missing_id (svg_without_error)
75
+ error_messages = result.errors.map(&:message).join("\n")
76
+ expect(error_messages).not_to include("missing_id")
77
+ end
78
+ end
79
+ end
80
+
81
+ it "resets state when using the same profile instance" do
82
+ # Get profile instance
83
+ profile = SvgConform::Profiles.get(:metanorma)
84
+
85
+ # Run two validations using the same profile
86
+ validator.validate(svg_with_error, profile: profile)
87
+ result2 = validator.validate(svg_without_error, profile: profile)
88
+
89
+ # Second validation should not have first validation's errors
90
+ error_messages = result2.errors.map(&:message).join("\n")
91
+ expect(error_messages).not_to include("missing_id")
92
+ end
93
+ end
@@ -0,0 +1,172 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe SvgConform::Validator do
6
+ let(:validator) { described_class.new(mode: :sax) }
7
+ let(:simple_svg) do
8
+ <<~SVG
9
+ <?xml version="1.0" encoding="UTF-8"?>
10
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
11
+ <rect id="box" x="10" y="10" width="80" height="80" fill="black"/>
12
+ </svg>
13
+ SVG
14
+ end
15
+
16
+ describe "#validate with different input types" do
17
+ context "with String input (backward compatibility)" do
18
+ it "validates XML string successfully" do
19
+ result = validator.validate(simple_svg, profile: :metanorma)
20
+
21
+ expect(result).to be_a(SvgConform::ValidationResult)
22
+ expect(result.valid?).to be true
23
+ end
24
+
25
+ it "processes errors correctly" do
26
+ invalid_svg = '<svg><rect fill="red"/></svg>'
27
+ result = validator.validate(invalid_svg, profile: :svg_1_2_rfc)
28
+
29
+ expect(result).to be_a(SvgConform::ValidationResult)
30
+ # Will have errors due to missing viewBox and invalid color
31
+ end
32
+ end
33
+
34
+ context "with Moxml::Document input" do
35
+ it "validates Moxml document without re-parsing" do
36
+ # Parse once into Moxml
37
+ moxml_doc = Moxml.new.parse(simple_svg)
38
+
39
+ # Validate using the document object
40
+ result = validator.validate(moxml_doc, profile: :metanorma)
41
+
42
+ expect(result).to be_a(SvgConform::ValidationResult)
43
+ expect(result.valid?).to be true
44
+ end
45
+
46
+ it "serializes document once for SAX validation (safe for large files)" do
47
+ moxml_doc = Moxml.new.parse(simple_svg)
48
+
49
+ # Should call to_xml once for SAX validation
50
+ # (SAX mode is safe for large files, unlike DOM)
51
+ expect(moxml_doc).to receive(:to_xml).once.and_call_original
52
+
53
+ validator.validate(moxml_doc, profile: :metanorma)
54
+ end
55
+ end
56
+
57
+ context "with Moxml::Element input" do
58
+ it "validates Moxml element node" do
59
+ moxml_doc = Moxml.new.parse(simple_svg)
60
+ svg_element = moxml_doc.root
61
+
62
+ result = validator.validate(svg_element, profile: :metanorma)
63
+
64
+ expect(result).to be_a(SvgConform::ValidationResult)
65
+ expect(result.valid?).to be true
66
+ end
67
+ end
68
+
69
+ context "with Nokogiri input (metanorm use case)" do
70
+ it "validates Nokogiri::XML::Document" do
71
+ nokogiri_doc = Nokogiri::XML(simple_svg)
72
+
73
+ result = validator.validate(nokogiri_doc, profile: :metanorma)
74
+
75
+ expect(result).to be_a(SvgConform::ValidationResult)
76
+ expect(result.valid?).to be true
77
+ end
78
+
79
+ it "validates Nokogiri::XML::Element" do
80
+ nokogiri_doc = Nokogiri::XML(simple_svg)
81
+ svg_element = nokogiri_doc.root
82
+
83
+ # This is the metanorma use case - passing element directly
84
+ result = validator.validate(svg_element, profile: :metanorma)
85
+
86
+ expect(result).to be_a(SvgConform::ValidationResult)
87
+ expect(result.valid?).to be true
88
+ end
89
+
90
+ it "serializes Nokogiri element once for SAX validation" do
91
+ nokogiri_doc = Nokogiri::XML(simple_svg)
92
+ svg_element = nokogiri_doc.root
93
+
94
+ # Should call to_xml once for SAX validation
95
+ # (SAX mode is memory-safe for large SVGs)
96
+ expect(svg_element).to receive(:to_xml).once.and_call_original
97
+
98
+ validator.validate(svg_element, profile: :metanorma)
99
+ end
100
+ end
101
+
102
+ context "with invalid input" do
103
+ it "raises ArgumentError for unsupported input type" do
104
+ expect do
105
+ validator.validate(12345, profile: :metanorma)
106
+ end.to raise_error(ArgumentError, /Invalid input type/)
107
+ end
108
+
109
+ it "raises ArgumentError for nil input" do
110
+ expect do
111
+ validator.validate(nil, profile: :metanorma)
112
+ end.to raise_error(ArgumentError, /Invalid input type/)
113
+ end
114
+ end
115
+
116
+ context "with reference manifest" do
117
+ let(:svg_with_refs) do
118
+ <<~SVG
119
+ <?xml version="1.0" encoding="UTF-8"?>
120
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
121
+ <defs>
122
+ <rect id="box" width="10" height="10"/>
123
+ </defs>
124
+ <use href="#box" x="20" y="20"/>
125
+ </svg>
126
+ SVG
127
+ end
128
+
129
+ it "builds reference manifest from Nokogiri element" do
130
+ nokogiri_doc = Nokogiri::XML(svg_with_refs)
131
+ svg_element = nokogiri_doc.root
132
+
133
+ result = validator.validate(svg_element, profile: :metanorma)
134
+
135
+ expect(result.reference_manifest).not_to be_nil
136
+ expect(result.available_ids.map(&:id_value)).to include("box")
137
+ expect(result.internal_references.size).to be > 0
138
+ end
139
+
140
+ it "builds reference manifest from Moxml document" do
141
+ moxml_doc = Moxml.new.parse(svg_with_refs)
142
+
143
+ result = validator.validate(moxml_doc, profile: :metanorma)
144
+
145
+ expect(result.reference_manifest).not_to be_nil
146
+ expect(result.available_ids.map(&:id_value)).to include("box")
147
+ end
148
+ end
149
+ end
150
+
151
+ describe "integration with remediation" do
152
+ let(:invalid_svg) do
153
+ <<~SVG
154
+ <?xml version="1.0" encoding="UTF-8"?>
155
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
156
+ <rect fill="red" width="10" height="10"/>
157
+ </svg>
158
+ SVG
159
+ end
160
+
161
+ it "applies remediation when using document object input" do
162
+ nokogiri_doc = Nokogiri::XML(invalid_svg)
163
+ svg_element = nokogiri_doc.root
164
+
165
+ result = validator.validate(svg_element, profile: :svg_1_2_rfc, fix: true)
166
+
167
+ # Should have validation errors initially
168
+ expect(result.has_errors?).to be true
169
+ # Remediation should have been attempted
170
+ end
171
+ end
172
+ 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.4
4
+ version: 0.1.5
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-19 00:00:00.000000000 Z
11
+ date: 2025-11-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: lutaml-model
@@ -92,11 +92,15 @@ files:
92
92
  - config/profiles/svg_1_2_rfc.yml
93
93
  - config/profiles/svg_1_2_rfc_with_rdf.yml
94
94
  - config/svgcheck_mapping.yml
95
+ - docs/api_reference.adoc
96
+ - docs/cli_guide.adoc
95
97
  - docs/profiles.adoc
96
98
  - docs/rdf_metadata_support.adoc
99
+ - docs/reference_manifest.adoc
97
100
  - docs/remediation.adoc
98
101
  - docs/requirements.adoc
99
102
  - examples/demo.rb
103
+ - examples/document_input_demo.rb
100
104
  - examples/readme_usage.rb
101
105
  - examples/requirements_demo.rb
102
106
  - exe/svg_conform
@@ -137,6 +141,11 @@ files:
137
141
  - lib/svg_conform/node_index_builder.rb
138
142
  - lib/svg_conform/profile.rb
139
143
  - lib/svg_conform/profiles.rb
144
+ - lib/svg_conform/references.rb
145
+ - lib/svg_conform/references/base_reference.rb
146
+ - lib/svg_conform/references/id_definition.rb
147
+ - lib/svg_conform/references/reference_classifier.rb
148
+ - lib/svg_conform/references/reference_manifest.rb
140
149
  - lib/svg_conform/remediation_engine.rb
141
150
  - lib/svg_conform/remediation_result.rb
142
151
  - lib/svg_conform/remediation_runner.rb
@@ -160,6 +169,7 @@ files:
160
169
  - lib/svg_conform/requirements/element_requirement_config.rb
161
170
  - lib/svg_conform/requirements/font_family_requirement.rb
162
171
  - lib/svg_conform/requirements/forbidden_content_requirement.rb
172
+ - lib/svg_conform/requirements/id_collection_requirement.rb
163
173
  - lib/svg_conform/requirements/id_reference_requirement.rb
164
174
  - lib/svg_conform/requirements/invalid_id_references_requirement.rb
165
175
  - lib/svg_conform/requirements/link_validation_requirement.rb
@@ -386,6 +396,9 @@ files:
386
396
  - spec/svg_conform/profiles/no_external_css_profile_spec.rb
387
397
  - spec/svg_conform/profiles/svg_1_2_rfc_profile_spec.rb
388
398
  - spec/svg_conform/profiles/svg_1_2_rfc_with_rdf_profile_spec.rb
399
+ - spec/svg_conform/references/integration_spec.rb
400
+ - spec/svg_conform/references/reference_classifier_spec.rb
401
+ - spec/svg_conform/references/reference_manifest_spec.rb
389
402
  - spec/svg_conform/remediations/color_remediation_spec.rb
390
403
  - spec/svg_conform/remediations/font_embedding_remediation_spec.rb
391
404
  - spec/svg_conform/remediations/font_remediation_spec.rb
@@ -401,6 +414,7 @@ files:
401
414
  - spec/svg_conform/requirements/font_family_requirement_spec.rb
402
415
  - spec/svg_conform/requirements/forbidden_content_requirement_spec.rb
403
416
  - spec/svg_conform/requirements/id_reference_requirement_spec.rb
417
+ - spec/svg_conform/requirements/id_reference_state_spec.rb
404
418
  - spec/svg_conform/requirements/invalid_id_references_requirement_spec.rb
405
419
  - spec/svg_conform/requirements/link_validation_requirement_spec.rb
406
420
  - spec/svg_conform/requirements/namespace_attributes_requirement_spec.rb
@@ -411,6 +425,7 @@ files:
411
425
  - spec/svg_conform/requirements/style_promotion_requirement_spec.rb
412
426
  - spec/svg_conform/requirements/style_requirement_spec.rb
413
427
  - spec/svg_conform/requirements/viewbox_required_requirement_spec.rb
428
+ - spec/svg_conform/validator_input_types_spec.rb
414
429
  - spec/svg_conform_spec.rb
415
430
  - spec/svgcheck_compatibility_spec.rb
416
431
  - svg_conform.gemspec