svg_conform 0.1.0
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 +7 -0
- data/.github/workflows/rake.yml +15 -0
- data/.github/workflows/release.yml +23 -0
- data/.github/workflows/svgcheck-compatibility.yml +135 -0
- data/.gitignore +12 -0
- data/.rspec +3 -0
- data/.rubocop.yml +13 -0
- data/.rubocop_todo.yml +183 -0
- data/CODE_OF_CONDUCT.md +132 -0
- data/Gemfile +14 -0
- data/README.adoc +1384 -0
- data/Rakefile +15 -0
- data/config/profiles/base.yml +34 -0
- data/config/profiles/lucid_fix.yml +37 -0
- data/config/profiles/metanorma.yml +212 -0
- data/config/profiles/no_external_css.yml +20 -0
- data/config/profiles/svg_1_2_rfc.yml +284 -0
- data/config/profiles/svg_1_2_rfc_with_rdf.yml +145 -0
- data/config/svgcheck_mapping.yml +180 -0
- data/docs/profiles.adoc +547 -0
- data/docs/rdf_metadata_support.adoc +212 -0
- data/docs/remediation.adoc +732 -0
- data/docs/requirements.adoc +709 -0
- data/examples/demo.rb +116 -0
- data/examples/requirements_demo.rb +240 -0
- data/exe/svg_conform +7 -0
- data/lib/svg_conform/batch_report.rb +70 -0
- data/lib/svg_conform/cli.rb +107 -0
- data/lib/svg_conform/commands/check.rb +390 -0
- data/lib/svg_conform/commands/profiles.rb +118 -0
- data/lib/svg_conform/commands/svgcheck.rb +90 -0
- data/lib/svg_conform/commands/svgcheck_compare.rb +92 -0
- data/lib/svg_conform/commands/svgcheck_compatibility.rb +43 -0
- data/lib/svg_conform/commands/svgcheck_generate.rb +262 -0
- data/lib/svg_conform/compatibility/analysis_context.rb +68 -0
- data/lib/svg_conform/compatibility/comparison_result.rb +147 -0
- data/lib/svg_conform/compatibility/compatibility_analyzer.rb +85 -0
- data/lib/svg_conform/compatibility/file_processor.rb +109 -0
- data/lib/svg_conform/compatibility/pattern_discovery.rb +319 -0
- data/lib/svg_conform/compatibility/report_formatter.rb +359 -0
- data/lib/svg_conform/compatibility/svg_analysis_engine.rb +316 -0
- data/lib/svg_conform/compatibility/validity_analysis.rb +252 -0
- data/lib/svg_conform/compatibility/xml_analysis_engine.rb +198 -0
- data/lib/svg_conform/compatibility_analyzer.rb +285 -0
- data/lib/svg_conform/conformance_report.rb +267 -0
- data/lib/svg_conform/constants.rb +199 -0
- data/lib/svg_conform/css_color.rb +262 -0
- data/lib/svg_conform/document.rb +203 -0
- data/lib/svg_conform/external_checkers/svgcheck/compatibility_engine.rb +166 -0
- data/lib/svg_conform/external_checkers/svgcheck/output_generator.rb +101 -0
- data/lib/svg_conform/external_checkers/svgcheck/parser.rb +200 -0
- data/lib/svg_conform/external_checkers/svgcheck/report_comparator.rb +175 -0
- data/lib/svg_conform/external_checkers/svgcheck/report_generator.rb +82 -0
- data/lib/svg_conform/external_checkers/svgcheck/validation_pipeline.rb +249 -0
- data/lib/svg_conform/external_checkers/svgcheck.rb +56 -0
- data/lib/svg_conform/external_checkers.rb +34 -0
- data/lib/svg_conform/fixer.rb +56 -0
- data/lib/svg_conform/profile.rb +164 -0
- data/lib/svg_conform/profiles.rb +60 -0
- data/lib/svg_conform/remediation_engine.rb +92 -0
- data/lib/svg_conform/remediation_result.rb +36 -0
- data/lib/svg_conform/remediation_runner.rb +225 -0
- data/lib/svg_conform/remediations/base_remediation.rb +165 -0
- data/lib/svg_conform/remediations/color_remediation.rb +226 -0
- data/lib/svg_conform/remediations/font_embedding_remediation.rb +145 -0
- data/lib/svg_conform/remediations/font_remediation.rb +122 -0
- data/lib/svg_conform/remediations/image_embedding_remediation.rb +154 -0
- data/lib/svg_conform/remediations/invalid_id_references_remediation.rb +129 -0
- data/lib/svg_conform/remediations/namespace_attribute_remediation.rb +244 -0
- data/lib/svg_conform/remediations/namespace_remediation.rb +151 -0
- data/lib/svg_conform/remediations/no_external_css_remediation.rb +192 -0
- data/lib/svg_conform/remediations/style_promotion_remediation.rb +93 -0
- data/lib/svg_conform/remediations/viewbox_remediation.rb +127 -0
- data/lib/svg_conform/remediations.rb +40 -0
- data/lib/svg_conform/report_comparator.rb +772 -0
- data/lib/svg_conform/requirements/allowed_elements_requirement.rb +367 -0
- data/lib/svg_conform/requirements/base_requirement.rb +98 -0
- data/lib/svg_conform/requirements/color_restrictions_requirement.rb +126 -0
- data/lib/svg_conform/requirements/element_requirement_config.rb +75 -0
- data/lib/svg_conform/requirements/font_family_requirement.rb +133 -0
- data/lib/svg_conform/requirements/forbidden_content_requirement.rb +60 -0
- data/lib/svg_conform/requirements/id_reference_requirement.rb +133 -0
- data/lib/svg_conform/requirements/invalid_id_references_requirement.rb +132 -0
- data/lib/svg_conform/requirements/link_validation_requirement.rb +55 -0
- data/lib/svg_conform/requirements/namespace_attributes_requirement.rb +211 -0
- data/lib/svg_conform/requirements/namespace_requirement.rb +294 -0
- data/lib/svg_conform/requirements/no_external_css_requirement.rb +132 -0
- data/lib/svg_conform/requirements/no_external_fonts_requirement.rb +121 -0
- data/lib/svg_conform/requirements/no_external_images_requirement.rb +91 -0
- data/lib/svg_conform/requirements/style_promotion_requirement.rb +72 -0
- data/lib/svg_conform/requirements/style_requirement.rb +226 -0
- data/lib/svg_conform/requirements/viewbox_required_requirement.rb +96 -0
- data/lib/svg_conform/requirements.rb +49 -0
- data/lib/svg_conform/semantic_comparator.rb +829 -0
- data/lib/svg_conform/validation_context.rb +408 -0
- data/lib/svg_conform/validation_result.rb +146 -0
- data/lib/svg_conform/validator.rb +91 -0
- data/lib/svg_conform/version.rb +5 -0
- data/lib/svg_conform.rb +68 -0
- data/lib/tasks/fixtures.rake +321 -0
- data/lib/tasks/svgcheck.rake +111 -0
- data/reference-docs/SVG-1.2-RFC.rnc.txt +1676 -0
- data/reference-docs/Scalable Vector Graphics (SVG) 1.1 (Second Edition).html +40764 -0
- data/reference-docs/Scalable Vector Graphics (SVG) Tiny 1.2 Specification.html +44591 -0
- data/reference-docs/rfc7996.txt +2971 -0
- data/sig/svg_conform.rbs +4 -0
- data/spec/fixtures/allowed_elements/inputs/basic_violations.svg +21 -0
- data/spec/fixtures/allowed_elements/repair/basic_violations.svg +18 -0
- data/spec/fixtures/color_restrictions/inputs/basic_violations.svg +23 -0
- data/spec/fixtures/color_restrictions/repair/basic_violations.svg +23 -0
- data/spec/fixtures/comprehensive/inputs/multiple_violations.svg +21 -0
- data/spec/fixtures/comprehensive/repair/multiple_violations.svg +16 -0
- data/spec/fixtures/font_family/inputs/basic_violations.svg +17 -0
- data/spec/fixtures/font_family/repair/basic_violations.svg +17 -0
- data/spec/fixtures/forbidden_content/inputs/basic_violations.svg +27 -0
- data/spec/fixtures/forbidden_content/repair/basic_violations.svg +19 -0
- data/spec/fixtures/id_reference/inputs/basic_violations.svg +17 -0
- data/spec/fixtures/id_reference/repair/basic_violations.svg +15 -0
- data/spec/fixtures/link_validation/inputs/basic_violations.svg +20 -0
- data/spec/fixtures/link_validation/repair/basic_violations.svg +16 -0
- data/spec/fixtures/lucid/inputs/simple.svg +67 -0
- data/spec/fixtures/lucid/repair/simple.svg +63 -0
- data/spec/fixtures/namespace/inputs/basic_violations.svg +20 -0
- data/spec/fixtures/namespace/repair/basic_violations.svg +17 -0
- data/spec/fixtures/namespace_attributes/inputs/basic_violations.svg +16 -0
- data/spec/fixtures/namespace_attributes/repair/basic_violations.svg +15 -0
- data/spec/fixtures/no_external_css/inputs/basic_violations.svg +20 -0
- data/spec/fixtures/no_external_css/repair/basic_violations.svg +18 -0
- data/spec/fixtures/style/inputs/basic_violations.svg +22 -0
- data/spec/fixtures/style/repair/basic_violations.svg +22 -0
- data/spec/fixtures/style_promotion/inputs/basic_test.svg +15 -0
- data/spec/fixtures/style_promotion/repair/basic_test.svg +15 -0
- data/spec/fixtures/svg_1_2_rfc/inputs/allowed_elements_violations.svg +18 -0
- data/spec/fixtures/svg_1_2_rfc/inputs/color_restrictions_violations.svg +23 -0
- data/spec/fixtures/svgcheck/check/DrawBerry-sample-2.svg.code +1 -0
- data/spec/fixtures/svgcheck/check/DrawBerry-sample-2.svg.err +0 -0
- data/spec/fixtures/svgcheck/check/DrawBerry-sample-2.svg.out +23 -0
- data/spec/fixtures/svgcheck/check/IETF-test.svg.code +1 -0
- data/spec/fixtures/svgcheck/check/IETF-test.svg.err +0 -0
- data/spec/fixtures/svgcheck/check/IETF-test.svg.out +20 -0
- data/spec/fixtures/svgcheck/check/circle.svg.code +1 -0
- data/spec/fixtures/svgcheck/check/circle.svg.err +0 -0
- data/spec/fixtures/svgcheck/check/circle.svg.out +2 -0
- data/spec/fixtures/svgcheck/check/colors.svg.code +1 -0
- data/spec/fixtures/svgcheck/check/colors.svg.err +0 -0
- data/spec/fixtures/svgcheck/check/colors.svg.out +13 -0
- data/spec/fixtures/svgcheck/check/dia-sample-svg.svg.code +1 -0
- data/spec/fixtures/svgcheck/check/dia-sample-svg.svg.err +0 -0
- data/spec/fixtures/svgcheck/check/dia-sample-svg.svg.out +76 -0
- data/spec/fixtures/svgcheck/check/example-dot.svg.code +1 -0
- data/spec/fixtures/svgcheck/check/example-dot.svg.err +0 -0
- data/spec/fixtures/svgcheck/check/example-dot.svg.out +11 -0
- data/spec/fixtures/svgcheck/check/full-tiny.svg.code +1 -0
- data/spec/fixtures/svgcheck/check/full-tiny.svg.err +0 -0
- data/spec/fixtures/svgcheck/check/full-tiny.svg.out +5835 -0
- data/spec/fixtures/svgcheck/check/good.svg.code +1 -0
- data/spec/fixtures/svgcheck/check/good.svg.err +0 -0
- data/spec/fixtures/svgcheck/check/good.svg.out +1 -0
- data/spec/fixtures/svgcheck/check/httpbis-proxy20-fig6.svg.code +1 -0
- data/spec/fixtures/svgcheck/check/httpbis-proxy20-fig6.svg.err +0 -0
- data/spec/fixtures/svgcheck/check/httpbis-proxy20-fig6.svg.out +5 -0
- data/spec/fixtures/svgcheck/check/malformed.svg.code +1 -0
- data/spec/fixtures/svgcheck/check/malformed.svg.err +0 -0
- data/spec/fixtures/svgcheck/check/malformed.svg.out +8 -0
- data/spec/fixtures/svgcheck/check/rfc-svg.svg.code +1 -0
- data/spec/fixtures/svgcheck/check/rfc-svg.svg.err +0 -0
- data/spec/fixtures/svgcheck/check/rfc-svg.svg.out +1 -0
- data/spec/fixtures/svgcheck/check/rfc.xml.code +1 -0
- data/spec/fixtures/svgcheck/check/rfc.xml.err +0 -0
- data/spec/fixtures/svgcheck/check/rfc.xml.out +2 -0
- data/spec/fixtures/svgcheck/check/rgb.svg.code +1 -0
- data/spec/fixtures/svgcheck/check/rgb.svg.err +0 -0
- data/spec/fixtures/svgcheck/check/rgb.svg.out +9 -0
- data/spec/fixtures/svgcheck/check/svg-wordle.svg.code +1 -0
- data/spec/fixtures/svgcheck/check/svg-wordle.svg.err +0 -0
- data/spec/fixtures/svgcheck/check/svg-wordle.svg.out +508 -0
- data/spec/fixtures/svgcheck/check/threshold.svg.code +1 -0
- data/spec/fixtures/svgcheck/check/threshold.svg.err +0 -0
- data/spec/fixtures/svgcheck/check/threshold.svg.out +20 -0
- data/spec/fixtures/svgcheck/check/utf8.svg.code +1 -0
- data/spec/fixtures/svgcheck/check/utf8.svg.err +0 -0
- data/spec/fixtures/svgcheck/check/utf8.svg.out +162 -0
- data/spec/fixtures/svgcheck/check/viewBox-both.svg.code +1 -0
- data/spec/fixtures/svgcheck/check/viewBox-both.svg.err +0 -0
- data/spec/fixtures/svgcheck/check/viewBox-both.svg.out +4 -0
- data/spec/fixtures/svgcheck/check/viewBox-height.svg.code +1 -0
- data/spec/fixtures/svgcheck/check/viewBox-height.svg.err +0 -0
- data/spec/fixtures/svgcheck/check/viewBox-height.svg.out +3 -0
- data/spec/fixtures/svgcheck/check/viewBox-none.svg.code +1 -0
- data/spec/fixtures/svgcheck/check/viewBox-none.svg.err +0 -0
- data/spec/fixtures/svgcheck/check/viewBox-none.svg.out +3 -0
- data/spec/fixtures/svgcheck/check/viewBox-width.svg.code +1 -0
- data/spec/fixtures/svgcheck/check/viewBox-width.svg.err +0 -0
- data/spec/fixtures/svgcheck/check/viewBox-width.svg.out +3 -0
- data/spec/fixtures/svgcheck/inputs/DrawBerry-sample-2.svg +28 -0
- data/spec/fixtures/svgcheck/inputs/IETF-test.svg +28 -0
- data/spec/fixtures/svgcheck/inputs/circle.svg +3 -0
- data/spec/fixtures/svgcheck/inputs/colors.svg +18 -0
- data/spec/fixtures/svgcheck/inputs/dia-sample-svg.svg +47 -0
- data/spec/fixtures/svgcheck/inputs/example-dot.svg +75 -0
- data/spec/fixtures/svgcheck/inputs/full-tiny.svg +16194 -0
- data/spec/fixtures/svgcheck/inputs/good.svg +19 -0
- data/spec/fixtures/svgcheck/inputs/httpbis-proxy20-fig6.svg +2 -0
- data/spec/fixtures/svgcheck/inputs/malformed.svg +11 -0
- data/spec/fixtures/svgcheck/inputs/rfc-svg.svg +1028 -0
- data/spec/fixtures/svgcheck/inputs/rfc.xml +37 -0
- data/spec/fixtures/svgcheck/inputs/rgb.svg +9 -0
- data/spec/fixtures/svgcheck/inputs/svg-wordle.svg +330 -0
- data/spec/fixtures/svgcheck/inputs/threshold.svg +26 -0
- data/spec/fixtures/svgcheck/inputs/utf8.svg +448 -0
- data/spec/fixtures/svgcheck/inputs/viewBox-both.svg +3 -0
- data/spec/fixtures/svgcheck/inputs/viewBox-height.svg +3 -0
- data/spec/fixtures/svgcheck/inputs/viewBox-none.svg +3 -0
- data/spec/fixtures/svgcheck/inputs/viewBox-width.svg +3 -0
- data/spec/fixtures/svgcheck/repair/DrawBerry-sample-2.svg.code +1 -0
- data/spec/fixtures/svgcheck/repair/DrawBerry-sample-2.svg.err +0 -0
- data/spec/fixtures/svgcheck/repair/DrawBerry-sample-2.svg.file +0 -0
- data/spec/fixtures/svgcheck/repair/DrawBerry-sample-2.svg.out +23 -0
- data/spec/fixtures/svgcheck/repair/IETF-test.svg.code +1 -0
- data/spec/fixtures/svgcheck/repair/IETF-test.svg.err +0 -0
- data/spec/fixtures/svgcheck/repair/IETF-test.svg.file +29 -0
- data/spec/fixtures/svgcheck/repair/IETF-test.svg.out +20 -0
- data/spec/fixtures/svgcheck/repair/circle.svg.code +1 -0
- data/spec/fixtures/svgcheck/repair/circle.svg.err +0 -0
- data/spec/fixtures/svgcheck/repair/circle.svg.file +4 -0
- data/spec/fixtures/svgcheck/repair/circle.svg.out +2 -0
- data/spec/fixtures/svgcheck/repair/colors.svg.code +1 -0
- data/spec/fixtures/svgcheck/repair/colors.svg.err +0 -0
- data/spec/fixtures/svgcheck/repair/colors.svg.file +19 -0
- data/spec/fixtures/svgcheck/repair/colors.svg.out +13 -0
- data/spec/fixtures/svgcheck/repair/dia-sample-svg.svg.code +1 -0
- data/spec/fixtures/svgcheck/repair/dia-sample-svg.svg.err +0 -0
- data/spec/fixtures/svgcheck/repair/dia-sample-svg.svg.file +47 -0
- data/spec/fixtures/svgcheck/repair/dia-sample-svg.svg.out +76 -0
- data/spec/fixtures/svgcheck/repair/example-dot.svg.code +1 -0
- data/spec/fixtures/svgcheck/repair/example-dot.svg.err +0 -0
- data/spec/fixtures/svgcheck/repair/example-dot.svg.file +69 -0
- data/spec/fixtures/svgcheck/repair/example-dot.svg.out +11 -0
- data/spec/fixtures/svgcheck/repair/good.svg.code +1 -0
- data/spec/fixtures/svgcheck/repair/good.svg.err +0 -0
- data/spec/fixtures/svgcheck/repair/good.svg.file +0 -0
- data/spec/fixtures/svgcheck/repair/good.svg.out +1 -0
- data/spec/fixtures/svgcheck/repair/httpbis-proxy20-fig6.svg.code +1 -0
- data/spec/fixtures/svgcheck/repair/httpbis-proxy20-fig6.svg.err +0 -0
- data/spec/fixtures/svgcheck/repair/httpbis-proxy20-fig6.svg.file +73 -0
- data/spec/fixtures/svgcheck/repair/httpbis-proxy20-fig6.svg.out +5 -0
- data/spec/fixtures/svgcheck/repair/malformed.svg.code +1 -0
- data/spec/fixtures/svgcheck/repair/malformed.svg.err +0 -0
- data/spec/fixtures/svgcheck/repair/malformed.svg.file +9 -0
- data/spec/fixtures/svgcheck/repair/malformed.svg.out +8 -0
- data/spec/fixtures/svgcheck/repair/rfc-svg.svg.code +1 -0
- data/spec/fixtures/svgcheck/repair/rfc-svg.svg.err +0 -0
- data/spec/fixtures/svgcheck/repair/rfc-svg.svg.file +0 -0
- data/spec/fixtures/svgcheck/repair/rfc-svg.svg.out +1 -0
- data/spec/fixtures/svgcheck/repair/rfc.xml.code +1 -0
- data/spec/fixtures/svgcheck/repair/rfc.xml.err +0 -0
- data/spec/fixtures/svgcheck/repair/rfc.xml.file +37 -0
- data/spec/fixtures/svgcheck/repair/rfc.xml.out +2 -0
- data/spec/fixtures/svgcheck/repair/rgb.svg.code +1 -0
- data/spec/fixtures/svgcheck/repair/rgb.svg.err +0 -0
- data/spec/fixtures/svgcheck/repair/rgb.svg.file +10 -0
- data/spec/fixtures/svgcheck/repair/rgb.svg.out +9 -0
- data/spec/fixtures/svgcheck/repair/svg-wordle.svg.code +1 -0
- data/spec/fixtures/svgcheck/repair/svg-wordle.svg.err +0 -0
- data/spec/fixtures/svgcheck/repair/svg-wordle.svg.file +112 -0
- data/spec/fixtures/svgcheck/repair/svg-wordle.svg.out +508 -0
- data/spec/fixtures/svgcheck/repair/threshold.svg.code +1 -0
- data/spec/fixtures/svgcheck/repair/threshold.svg.err +0 -0
- data/spec/fixtures/svgcheck/repair/threshold.svg.file +27 -0
- data/spec/fixtures/svgcheck/repair/threshold.svg.out +20 -0
- data/spec/fixtures/svgcheck/repair/utf8.svg.code +1 -0
- data/spec/fixtures/svgcheck/repair/utf8.svg.err +0 -0
- data/spec/fixtures/svgcheck/repair/utf8.svg.file +381 -0
- data/spec/fixtures/svgcheck/repair/utf8.svg.out +162 -0
- data/spec/fixtures/svgcheck/repair/viewBox-both.svg.code +1 -0
- data/spec/fixtures/svgcheck/repair/viewBox-both.svg.err +0 -0
- data/spec/fixtures/svgcheck/repair/viewBox-both.svg.file +4 -0
- data/spec/fixtures/svgcheck/repair/viewBox-both.svg.out +4 -0
- data/spec/fixtures/svgcheck/repair/viewBox-height.svg.code +1 -0
- data/spec/fixtures/svgcheck/repair/viewBox-height.svg.err +0 -0
- data/spec/fixtures/svgcheck/repair/viewBox-height.svg.file +4 -0
- data/spec/fixtures/svgcheck/repair/viewBox-height.svg.out +3 -0
- data/spec/fixtures/svgcheck/repair/viewBox-none.svg.code +1 -0
- data/spec/fixtures/svgcheck/repair/viewBox-none.svg.err +0 -0
- data/spec/fixtures/svgcheck/repair/viewBox-none.svg.file +4 -0
- data/spec/fixtures/svgcheck/repair/viewBox-none.svg.out +3 -0
- data/spec/fixtures/svgcheck/repair/viewBox-width.svg.code +1 -0
- data/spec/fixtures/svgcheck/repair/viewBox-width.svg.err +0 -0
- data/spec/fixtures/svgcheck/repair/viewBox-width.svg.file +4 -0
- data/spec/fixtures/svgcheck/repair/viewBox-width.svg.out +3 -0
- data/spec/fixtures/viewbox_required/inputs/missing_viewbox.svg +10 -0
- data/spec/fixtures/viewbox_required/repair/missing_viewbox.svg +10 -0
- data/spec/spec_helper.rb +16 -0
- data/spec/svg_conform/batch_report_spec.rb +99 -0
- data/spec/svg_conform/commands/check_command_spec.rb +90 -0
- data/spec/svg_conform/commands/profiles_command_spec.rb +20 -0
- data/spec/svg_conform/commands/svgcheck_compare_command_spec.rb +13 -0
- data/spec/svg_conform/commands/svgcheck_compatibility_command_spec.rb +13 -0
- data/spec/svg_conform/commands/svgcheck_generate_command_spec.rb +14 -0
- data/spec/svg_conform/profiles/base_profile_spec.rb +42 -0
- data/spec/svg_conform/profiles/lucid_fix_profile_spec.rb +46 -0
- data/spec/svg_conform/profiles/lucid_profile_spec.rb +84 -0
- data/spec/svg_conform/profiles/metanorma_profile_spec.rb +62 -0
- data/spec/svg_conform/profiles/no_external_css_profile_spec.rb +66 -0
- data/spec/svg_conform/profiles/svg_1_2_rfc_profile_spec.rb +200 -0
- data/spec/svg_conform/profiles/svg_1_2_rfc_with_rdf_profile_spec.rb +81 -0
- data/spec/svg_conform/remediations/color_remediation_spec.rb +95 -0
- data/spec/svg_conform/remediations/font_embedding_remediation_spec.rb +20 -0
- data/spec/svg_conform/remediations/font_remediation_spec.rb +95 -0
- data/spec/svg_conform/remediations/image_embedding_remediation_spec.rb +20 -0
- data/spec/svg_conform/remediations/invalid_id_references_remediation_spec.rb +97 -0
- data/spec/svg_conform/remediations/namespace_attribute_remediation_spec.rb +97 -0
- data/spec/svg_conform/remediations/namespace_remediation_spec.rb +95 -0
- data/spec/svg_conform/remediations/no_external_css_remediation_spec.rb +97 -0
- data/spec/svg_conform/remediations/style_promotion_remediation_spec.rb +97 -0
- data/spec/svg_conform/remediations/viewbox_remediation_spec.rb +95 -0
- data/spec/svg_conform/requirements/allowed_elements_requirement_spec.rb +118 -0
- data/spec/svg_conform/requirements/color_restrictions_requirement_spec.rb +168 -0
- data/spec/svg_conform/requirements/font_family_requirement_spec.rb +188 -0
- data/spec/svg_conform/requirements/forbidden_content_requirement_spec.rb +195 -0
- data/spec/svg_conform/requirements/id_reference_requirement_spec.rb +78 -0
- data/spec/svg_conform/requirements/invalid_id_references_requirement_spec.rb +78 -0
- data/spec/svg_conform/requirements/link_validation_requirement_spec.rb +78 -0
- data/spec/svg_conform/requirements/namespace_attributes_requirement_spec.rb +86 -0
- data/spec/svg_conform/requirements/namespace_requirement_spec.rb +184 -0
- data/spec/svg_conform/requirements/no_external_css_requirement_spec.rb +78 -0
- data/spec/svg_conform/requirements/no_external_fonts_requirement_spec.rb +20 -0
- data/spec/svg_conform/requirements/no_external_images_requirement_spec.rb +20 -0
- data/spec/svg_conform/requirements/style_promotion_requirement_spec.rb +78 -0
- data/spec/svg_conform/requirements/style_requirement_spec.rb +76 -0
- data/spec/svg_conform/requirements/viewbox_required_requirement_spec.rb +165 -0
- data/spec/svg_conform_spec.rb +32 -0
- data/spec/svgcheck_compatibility_spec.rb +355 -0
- data/svg_conform.gemspec +35 -0
- metadata +436 -0
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base_remediation"
|
|
4
|
+
|
|
5
|
+
module SvgConform
|
|
6
|
+
module Remediations
|
|
7
|
+
# Remediation action to remove external CSS references
|
|
8
|
+
class NoExternalCssRemediation < BaseRemediation
|
|
9
|
+
attribute :type, :string, default: -> { "NoExternalCssRemediation" }
|
|
10
|
+
attribute :strategy, :string, default: "remove_external_references"
|
|
11
|
+
attribute :preserve_inline_styles, :boolean, default: true
|
|
12
|
+
attribute :log_removed_elements, :boolean, default: true
|
|
13
|
+
|
|
14
|
+
def apply(document, context)
|
|
15
|
+
changes = []
|
|
16
|
+
|
|
17
|
+
case @strategy
|
|
18
|
+
when "remove_external_references"
|
|
19
|
+
changes += remove_external_link_elements(document, context)
|
|
20
|
+
changes += remove_external_imports_from_style_elements(document,
|
|
21
|
+
context)
|
|
22
|
+
changes += remove_external_urls_from_style_attributes(document,
|
|
23
|
+
context)
|
|
24
|
+
else
|
|
25
|
+
context.add_error(
|
|
26
|
+
message: "Unknown remediation strategy: #{@strategy}",
|
|
27
|
+
node: document.root,
|
|
28
|
+
)
|
|
29
|
+
return []
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
if @log_removed_elements && changes.any?
|
|
33
|
+
log_remediation(context,
|
|
34
|
+
"Removed #{changes.length} external CSS references")
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
changes
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
private
|
|
41
|
+
|
|
42
|
+
def remove_external_link_elements(document, context)
|
|
43
|
+
changes = []
|
|
44
|
+
|
|
45
|
+
document.traverse do |node|
|
|
46
|
+
next unless element?(node) && node.name == "link"
|
|
47
|
+
|
|
48
|
+
rel = get_attribute(node, "rel")
|
|
49
|
+
href = get_attribute(node, "href")
|
|
50
|
+
|
|
51
|
+
if rel&.downcase == "stylesheet" && href && !allowed_url?(href)
|
|
52
|
+
if @log_removed_elements
|
|
53
|
+
log_removal(context,
|
|
54
|
+
"Removing external CSS link: #{href}")
|
|
55
|
+
end
|
|
56
|
+
node.remove
|
|
57
|
+
changes << {
|
|
58
|
+
type: :element_removed,
|
|
59
|
+
description: "Removed external CSS link: #{href}",
|
|
60
|
+
node_name: node.name,
|
|
61
|
+
href: href,
|
|
62
|
+
}
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
changes
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def remove_external_imports_from_style_elements(document, context)
|
|
70
|
+
changes = []
|
|
71
|
+
|
|
72
|
+
document.traverse do |node|
|
|
73
|
+
next unless element?(node) && node.name == "style"
|
|
74
|
+
|
|
75
|
+
content = node.text || ""
|
|
76
|
+
original_content = content.dup
|
|
77
|
+
|
|
78
|
+
# Remove @import url() statements
|
|
79
|
+
content.gsub!(/@import\s+url\s*\(\s*['"]?([^'")\s]+)['"]?\s*\)\s*;?/i) do |match|
|
|
80
|
+
url = ::Regexp.last_match(1)
|
|
81
|
+
if allowed_url?(url)
|
|
82
|
+
match # Keep allowed URLs
|
|
83
|
+
else
|
|
84
|
+
if @log_removed_elements
|
|
85
|
+
log_removal(context,
|
|
86
|
+
"Removing external CSS import: #{url}")
|
|
87
|
+
end
|
|
88
|
+
changes << {
|
|
89
|
+
type: :content_modified,
|
|
90
|
+
description: "Removed external CSS import: #{url}",
|
|
91
|
+
node_name: node.name,
|
|
92
|
+
url: url,
|
|
93
|
+
}
|
|
94
|
+
"" # Remove disallowed URLs
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# Remove @import "url" statements
|
|
99
|
+
content.gsub!(/@import\s+['"]([^'"]+)['"]\s*;?/i) do |match|
|
|
100
|
+
url = ::Regexp.last_match(1)
|
|
101
|
+
if allowed_url?(url)
|
|
102
|
+
match # Keep allowed URLs
|
|
103
|
+
else
|
|
104
|
+
if @log_removed_elements
|
|
105
|
+
log_removal(context,
|
|
106
|
+
"Removing external CSS import: #{url}")
|
|
107
|
+
end
|
|
108
|
+
changes << {
|
|
109
|
+
type: :content_modified,
|
|
110
|
+
description: "Removed external CSS import: #{url}",
|
|
111
|
+
node_name: node.name,
|
|
112
|
+
url: url,
|
|
113
|
+
}
|
|
114
|
+
"" # Remove disallowed URLs
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# Update the node content if it changed
|
|
119
|
+
if content != original_content
|
|
120
|
+
# Clear existing text content and set new content
|
|
121
|
+
node.text = content
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
changes
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def remove_external_urls_from_style_attributes(document, context)
|
|
129
|
+
changes = []
|
|
130
|
+
|
|
131
|
+
document.traverse do |node|
|
|
132
|
+
next unless element?(node)
|
|
133
|
+
|
|
134
|
+
style_value = get_attribute(node, "style")
|
|
135
|
+
next unless style_value
|
|
136
|
+
|
|
137
|
+
original_style = style_value.dup
|
|
138
|
+
|
|
139
|
+
# Remove url() references in style attributes
|
|
140
|
+
style_value.gsub!(/url\s*\(\s*['"]?([^'")\s]+)['"]?\s*\)/i) do |match|
|
|
141
|
+
url = ::Regexp.last_match(1)
|
|
142
|
+
if allowed_url?(url)
|
|
143
|
+
match # Keep allowed URLs
|
|
144
|
+
else
|
|
145
|
+
if @log_removed_elements
|
|
146
|
+
log_removal(context,
|
|
147
|
+
"Removing external URL from style attribute: #{url}")
|
|
148
|
+
end
|
|
149
|
+
changes << {
|
|
150
|
+
type: :attribute_modified,
|
|
151
|
+
description: "Removed external URL from style attribute: #{url}",
|
|
152
|
+
node_name: node.name,
|
|
153
|
+
attribute_name: "style",
|
|
154
|
+
url: url,
|
|
155
|
+
}
|
|
156
|
+
"" # Remove disallowed URLs
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# Update the attribute if it changed
|
|
161
|
+
if style_value != original_style
|
|
162
|
+
set_attribute(node, "style",
|
|
163
|
+
style_value)
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
changes
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def allowed_url?(url)
|
|
171
|
+
return true if url.nil? || url.empty?
|
|
172
|
+
|
|
173
|
+
# Data URLs are typically allowed
|
|
174
|
+
return true if url.start_with?("data:")
|
|
175
|
+
|
|
176
|
+
# Fragment identifiers (internal references) are allowed
|
|
177
|
+
return true if url.start_with?("#")
|
|
178
|
+
|
|
179
|
+
# For remediation, we're more restrictive - only allow data: and fragment URLs
|
|
180
|
+
false
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def log_removal(context, message)
|
|
184
|
+
context.add_info(message: message) if context.respond_to?(:add_info)
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
def log_remediation(context, message)
|
|
188
|
+
context.add_info(message: message) if context.respond_to?(:add_info)
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
end
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base_remediation"
|
|
4
|
+
|
|
5
|
+
module SvgConform
|
|
6
|
+
module Remediations
|
|
7
|
+
# Promotes CSS style properties to individual attributes
|
|
8
|
+
class StylePromotionRemediation < BaseRemediation
|
|
9
|
+
# CSS properties that can be promoted to SVG attributes
|
|
10
|
+
PROMOTABLE_PROPERTIES = %w[
|
|
11
|
+
fill stroke stroke-width stroke-opacity stroke-linecap stroke-linejoin
|
|
12
|
+
fill-opacity fill-rule text-anchor font-family font-size font-weight
|
|
13
|
+
font-style opacity visibility display
|
|
14
|
+
].freeze
|
|
15
|
+
|
|
16
|
+
def apply(document, _context)
|
|
17
|
+
results = []
|
|
18
|
+
|
|
19
|
+
document.xpath("//*[@style]").each do |element|
|
|
20
|
+
style_attr = element["style"]
|
|
21
|
+
next if style_attr.nil? || style_attr.strip.empty?
|
|
22
|
+
|
|
23
|
+
promoted_properties = promote_style_properties(element, style_attr)
|
|
24
|
+
promoted_properties.each do |property, value|
|
|
25
|
+
results << create_promotion_result(element, property, value)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
results
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
def promote_style_properties(element, style_attr)
|
|
35
|
+
promoted = {}
|
|
36
|
+
remaining_styles = []
|
|
37
|
+
|
|
38
|
+
# Parse CSS style declarations
|
|
39
|
+
style_declarations = parse_style_declarations(style_attr)
|
|
40
|
+
|
|
41
|
+
style_declarations.each do |property, value|
|
|
42
|
+
if PROMOTABLE_PROPERTIES.include?(property)
|
|
43
|
+
# Promote to attribute
|
|
44
|
+
element[property] = value
|
|
45
|
+
promoted[property] = value
|
|
46
|
+
else
|
|
47
|
+
# Keep in style attribute
|
|
48
|
+
remaining_styles << "#{property}:#{value}"
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Update or remove style attribute
|
|
53
|
+
if remaining_styles.empty?
|
|
54
|
+
element.remove_attribute("style")
|
|
55
|
+
else
|
|
56
|
+
element["style"] = remaining_styles.join(";")
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
promoted
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def parse_style_declarations(style_attr)
|
|
63
|
+
declarations = {}
|
|
64
|
+
|
|
65
|
+
# Split by semicolon and parse each declaration
|
|
66
|
+
style_attr.split(";").each do |declaration|
|
|
67
|
+
next if declaration.strip.empty?
|
|
68
|
+
|
|
69
|
+
parts = declaration.split(":", 2)
|
|
70
|
+
next unless parts.length == 2
|
|
71
|
+
|
|
72
|
+
property = parts[0].strip
|
|
73
|
+
value = parts[1].strip
|
|
74
|
+
|
|
75
|
+
# Remove any trailing semicolon from value
|
|
76
|
+
value = value.chomp(";")
|
|
77
|
+
|
|
78
|
+
declarations[property] = value
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
declarations
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def create_promotion_result(element, property, _value)
|
|
85
|
+
log_change(
|
|
86
|
+
:style_promotion,
|
|
87
|
+
"Style property '#{property}' promoted to attribute",
|
|
88
|
+
element,
|
|
89
|
+
)
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base_remediation"
|
|
4
|
+
|
|
5
|
+
module SvgConform
|
|
6
|
+
module Remediations
|
|
7
|
+
# Remediation action for viewBox-related issues that matches svgcheck behavior
|
|
8
|
+
class ViewboxRemediation < BaseRemediation
|
|
9
|
+
attribute :type, :string, default: -> { "ViewboxRemediation" }
|
|
10
|
+
|
|
11
|
+
def apply(document, _context)
|
|
12
|
+
changes = []
|
|
13
|
+
|
|
14
|
+
# Get the root SVG element directly from the document
|
|
15
|
+
svg_element = document.root
|
|
16
|
+
|
|
17
|
+
if svg_element
|
|
18
|
+
# Check if viewBox is missing or malformed
|
|
19
|
+
current_viewbox = get_attribute(svg_element, "viewBox")
|
|
20
|
+
|
|
21
|
+
if current_viewbox.nil? || current_viewbox.empty?
|
|
22
|
+
changes.concat(add_viewbox_from_dimensions(svg_element))
|
|
23
|
+
elsif current_viewbox =~ /[()]/ || current_viewbox !~ /^[\d.\s-]+$/
|
|
24
|
+
# Malformed viewBox - try to fix it
|
|
25
|
+
changes.concat(fix_malformed_viewbox(svg_element, current_viewbox))
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
changes
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
def add_viewbox_from_dimensions(svg_element)
|
|
35
|
+
changes = []
|
|
36
|
+
|
|
37
|
+
# Try to get width and height attributes (matching svgcheck logic)
|
|
38
|
+
width = get_attribute(svg_element, "width")
|
|
39
|
+
height = get_attribute(svg_element, "height")
|
|
40
|
+
|
|
41
|
+
if width && height
|
|
42
|
+
# Extract numeric values (svgcheck uses maybefloat function)
|
|
43
|
+
width_num = extract_float(width)
|
|
44
|
+
height_num = extract_float(height)
|
|
45
|
+
|
|
46
|
+
if width_num && height_num
|
|
47
|
+
# Create viewBox value: "0 0 width height" (matching svgcheck format)
|
|
48
|
+
# Format numbers to avoid unnecessary decimal places
|
|
49
|
+
width_formatted = width_num == width_num.to_i ? width_num.to_i.to_s : width_num.to_s
|
|
50
|
+
height_formatted = height_num == height_num.to_i ? height_num.to_i.to_s : height_num.to_s
|
|
51
|
+
viewbox_value = "0 0 #{width_formatted} #{height_formatted}"
|
|
52
|
+
set_attribute(svg_element, "viewBox", viewbox_value)
|
|
53
|
+
|
|
54
|
+
changes << log_change(
|
|
55
|
+
:attribute_added,
|
|
56
|
+
"The attribute viewBox is required on the root svg element",
|
|
57
|
+
svg_element,
|
|
58
|
+
)
|
|
59
|
+
changes << log_change(
|
|
60
|
+
:attribute_added,
|
|
61
|
+
"Trying to put in the attribute with value '#{viewbox_value}'",
|
|
62
|
+
svg_element,
|
|
63
|
+
)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
changes
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def extract_float(value)
|
|
71
|
+
return nil unless value
|
|
72
|
+
|
|
73
|
+
# Try to convert to float (matching svgcheck's maybefloat function)
|
|
74
|
+
begin
|
|
75
|
+
Float(value)
|
|
76
|
+
rescue ArgumentError, TypeError
|
|
77
|
+
nil
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def fix_malformed_viewbox(svg_element, malformed_value)
|
|
82
|
+
changes = []
|
|
83
|
+
|
|
84
|
+
# Remove parentheses and extra characters, extract numbers
|
|
85
|
+
cleaned_value = malformed_value.gsub(/[()]/, "").strip
|
|
86
|
+
|
|
87
|
+
# Split by spaces or commas and extract numeric values
|
|
88
|
+
numbers = cleaned_value.split(/[\s,]+/).map do |part|
|
|
89
|
+
part.gsub(/[^\d.-]/, "") # Remove non-numeric characters except . and -
|
|
90
|
+
end.compact.reject(&:empty?)
|
|
91
|
+
|
|
92
|
+
# Try to convert to valid numbers
|
|
93
|
+
valid_numbers = numbers.map do |num_str|
|
|
94
|
+
Float(num_str)
|
|
95
|
+
rescue ArgumentError
|
|
96
|
+
nil
|
|
97
|
+
end.compact
|
|
98
|
+
|
|
99
|
+
# If we have 4 valid numbers, create proper viewBox
|
|
100
|
+
if valid_numbers.length == 4
|
|
101
|
+
proper_viewbox = valid_numbers.join(" ")
|
|
102
|
+
set_attribute(svg_element, "viewBox", proper_viewbox)
|
|
103
|
+
|
|
104
|
+
changes << log_change(
|
|
105
|
+
:attribute_modified,
|
|
106
|
+
"Fixed malformed viewBox attribute from '#{malformed_value}' to '#{proper_viewbox}'",
|
|
107
|
+
svg_element,
|
|
108
|
+
)
|
|
109
|
+
elsif valid_numbers.length >= 2
|
|
110
|
+
# If we have at least width and height, use them
|
|
111
|
+
width = valid_numbers[2] || valid_numbers[0]
|
|
112
|
+
height = valid_numbers[3] || valid_numbers[1]
|
|
113
|
+
proper_viewbox = "0 0 #{width} #{height}"
|
|
114
|
+
set_attribute(svg_element, "viewBox", proper_viewbox)
|
|
115
|
+
|
|
116
|
+
changes << log_change(
|
|
117
|
+
:attribute_modified,
|
|
118
|
+
"Fixed malformed viewBox attribute from '#{malformed_value}' to '#{proper_viewbox}'",
|
|
119
|
+
svg_element,
|
|
120
|
+
)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
changes
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "remediations/base_remediation"
|
|
4
|
+
require_relative "remediations/color_remediation"
|
|
5
|
+
require_relative "remediations/font_embedding_remediation"
|
|
6
|
+
require_relative "remediations/font_remediation"
|
|
7
|
+
require_relative "remediations/image_embedding_remediation"
|
|
8
|
+
require_relative "remediations/invalid_id_references_remediation"
|
|
9
|
+
require_relative "remediations/namespace_attribute_remediation"
|
|
10
|
+
require_relative "remediations/namespace_remediation"
|
|
11
|
+
require_relative "remediations/no_external_css_remediation"
|
|
12
|
+
require_relative "remediations/style_promotion_remediation"
|
|
13
|
+
require_relative "remediations/viewbox_remediation"
|
|
14
|
+
|
|
15
|
+
module SvgConform
|
|
16
|
+
module Remediations
|
|
17
|
+
# Auto-load all remediation classes
|
|
18
|
+
def self.all
|
|
19
|
+
[
|
|
20
|
+
ColorRemediation,
|
|
21
|
+
FontEmbeddingRemediation,
|
|
22
|
+
FontRemediation,
|
|
23
|
+
ImageEmbeddingRemediation,
|
|
24
|
+
InvalidIdReferencesRemediation,
|
|
25
|
+
NamespaceAttributeRemediation,
|
|
26
|
+
NamespaceRemediation,
|
|
27
|
+
NoExternalCSSRemediation,
|
|
28
|
+
StylePromotionRemediation,
|
|
29
|
+
ViewboxRemediation,
|
|
30
|
+
]
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Find a remediation class by name
|
|
34
|
+
def self.find(class_name)
|
|
35
|
+
const_get(class_name)
|
|
36
|
+
rescue NameError
|
|
37
|
+
nil
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|