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,133 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base_requirement"
|
|
4
|
+
|
|
5
|
+
module SvgConform
|
|
6
|
+
module Requirements
|
|
7
|
+
# Validates font family restrictions
|
|
8
|
+
class FontFamilyRequirement < BaseRequirement
|
|
9
|
+
attribute :type, :string, default: -> { "FontFamilyRequirement" }
|
|
10
|
+
attribute :allowed_families, :string, collection: true, default: -> {
|
|
11
|
+
%w[serif sans-serif monospace]
|
|
12
|
+
}
|
|
13
|
+
attribute :svgcheck_compatibility, :boolean, default: -> { false }
|
|
14
|
+
attribute :enable_fallback, :boolean, default: -> { false }
|
|
15
|
+
attribute :default_fallback, :string, default: -> { "sans-serif" }
|
|
16
|
+
|
|
17
|
+
yaml do
|
|
18
|
+
map "id", to: :id
|
|
19
|
+
map "description", to: :description
|
|
20
|
+
map "type", to: :type
|
|
21
|
+
map "allowed_families", to: :allowed_families
|
|
22
|
+
map "svgcheck_compatibility", to: :svgcheck_compatibility
|
|
23
|
+
map "enable_fallback", to: :enable_fallback
|
|
24
|
+
map "default_fallback", to: :default_fallback
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def check(node, context)
|
|
28
|
+
return unless element?(node)
|
|
29
|
+
|
|
30
|
+
# Check font-family attribute only (not style properties)
|
|
31
|
+
# Style properties are handled by StylePromotionRequirement to avoid duplication
|
|
32
|
+
font_family = get_attribute(node, "font-family")
|
|
33
|
+
return unless font_family
|
|
34
|
+
|
|
35
|
+
if svgcheck_compatibility
|
|
36
|
+
check_font_family_svgcheck_mode(node, context, font_family,
|
|
37
|
+
"font-family")
|
|
38
|
+
elsif !valid_font_family?(font_family)
|
|
39
|
+
context.add_error(
|
|
40
|
+
requirement_id: id,
|
|
41
|
+
message: "Font family '#{font_family}' is not allowed in this profile",
|
|
42
|
+
node: node,
|
|
43
|
+
severity: :error,
|
|
44
|
+
data: { attribute: "font-family", value: font_family },
|
|
45
|
+
)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
private
|
|
50
|
+
|
|
51
|
+
def check_font_family_svgcheck_mode(node, context, font_family_value,
|
|
52
|
+
attribute_name)
|
|
53
|
+
# Check if the font family value is valid according to svgcheck
|
|
54
|
+
return if valid_font_family_svgcheck?(font_family_value)
|
|
55
|
+
|
|
56
|
+
# Generate error message matching svgcheck's exact format
|
|
57
|
+
context.add_error(
|
|
58
|
+
requirement_id: id,
|
|
59
|
+
message: "The attribute '#{attribute_name}' does not allow the value '#{font_family_value}', replaced with '#{default_fallback}'",
|
|
60
|
+
node: node,
|
|
61
|
+
severity: :error,
|
|
62
|
+
data: {
|
|
63
|
+
attribute: attribute_name,
|
|
64
|
+
original_value: font_family_value,
|
|
65
|
+
replacement_value: default_fallback,
|
|
66
|
+
},
|
|
67
|
+
)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def extract_valid_fonts(font_family_value)
|
|
71
|
+
# Parse font family list (comma-separated)
|
|
72
|
+
families = font_family_value.split(",").map(&:strip)
|
|
73
|
+
|
|
74
|
+
valid_fonts = []
|
|
75
|
+
families.each do |family|
|
|
76
|
+
# Remove quotes if present
|
|
77
|
+
clean_family = family.gsub(/['"]/, "").strip.downcase
|
|
78
|
+
valid_fonts << clean_family if allowed_families.include?(clean_family)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
valid_fonts
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def valid_font_family_svgcheck?(font_family)
|
|
85
|
+
# svgcheck allows: serif, sans-serif, monospace, inherit
|
|
86
|
+
# Any other value is considered invalid and gets replaced with sans-serif
|
|
87
|
+
svgcheck_allowed = %w[serif sans-serif monospace inherit]
|
|
88
|
+
|
|
89
|
+
# Parse font family list (can be comma-separated)
|
|
90
|
+
families = font_family.split(",").map(&:strip)
|
|
91
|
+
|
|
92
|
+
# Check if any family in the list is valid
|
|
93
|
+
families.any? do |family|
|
|
94
|
+
# Remove quotes if present
|
|
95
|
+
clean_family = family.gsub(/['"]/, "").strip.downcase
|
|
96
|
+
svgcheck_allowed.include?(clean_family)
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def valid_font_family?(font_family)
|
|
101
|
+
# Parse font family list (can be comma-separated)
|
|
102
|
+
families = font_family.split(",").map(&:strip)
|
|
103
|
+
|
|
104
|
+
# All families must be allowed (matching svgcheck behavior)
|
|
105
|
+
families.all? do |family|
|
|
106
|
+
# Remove quotes if present
|
|
107
|
+
clean_family = family.gsub(/['"]/, "").strip.downcase
|
|
108
|
+
allowed_families.include?(clean_family)
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def parse_style(style_string)
|
|
113
|
+
return {} if style_string.nil? || style_string.empty?
|
|
114
|
+
|
|
115
|
+
properties = {}
|
|
116
|
+
declarations = style_string.split(";").map(&:strip)
|
|
117
|
+
|
|
118
|
+
declarations.each do |declaration|
|
|
119
|
+
next if declaration.empty?
|
|
120
|
+
|
|
121
|
+
parts = declaration.split(":", 2)
|
|
122
|
+
next unless parts.length == 2
|
|
123
|
+
|
|
124
|
+
property = parts[0].strip
|
|
125
|
+
value = parts[1].strip
|
|
126
|
+
properties[property] = value
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
properties
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base_requirement"
|
|
4
|
+
|
|
5
|
+
module SvgConform
|
|
6
|
+
module Requirements
|
|
7
|
+
class ForbiddenContentRequirement < BaseRequirement
|
|
8
|
+
attribute :forbidden_elements, :string, collection: true, default: -> {
|
|
9
|
+
[]
|
|
10
|
+
}
|
|
11
|
+
attribute :forbidden_attributes, :string, collection: true, default: -> {
|
|
12
|
+
[]
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
yaml do
|
|
16
|
+
map "id", to: :id
|
|
17
|
+
map "description", to: :description
|
|
18
|
+
map "type", to: :type
|
|
19
|
+
map "forbidden_elements", to: :forbidden_elements
|
|
20
|
+
map "forbidden_attributes", to: :forbidden_attributes
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def validate_document(document, context)
|
|
24
|
+
document.traverse do |node|
|
|
25
|
+
check(node, context) if should_check_node?(node)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def check(node, context)
|
|
30
|
+
return unless element?(node)
|
|
31
|
+
|
|
32
|
+
# Check if this is a forbidden element
|
|
33
|
+
if forbidden_elements.include?(node.name)
|
|
34
|
+
context.add_error(
|
|
35
|
+
requirement_id: id,
|
|
36
|
+
message: "Forbidden element '#{node.name}' is not allowed",
|
|
37
|
+
node: node,
|
|
38
|
+
severity: :error,
|
|
39
|
+
)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Check for forbidden attributes
|
|
43
|
+
if node.respond_to?(:attributes) && node.attributes
|
|
44
|
+
node.attributes.each do |attr|
|
|
45
|
+
attr_name = attr.respond_to?(:name) ? attr.name : attr.to_s
|
|
46
|
+
|
|
47
|
+
if forbidden_attributes.include?(attr_name)
|
|
48
|
+
context.add_error(
|
|
49
|
+
requirement_id: id,
|
|
50
|
+
message: "Forbidden attribute '#{attr_name}' is not allowed",
|
|
51
|
+
node: node,
|
|
52
|
+
severity: :error,
|
|
53
|
+
)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base_requirement"
|
|
4
|
+
require "set"
|
|
5
|
+
|
|
6
|
+
module SvgConform
|
|
7
|
+
module Requirements
|
|
8
|
+
class IdReferenceRequirement < BaseRequirement
|
|
9
|
+
def validate_document(document, context)
|
|
10
|
+
# Collect all IDs in the document
|
|
11
|
+
ids = Set.new
|
|
12
|
+
document.xpath("//*[@id]").each do |element|
|
|
13
|
+
id_value = element["id"]
|
|
14
|
+
ids.add(id_value) if id_value && !id_value.empty?
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Check references to IDs
|
|
18
|
+
check_url_references(document, ids, context)
|
|
19
|
+
check_href_references(document, ids, context)
|
|
20
|
+
check_other_references(document, ids, context)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def check_url_references(document, ids, context)
|
|
26
|
+
# Check url() references in style attributes and CSS properties
|
|
27
|
+
url_attributes = %w[fill stroke marker-start marker-mid marker-end
|
|
28
|
+
clip-path mask filter]
|
|
29
|
+
|
|
30
|
+
url_attributes.each do |attr_name|
|
|
31
|
+
document.xpath("//*[@#{attr_name}]").each do |element|
|
|
32
|
+
attr_value = element[attr_name]
|
|
33
|
+
next unless attr_value
|
|
34
|
+
|
|
35
|
+
url_refs = extract_url_references(attr_value)
|
|
36
|
+
url_refs.each do |ref_id|
|
|
37
|
+
next if ids.include?(ref_id)
|
|
38
|
+
|
|
39
|
+
context.add_error(
|
|
40
|
+
node: element,
|
|
41
|
+
message: "Reference to undefined ID '#{ref_id}' in attribute '#{attr_name}'",
|
|
42
|
+
requirement_id: id,
|
|
43
|
+
)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Check style attributes
|
|
49
|
+
document.xpath("//*[@style]").each do |element|
|
|
50
|
+
style_attr = element["style"]
|
|
51
|
+
next unless style_attr
|
|
52
|
+
|
|
53
|
+
url_refs = extract_url_references(style_attr)
|
|
54
|
+
url_refs.each do |ref_id|
|
|
55
|
+
next if ids.include?(ref_id)
|
|
56
|
+
|
|
57
|
+
context.add_error(
|
|
58
|
+
node: element,
|
|
59
|
+
message: "Reference to undefined ID '#{ref_id}' in style attribute",
|
|
60
|
+
requirement_id: id,
|
|
61
|
+
)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def check_href_references(document, ids, context)
|
|
67
|
+
# Check href and xlink:href references
|
|
68
|
+
document.xpath("//*[@href or @*[local-name()='href']]").each do |element|
|
|
69
|
+
href_value = element["href"]
|
|
70
|
+
|
|
71
|
+
# Check for xlink:href if regular href is not present
|
|
72
|
+
if href_value.nil?
|
|
73
|
+
href_value = element.attributes.find do |attr|
|
|
74
|
+
attr.name == "href" && attr.namespace&.uri == "http://www.w3.org/1999/xlink"
|
|
75
|
+
end&.value
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
next unless href_value
|
|
79
|
+
|
|
80
|
+
# Only check fragment identifiers (starting with #)
|
|
81
|
+
next unless href_value.start_with?("#")
|
|
82
|
+
|
|
83
|
+
ref_id = href_value[1..] # Remove the #
|
|
84
|
+
next if ids.include?(ref_id)
|
|
85
|
+
|
|
86
|
+
context.add_error(
|
|
87
|
+
node: element,
|
|
88
|
+
message: "Reference to undefined ID '#{ref_id}' in href attribute",
|
|
89
|
+
requirement_id: id,
|
|
90
|
+
)
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def check_other_references(document, ids, context)
|
|
95
|
+
# Check other attributes that reference IDs
|
|
96
|
+
id_ref_attributes = %w[for aria-labelledby aria-describedby
|
|
97
|
+
aria-controls aria-owns]
|
|
98
|
+
|
|
99
|
+
id_ref_attributes.each do |attr_name|
|
|
100
|
+
document.xpath("//*[@#{attr_name}]").each do |element|
|
|
101
|
+
attr_value = element[attr_name]
|
|
102
|
+
next unless attr_value
|
|
103
|
+
|
|
104
|
+
# These attributes can contain space-separated lists of IDs
|
|
105
|
+
ref_ids = attr_value.split(/\s+/)
|
|
106
|
+
ref_ids.each do |ref_id|
|
|
107
|
+
next if ref_id.empty?
|
|
108
|
+
|
|
109
|
+
next if ids.include?(ref_id)
|
|
110
|
+
|
|
111
|
+
context.add_error(
|
|
112
|
+
node: element,
|
|
113
|
+
message: "Reference to undefined ID '#{ref_id}' in #{attr_name} attribute",
|
|
114
|
+
requirement_id: id,
|
|
115
|
+
)
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def extract_url_references(value)
|
|
122
|
+
refs = []
|
|
123
|
+
|
|
124
|
+
# Match url(#id) patterns
|
|
125
|
+
value.scan(/url\(#([^)]+)\)/) do |match|
|
|
126
|
+
refs << match[0]
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
refs
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base_requirement"
|
|
4
|
+
|
|
5
|
+
module SvgConform
|
|
6
|
+
module Requirements
|
|
7
|
+
# Requirement to validate that ID references point to existing elements
|
|
8
|
+
# Based on the Lucid SVG fix script that removes use elements with invalid IDREF
|
|
9
|
+
class InvalidIdReferencesRequirement < BaseRequirement
|
|
10
|
+
attribute :type, :string, default: -> { "InvalidIdReferencesRequirement" }
|
|
11
|
+
attribute :check_use_elements, :boolean, default: true
|
|
12
|
+
attribute :check_other_references, :boolean, default: false
|
|
13
|
+
attribute :strict_mode, :boolean, default: false
|
|
14
|
+
|
|
15
|
+
yaml do
|
|
16
|
+
map "id", to: :id
|
|
17
|
+
map "description", to: :description
|
|
18
|
+
map "type", to: :type
|
|
19
|
+
map "check_use_elements", to: :check_use_elements
|
|
20
|
+
map "check_other_references", to: :check_other_references
|
|
21
|
+
map "strict_mode", to: :strict_mode
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def validate_document(document, context)
|
|
25
|
+
# Collect all existing IDs in the document
|
|
26
|
+
existing_ids = collect_existing_ids(document)
|
|
27
|
+
context.set_data(:existing_ids, existing_ids)
|
|
28
|
+
|
|
29
|
+
# Check for invalid references
|
|
30
|
+
super(document, context)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def check(node, context)
|
|
34
|
+
return unless element?(node)
|
|
35
|
+
|
|
36
|
+
if check_use_elements && node.name == "use"
|
|
37
|
+
check_use_element(node,
|
|
38
|
+
context)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
return unless check_other_references
|
|
42
|
+
|
|
43
|
+
check_other_id_references(node, context)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
private
|
|
47
|
+
|
|
48
|
+
def collect_existing_ids(document)
|
|
49
|
+
ids = Set.new
|
|
50
|
+
document.traverse do |node|
|
|
51
|
+
next unless element?(node)
|
|
52
|
+
|
|
53
|
+
id_attr = get_attribute(node, "id")
|
|
54
|
+
ids.add(id_attr) if id_attr && !id_attr.empty?
|
|
55
|
+
end
|
|
56
|
+
ids
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def check_use_element(node, context)
|
|
60
|
+
href = get_attribute(node, "xlink:href") || get_attribute(node, "href")
|
|
61
|
+
return unless href&.start_with?("#")
|
|
62
|
+
|
|
63
|
+
id_ref = href[1..] # Remove # prefix
|
|
64
|
+
return if id_ref.empty?
|
|
65
|
+
|
|
66
|
+
existing_ids = context.get_data(:existing_ids)
|
|
67
|
+
return if existing_ids.include?(id_ref)
|
|
68
|
+
|
|
69
|
+
context.add_error(
|
|
70
|
+
requirement: self,
|
|
71
|
+
node: node,
|
|
72
|
+
message: "use element references non-existent ID: #{id_ref}",
|
|
73
|
+
data: { invalid_id: id_ref, href: href },
|
|
74
|
+
)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def check_other_id_references(node, context)
|
|
78
|
+
# Check other attributes that reference IDs
|
|
79
|
+
id_reference_attributes = %w[
|
|
80
|
+
clip-path mask filter marker-start marker-mid marker-end
|
|
81
|
+
fill stroke
|
|
82
|
+
]
|
|
83
|
+
|
|
84
|
+
existing_ids = context.get_data(:existing_ids)
|
|
85
|
+
|
|
86
|
+
id_reference_attributes.each do |attr_name|
|
|
87
|
+
attr_value = get_attribute(node, attr_name)
|
|
88
|
+
next unless attr_value
|
|
89
|
+
|
|
90
|
+
# Extract ID from url(#id) format
|
|
91
|
+
next unless attr_value =~ /^url\(#(.+)\)$/
|
|
92
|
+
|
|
93
|
+
id_ref = Regexp.last_match(1)
|
|
94
|
+
next if existing_ids.include?(id_ref)
|
|
95
|
+
|
|
96
|
+
context.add_error(
|
|
97
|
+
requirement: self,
|
|
98
|
+
node: node,
|
|
99
|
+
message: "#{attr_name} references non-existent ID: #{id_ref}",
|
|
100
|
+
data: { invalid_id: id_ref, attribute: attr_name,
|
|
101
|
+
value: attr_value },
|
|
102
|
+
)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Check style attribute for ID references
|
|
106
|
+
check_style_id_references(node, context, existing_ids)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def check_style_id_references(node, context, existing_ids)
|
|
110
|
+
style_value = get_attribute(node, "style")
|
|
111
|
+
return unless style_value
|
|
112
|
+
|
|
113
|
+
styles = parse_style(style_value)
|
|
114
|
+
|
|
115
|
+
styles.each do |property, value|
|
|
116
|
+
next unless value =~ /^url\(#(.+)\)$/
|
|
117
|
+
|
|
118
|
+
id_ref = Regexp.last_match(1)
|
|
119
|
+
next if existing_ids.include?(id_ref)
|
|
120
|
+
|
|
121
|
+
context.add_error(
|
|
122
|
+
requirement: self,
|
|
123
|
+
node: node,
|
|
124
|
+
message: "style property #{property} references non-existent ID: #{id_ref}",
|
|
125
|
+
data: { invalid_id: id_ref, style_property: property,
|
|
126
|
+
value: value },
|
|
127
|
+
)
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base_requirement"
|
|
4
|
+
|
|
5
|
+
module SvgConform
|
|
6
|
+
module Requirements
|
|
7
|
+
class LinkValidationRequirement < BaseRequirement
|
|
8
|
+
def check(node, context)
|
|
9
|
+
return unless element?(node)
|
|
10
|
+
|
|
11
|
+
# Check href attributes (both href and xlink:href)
|
|
12
|
+
href_value = get_attribute(node, "href")
|
|
13
|
+
|
|
14
|
+
# Check for xlink:href if regular href is not present
|
|
15
|
+
if href_value.nil? && node.respond_to?(:attributes)
|
|
16
|
+
xlink_href = node.attributes.find do |attr|
|
|
17
|
+
attr.name == "href" && attr.namespace&.uri == "http://www.w3.org/1999/xlink"
|
|
18
|
+
end
|
|
19
|
+
href_value = xlink_href&.value
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
if href_value && !ascii_only?(href_value)
|
|
23
|
+
context.add_error(
|
|
24
|
+
requirement_id: id,
|
|
25
|
+
message: "Link href '#{href_value}' contains non-ASCII characters",
|
|
26
|
+
node: node,
|
|
27
|
+
severity: :error,
|
|
28
|
+
)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Check other IRI attributes
|
|
32
|
+
iri_attributes = %w[src action formaction cite longdesc usemap]
|
|
33
|
+
iri_attributes.each do |attr_name|
|
|
34
|
+
iri_value = get_attribute(node, attr_name)
|
|
35
|
+
next unless iri_value
|
|
36
|
+
|
|
37
|
+
next if ascii_only?(iri_value)
|
|
38
|
+
|
|
39
|
+
context.add_error(
|
|
40
|
+
requirement_id: id,
|
|
41
|
+
message: "IRI attribute '#{attr_name}' value '#{iri_value}' contains non-ASCII characters",
|
|
42
|
+
node: node,
|
|
43
|
+
severity: :error,
|
|
44
|
+
)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
private
|
|
49
|
+
|
|
50
|
+
def ascii_only?(string)
|
|
51
|
+
string.ascii_only?
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|