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,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../compatibility/compatibility_analyzer"
|
|
4
|
+
|
|
5
|
+
module SvgConform
|
|
6
|
+
module Commands
|
|
7
|
+
# Command for comparing SvgConform with svgcheck compatibility
|
|
8
|
+
class SvgcheckCompatibility
|
|
9
|
+
def initialize(options = {})
|
|
10
|
+
@options = options
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def execute
|
|
14
|
+
validate_options
|
|
15
|
+
|
|
16
|
+
analyzer = SvgConform::Compatibility::CompatibilityAnalyzer.new(
|
|
17
|
+
mode: @options[:mode] || @options["mode"] || "check",
|
|
18
|
+
profile: @options[:profile] || @options["profile"] || "svg_1_2_rfc_compatible",
|
|
19
|
+
semantic: @options[:semantic] || @options["semantic"] || false,
|
|
20
|
+
svgcheck_dir: @options[:svgcheck_dir] || @options["svgcheck_dir"] || "spec/fixtures/svgcheck",
|
|
21
|
+
file: @options[:file] || @options["file"],
|
|
22
|
+
output: @options[:output] || @options["output"],
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
analyzer.run_analysis
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def validate_options
|
|
31
|
+
mode = @options[:mode] || @options["mode"] || "check"
|
|
32
|
+
raise "Invalid mode: #{mode}. Must be 'check' or 'repair'" unless %w[
|
|
33
|
+
check repair
|
|
34
|
+
].include?(mode)
|
|
35
|
+
|
|
36
|
+
file = @options[:file] || @options["file"]
|
|
37
|
+
return unless file && !file.match?(/\.(svg|xml)$/i)
|
|
38
|
+
|
|
39
|
+
raise "File must have .svg or .xml extension: #{file}"
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "English"
|
|
4
|
+
require "fileutils"
|
|
5
|
+
require "paint"
|
|
6
|
+
require "open3"
|
|
7
|
+
|
|
8
|
+
module SvgConform
|
|
9
|
+
module Commands
|
|
10
|
+
# Generate svgcheck outputs using Open3 for proper process management
|
|
11
|
+
class SvgcheckGenerate
|
|
12
|
+
def initialize(svgcheck_repo_path, options)
|
|
13
|
+
@svgcheck_repo_path = svgcheck_repo_path
|
|
14
|
+
@options = options
|
|
15
|
+
@svgcheck_exec = @options[:svgcheck_exec] || "svgcheck"
|
|
16
|
+
@fixtures_path = @options[:fixtures_path] || "spec/fixtures/svgcheck"
|
|
17
|
+
@test_dir = File.join(@svgcheck_repo_path, "svgcheck", "Tests")
|
|
18
|
+
@svgcheck_dir = File.join(@svgcheck_repo_path, "svgcheck")
|
|
19
|
+
@single_file = @options[:single_file]
|
|
20
|
+
@force = @options[:force] || false
|
|
21
|
+
@verbose = @options[:verbose] || false
|
|
22
|
+
@mode = @options[:mode] || "both" # 'check', 'repair', or 'both'
|
|
23
|
+
|
|
24
|
+
# File renaming map: svgcheck filename => our fixture filename
|
|
25
|
+
@file_rename_map = {
|
|
26
|
+
"full-tiny.xml" => "full-tiny.svg",
|
|
27
|
+
"rfc-svg.xml" => "rfc-svg.svg",
|
|
28
|
+
}
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def execute
|
|
32
|
+
puts Paint["🔧 Generating svgcheck outputs...", :blue, :bold]
|
|
33
|
+
puts Paint["📋 Mode: #{@mode}", :cyan]
|
|
34
|
+
|
|
35
|
+
# Ensure output directories exist
|
|
36
|
+
ensure_output_directories
|
|
37
|
+
|
|
38
|
+
if @single_file
|
|
39
|
+
generate_single_output(@single_file)
|
|
40
|
+
else
|
|
41
|
+
generate_all_outputs
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
def ensure_output_directories
|
|
48
|
+
case @mode
|
|
49
|
+
when "check"
|
|
50
|
+
FileUtils.mkdir_p(File.join(@fixtures_path, "check"))
|
|
51
|
+
when "repair"
|
|
52
|
+
FileUtils.mkdir_p(File.join(@fixtures_path, "repair"))
|
|
53
|
+
when "both"
|
|
54
|
+
FileUtils.mkdir_p(File.join(@fixtures_path, "check"))
|
|
55
|
+
FileUtils.mkdir_p(File.join(@fixtures_path, "repair"))
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def generate_single_output(filename)
|
|
60
|
+
test_file_path = File.join(@test_dir, filename)
|
|
61
|
+
|
|
62
|
+
unless File.exist?(test_file_path)
|
|
63
|
+
puts Paint["❌ Test file not found: #{test_file_path}", :red]
|
|
64
|
+
return false
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
success = true
|
|
68
|
+
|
|
69
|
+
case @mode
|
|
70
|
+
when "check"
|
|
71
|
+
success = generate_mode_output(filename, "check")
|
|
72
|
+
when "repair"
|
|
73
|
+
success = generate_mode_output(filename, "repair")
|
|
74
|
+
when "both"
|
|
75
|
+
check_success = generate_mode_output(filename, "check")
|
|
76
|
+
repair_success = generate_mode_output(filename, "repair")
|
|
77
|
+
success = check_success && repair_success
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
if success
|
|
81
|
+
puts Paint["✅ Generated outputs for #{filename}", :green]
|
|
82
|
+
else
|
|
83
|
+
puts Paint["❌ Failed to generate outputs for #{filename}", :red]
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
success
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def generate_mode_output(filename, mode)
|
|
90
|
+
test_file_path = File.join(@test_dir, filename)
|
|
91
|
+
|
|
92
|
+
# Apply file renaming if applicable
|
|
93
|
+
output_filename = @file_rename_map[filename] || filename
|
|
94
|
+
base_name = File.basename(output_filename, ".*")
|
|
95
|
+
extension = File.extname(output_filename)
|
|
96
|
+
|
|
97
|
+
# Create mode-specific output directory and base path
|
|
98
|
+
mode_dir = File.join(@fixtures_path, mode)
|
|
99
|
+
output_base = File.join(mode_dir, "#{base_name}#{extension}")
|
|
100
|
+
|
|
101
|
+
# Check if outputs already exist
|
|
102
|
+
expected_files = if mode == "repair"
|
|
103
|
+
["#{output_base}.out", "#{output_base}.err",
|
|
104
|
+
"#{output_base}.code", "#{output_base}.file"]
|
|
105
|
+
else
|
|
106
|
+
["#{output_base}.out", "#{output_base}.err",
|
|
107
|
+
"#{output_base}.code"]
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
if expected_files.any? { |f| File.exist?(f) } && !@force
|
|
111
|
+
puts Paint["⚠️ #{mode.capitalize} outputs already exist for #{filename} (use --force to overwrite)",
|
|
112
|
+
:yellow]
|
|
113
|
+
return true
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
puts Paint["📄 Generating #{mode} outputs for #{filename}...", :cyan]
|
|
117
|
+
|
|
118
|
+
run_svgcheck_mode(test_file_path, output_base, mode)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def generate_all_outputs
|
|
122
|
+
test_files = find_test_files
|
|
123
|
+
|
|
124
|
+
if test_files.empty?
|
|
125
|
+
puts Paint["❌ No test files found in #{@test_dir}", :red]
|
|
126
|
+
return
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
puts Paint["📊 Found #{test_files.length} test files", :cyan]
|
|
130
|
+
|
|
131
|
+
success_count = 0
|
|
132
|
+
skip_count = 0
|
|
133
|
+
error_count = 0
|
|
134
|
+
|
|
135
|
+
test_files.each do |filename|
|
|
136
|
+
# Skip problematic files
|
|
137
|
+
if should_skip_file?(filename)
|
|
138
|
+
puts Paint["⏭️ Skipping #{filename} (too large or problematic)",
|
|
139
|
+
:yellow]
|
|
140
|
+
skip_count += 1
|
|
141
|
+
next
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
if generate_single_output(filename)
|
|
145
|
+
success_count += 1
|
|
146
|
+
else
|
|
147
|
+
error_count += 1
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
puts "\n#{Paint['📈 GENERATION SUMMARY:', :blue, :bold]}"
|
|
152
|
+
puts " ✅ Successfully generated: #{Paint[success_count.to_s, :green,
|
|
153
|
+
:bold]}"
|
|
154
|
+
puts " ⏭️ Skipped: #{Paint[skip_count.to_s, :yellow, :bold]}"
|
|
155
|
+
puts " ❌ Failed: #{Paint[error_count.to_s, :red, :bold]}"
|
|
156
|
+
puts " 📁 Output directory: #{Paint[@fixtures_path, :cyan]}"
|
|
157
|
+
|
|
158
|
+
case @mode
|
|
159
|
+
when "check"
|
|
160
|
+
puts " 📂 Check outputs: #{Paint[File.join(@fixtures_path, 'check'),
|
|
161
|
+
:cyan]}"
|
|
162
|
+
when "repair"
|
|
163
|
+
puts " 📂 Repair outputs: #{Paint[File.join(@fixtures_path, 'repair'),
|
|
164
|
+
:cyan]}"
|
|
165
|
+
when "both"
|
|
166
|
+
puts " 📂 Check outputs: #{Paint[File.join(@fixtures_path, 'check'),
|
|
167
|
+
:cyan]}"
|
|
168
|
+
puts " 📂 Repair outputs: #{Paint[File.join(@fixtures_path, 'repair'),
|
|
169
|
+
:cyan]}"
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def find_test_files
|
|
174
|
+
return [] unless Dir.exist?(@test_dir)
|
|
175
|
+
|
|
176
|
+
# Find all .svg and .xml files
|
|
177
|
+
pattern = File.join(@test_dir, "*.{svg,xml}")
|
|
178
|
+
Dir.glob(pattern).map { |path| File.basename(path) }.sort
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def should_skip_file?(filename)
|
|
182
|
+
# Skip files that are known to be problematic
|
|
183
|
+
skip_patterns = [
|
|
184
|
+
/^full-tiny\.xml$/, # Too large
|
|
185
|
+
/^cache_saved/, # Cache directory
|
|
186
|
+
]
|
|
187
|
+
|
|
188
|
+
skip_patterns.any? { |pattern| filename.match?(pattern) }
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def run_svgcheck_mode(input_file, output_base, mode)
|
|
192
|
+
# Check if python3 is available
|
|
193
|
+
unless command_available?("python3")
|
|
194
|
+
puts Paint["❌ python3 not found. Please install Python 3.", :red]
|
|
195
|
+
return false
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
# Check if svgcheck module is available
|
|
199
|
+
unless Dir.exist?(@svgcheck_dir)
|
|
200
|
+
puts Paint["❌ svgcheck directory not found: #{@svgcheck_dir}", :red]
|
|
201
|
+
return false
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
begin
|
|
205
|
+
# Change to svgcheck directory to run the module
|
|
206
|
+
original_dir = Dir.pwd
|
|
207
|
+
Dir.chdir(@svgcheck_dir)
|
|
208
|
+
|
|
209
|
+
# Build command based on mode
|
|
210
|
+
relative_input = File.join("Tests", File.basename(input_file))
|
|
211
|
+
cmd = if mode == "repair"
|
|
212
|
+
["python3", "run.py", "--repair", relative_input]
|
|
213
|
+
else
|
|
214
|
+
["python3", "run.py", relative_input] # check mode - no --repair flag
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
puts " Running #{mode}: #{cmd.join(' ')}" if @verbose
|
|
218
|
+
|
|
219
|
+
stdout, stderr, status = Open3.capture3(*cmd)
|
|
220
|
+
|
|
221
|
+
# Return to original directory
|
|
222
|
+
Dir.chdir(original_dir)
|
|
223
|
+
|
|
224
|
+
# svgcheck writes validation messages to stderr, save as .out (following existing convention)
|
|
225
|
+
File.write("#{output_base}.out", stderr)
|
|
226
|
+
|
|
227
|
+
# svgcheck writes any other errors to stderr, but we'll keep a separate .err for consistency
|
|
228
|
+
File.write("#{output_base}.err", "")
|
|
229
|
+
|
|
230
|
+
# Write exit code to .code file
|
|
231
|
+
File.write("#{output_base}.code", status.exitstatus.to_s)
|
|
232
|
+
|
|
233
|
+
# For repair mode, svgcheck writes remediated SVG content to stdout
|
|
234
|
+
# For check mode, stdout should be empty or minimal
|
|
235
|
+
File.write("#{output_base}.file", stdout) if mode == "repair"
|
|
236
|
+
|
|
237
|
+
puts " #{mode.capitalize} exit status: #{status.exitstatus}" if @verbose
|
|
238
|
+
puts " #{mode.capitalize} stdout lines: #{stdout.lines.count}" if @verbose
|
|
239
|
+
puts " #{mode.capitalize} stderr lines: #{stderr.lines.count}" if @verbose
|
|
240
|
+
|
|
241
|
+
true
|
|
242
|
+
rescue StandardError => e
|
|
243
|
+
puts Paint["❌ Error running svgcheck in #{mode} mode: #{e.message}",
|
|
244
|
+
:red]
|
|
245
|
+
# Make sure we return to original directory even on error
|
|
246
|
+
Dir.chdir(original_dir) if Dir.pwd != original_dir
|
|
247
|
+
false
|
|
248
|
+
end
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
# SECURITY: Prevent command injection by using array form of system()
|
|
252
|
+
# GitHub CodeQL: Uncontrolled command line (CWE-078)
|
|
253
|
+
# This affects svgcheck generation commands (development use only)
|
|
254
|
+
def command_available?(command)
|
|
255
|
+
# Use array form to prevent shell injection
|
|
256
|
+
system("which", command, out: File::NULL, err: File::NULL) ||
|
|
257
|
+
system("where", command, out: File::NULL, err: File::NULL) || # Windows
|
|
258
|
+
File.executable?(command) # Direct path check
|
|
259
|
+
end
|
|
260
|
+
end
|
|
261
|
+
end
|
|
262
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SvgConform
|
|
4
|
+
module Compatibility
|
|
5
|
+
# Value object representing the context and configuration for compatibility analysis
|
|
6
|
+
class AnalysisContext
|
|
7
|
+
attr_reader :mode, :profile, :semantic, :svgcheck_dir, :file, :output_file
|
|
8
|
+
|
|
9
|
+
def initialize(options = {})
|
|
10
|
+
@mode = (options[:mode] || "check").to_sym
|
|
11
|
+
@profile = options[:profile]&.to_sym || :svg_1_2_rfc_compatible
|
|
12
|
+
@semantic = options[:semantic] || false
|
|
13
|
+
@svgcheck_dir = options[:svgcheck_dir] || "spec/fixtures/svgcheck"
|
|
14
|
+
@file = options[:file]
|
|
15
|
+
@output_file = options[:output]
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def single_file_analysis?
|
|
19
|
+
!@file.nil?
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def batch_analysis?
|
|
23
|
+
@file.nil?
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def check_mode?
|
|
27
|
+
@mode == :check
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def repair_mode?
|
|
31
|
+
@mode == :repair
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def semantic_analysis?
|
|
35
|
+
@semantic
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def file_output?
|
|
39
|
+
!@output_file.nil?
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def inputs_dir
|
|
43
|
+
File.join(@svgcheck_dir, "inputs")
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def outputs_dir
|
|
47
|
+
File.join(@svgcheck_dir, @mode.to_s)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def input_file_path
|
|
51
|
+
return nil unless single_file_analysis?
|
|
52
|
+
|
|
53
|
+
File.join(inputs_dir, @file)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def to_h
|
|
57
|
+
{
|
|
58
|
+
mode: @mode,
|
|
59
|
+
profile: @profile,
|
|
60
|
+
semantic: @semantic,
|
|
61
|
+
svgcheck_dir: @svgcheck_dir,
|
|
62
|
+
file: @file,
|
|
63
|
+
output_file: @output_file,
|
|
64
|
+
}
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SvgConform
|
|
4
|
+
module Compatibility
|
|
5
|
+
# Value object representing the results of a compatibility comparison
|
|
6
|
+
class ComparisonResult
|
|
7
|
+
attr_reader :filename, :type, :validation_comparison, :content_comparison,
|
|
8
|
+
:xml_equivalence, :svg_conform_result, :svgcheck_result
|
|
9
|
+
|
|
10
|
+
def initialize(filename:, type:, **options)
|
|
11
|
+
@filename = filename
|
|
12
|
+
@type = type
|
|
13
|
+
@validation_comparison = options[:validation_comparison]
|
|
14
|
+
@content_comparison = options[:content_comparison]
|
|
15
|
+
@xml_equivalence = options[:xml_equivalence]
|
|
16
|
+
@svg_conform_result = options[:svg_conform_result]
|
|
17
|
+
@svgcheck_result = options[:svgcheck_result]
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def semantic_validation?
|
|
21
|
+
@type == :semantic_validation
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def semantic_repair?
|
|
25
|
+
@type == :semantic_repair
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def basic_validation?
|
|
29
|
+
@type == :basic_validation
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def basic_repair?
|
|
33
|
+
@type == :basic_repair
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def compatibility_score
|
|
37
|
+
return 0.0 unless @validation_comparison
|
|
38
|
+
|
|
39
|
+
raw_score = @validation_comparison[:compatibility_score] || 0.0
|
|
40
|
+
raw_score * 100.0
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def validity_match?
|
|
44
|
+
return false unless @validation_comparison
|
|
45
|
+
|
|
46
|
+
@validation_comparison.dig(:overall_validity, :match) || false
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def svg_conform_valid?
|
|
50
|
+
if semantic_validation? || semantic_repair?
|
|
51
|
+
@validation_comparison&.dig(:overall_validity, :svg_conform) || false
|
|
52
|
+
else
|
|
53
|
+
@svg_conform_result&.success? || false
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def svgcheck_valid?
|
|
58
|
+
if semantic_validation? || semantic_repair?
|
|
59
|
+
@validation_comparison&.dig(:overall_validity, :svgcheck) || false
|
|
60
|
+
else
|
|
61
|
+
@svgcheck_result&.valid || false
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def content_equivalence_score
|
|
66
|
+
return 0.0 unless @content_comparison
|
|
67
|
+
|
|
68
|
+
raw_score = @content_comparison[:semantic_equivalence] || 0.0
|
|
69
|
+
raw_score * 100.0
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def xml_equivalent?
|
|
73
|
+
return false unless @xml_equivalence
|
|
74
|
+
|
|
75
|
+
@xml_equivalence[:xml_equivalent] || false
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def xml_differences
|
|
79
|
+
return [] unless @xml_equivalence
|
|
80
|
+
|
|
81
|
+
@xml_equivalence[:differences] || []
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def xml_error
|
|
85
|
+
return nil unless @xml_equivalence
|
|
86
|
+
|
|
87
|
+
@xml_equivalence[:error]
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def successful_remediation?
|
|
91
|
+
if semantic_repair?
|
|
92
|
+
svg_conform_valid?
|
|
93
|
+
elsif basic_repair?
|
|
94
|
+
@svg_conform_result&.success? || false
|
|
95
|
+
else
|
|
96
|
+
false
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def issues_fixed
|
|
101
|
+
return 0 unless basic_repair?
|
|
102
|
+
|
|
103
|
+
@svg_conform_result&.issues_fixed || 0
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def remediations_applied
|
|
107
|
+
return 0 unless basic_repair?
|
|
108
|
+
|
|
109
|
+
@svg_conform_result&.remediations_applied || 0
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def error_count
|
|
113
|
+
if semantic_validation? || semantic_repair?
|
|
114
|
+
# For semantic results, we'd need to extract from validation_comparison
|
|
115
|
+
0
|
|
116
|
+
else
|
|
117
|
+
# For basic repair mode, count initial validation errors
|
|
118
|
+
svg_conform_errors = if @svg_conform_result&.initial_validation
|
|
119
|
+
@svg_conform_result.initial_validation.failed_requirements.length
|
|
120
|
+
else
|
|
121
|
+
0
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
svgcheck_errors = @svgcheck_result&.errors&.total_count || 0
|
|
125
|
+
|
|
126
|
+
svg_conform_errors + svgcheck_errors
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def to_h
|
|
131
|
+
{
|
|
132
|
+
filename: @filename,
|
|
133
|
+
type: @type,
|
|
134
|
+
compatibility_score: compatibility_score,
|
|
135
|
+
validity_match: validity_match?,
|
|
136
|
+
svg_conform_valid: svg_conform_valid?,
|
|
137
|
+
svgcheck_valid: svgcheck_valid?,
|
|
138
|
+
content_equivalence_score: content_equivalence_score,
|
|
139
|
+
xml_equivalent: xml_equivalent?,
|
|
140
|
+
successful_remediation: successful_remediation?,
|
|
141
|
+
issues_fixed: issues_fixed,
|
|
142
|
+
remediations_applied: remediations_applied,
|
|
143
|
+
}
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "analysis_context"
|
|
4
|
+
require_relative "comparison_result"
|
|
5
|
+
require_relative "file_processor"
|
|
6
|
+
require_relative "svg_analysis_engine"
|
|
7
|
+
require_relative "xml_analysis_engine"
|
|
8
|
+
require_relative "report_formatter"
|
|
9
|
+
|
|
10
|
+
module SvgConform
|
|
11
|
+
module Compatibility
|
|
12
|
+
# Main orchestrator for compatibility analysis operations
|
|
13
|
+
class CompatibilityAnalyzer
|
|
14
|
+
def initialize(options = {})
|
|
15
|
+
@context = AnalysisContext.new(options)
|
|
16
|
+
@file_processor = FileProcessor.new(@context)
|
|
17
|
+
@svg_engine = SvgAnalysisEngine.new(@context, @file_processor)
|
|
18
|
+
@xml_engine = XmlAnalysisEngine.new(@context, @file_processor)
|
|
19
|
+
@formatter = ReportFormatter.new(@context)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def run_analysis
|
|
23
|
+
@file_processor.validate_environment
|
|
24
|
+
|
|
25
|
+
if @context.single_file_analysis?
|
|
26
|
+
run_single_file_analysis
|
|
27
|
+
else
|
|
28
|
+
run_batch_analysis
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
def run_single_file_analysis
|
|
35
|
+
filename = @context.file
|
|
36
|
+
result = analyze_single_file(filename)
|
|
37
|
+
|
|
38
|
+
if result
|
|
39
|
+
@formatter.display_single_file_result(result)
|
|
40
|
+
@formatter.write_output_file(result)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
result
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def run_batch_analysis
|
|
47
|
+
files = @file_processor.discover_files
|
|
48
|
+
results = []
|
|
49
|
+
|
|
50
|
+
files.each do |filename|
|
|
51
|
+
result = analyze_single_file(filename)
|
|
52
|
+
results << result if result
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
@formatter.display_batch_results(results)
|
|
56
|
+
@formatter.write_output_file(results)
|
|
57
|
+
|
|
58
|
+
results
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def analyze_single_file(filename)
|
|
62
|
+
unless @file_processor.file_exists?(filename)
|
|
63
|
+
puts "❌ Input file not found: #{filename}"
|
|
64
|
+
return nil
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
svgcheck_report = @file_processor.parse_svgcheck_outputs(filename)
|
|
68
|
+
unless svgcheck_report
|
|
69
|
+
puts "❌ Svgcheck outputs not found for: #{filename}"
|
|
70
|
+
return nil
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
if @file_processor.xml_file?(filename)
|
|
74
|
+
@xml_engine.analyze_file(filename, svgcheck_report)
|
|
75
|
+
else
|
|
76
|
+
@svg_engine.analyze_file(filename, svgcheck_report)
|
|
77
|
+
end
|
|
78
|
+
rescue StandardError => e
|
|
79
|
+
puts "❌ Error analyzing #{filename}: #{e.message}"
|
|
80
|
+
puts e.backtrace.first(5).join("\n") if ENV["DEBUG"]
|
|
81
|
+
nil
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|