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.
Files changed (335) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/rake.yml +15 -0
  3. data/.github/workflows/release.yml +23 -0
  4. data/.github/workflows/svgcheck-compatibility.yml +135 -0
  5. data/.gitignore +12 -0
  6. data/.rspec +3 -0
  7. data/.rubocop.yml +13 -0
  8. data/.rubocop_todo.yml +183 -0
  9. data/CODE_OF_CONDUCT.md +132 -0
  10. data/Gemfile +14 -0
  11. data/README.adoc +1384 -0
  12. data/Rakefile +15 -0
  13. data/config/profiles/base.yml +34 -0
  14. data/config/profiles/lucid_fix.yml +37 -0
  15. data/config/profiles/metanorma.yml +212 -0
  16. data/config/profiles/no_external_css.yml +20 -0
  17. data/config/profiles/svg_1_2_rfc.yml +284 -0
  18. data/config/profiles/svg_1_2_rfc_with_rdf.yml +145 -0
  19. data/config/svgcheck_mapping.yml +180 -0
  20. data/docs/profiles.adoc +547 -0
  21. data/docs/rdf_metadata_support.adoc +212 -0
  22. data/docs/remediation.adoc +732 -0
  23. data/docs/requirements.adoc +709 -0
  24. data/examples/demo.rb +116 -0
  25. data/examples/requirements_demo.rb +240 -0
  26. data/exe/svg_conform +7 -0
  27. data/lib/svg_conform/batch_report.rb +70 -0
  28. data/lib/svg_conform/cli.rb +107 -0
  29. data/lib/svg_conform/commands/check.rb +390 -0
  30. data/lib/svg_conform/commands/profiles.rb +118 -0
  31. data/lib/svg_conform/commands/svgcheck.rb +90 -0
  32. data/lib/svg_conform/commands/svgcheck_compare.rb +92 -0
  33. data/lib/svg_conform/commands/svgcheck_compatibility.rb +43 -0
  34. data/lib/svg_conform/commands/svgcheck_generate.rb +262 -0
  35. data/lib/svg_conform/compatibility/analysis_context.rb +68 -0
  36. data/lib/svg_conform/compatibility/comparison_result.rb +147 -0
  37. data/lib/svg_conform/compatibility/compatibility_analyzer.rb +85 -0
  38. data/lib/svg_conform/compatibility/file_processor.rb +109 -0
  39. data/lib/svg_conform/compatibility/pattern_discovery.rb +319 -0
  40. data/lib/svg_conform/compatibility/report_formatter.rb +359 -0
  41. data/lib/svg_conform/compatibility/svg_analysis_engine.rb +316 -0
  42. data/lib/svg_conform/compatibility/validity_analysis.rb +252 -0
  43. data/lib/svg_conform/compatibility/xml_analysis_engine.rb +198 -0
  44. data/lib/svg_conform/compatibility_analyzer.rb +285 -0
  45. data/lib/svg_conform/conformance_report.rb +267 -0
  46. data/lib/svg_conform/constants.rb +199 -0
  47. data/lib/svg_conform/css_color.rb +262 -0
  48. data/lib/svg_conform/document.rb +203 -0
  49. data/lib/svg_conform/external_checkers/svgcheck/compatibility_engine.rb +166 -0
  50. data/lib/svg_conform/external_checkers/svgcheck/output_generator.rb +101 -0
  51. data/lib/svg_conform/external_checkers/svgcheck/parser.rb +200 -0
  52. data/lib/svg_conform/external_checkers/svgcheck/report_comparator.rb +175 -0
  53. data/lib/svg_conform/external_checkers/svgcheck/report_generator.rb +82 -0
  54. data/lib/svg_conform/external_checkers/svgcheck/validation_pipeline.rb +249 -0
  55. data/lib/svg_conform/external_checkers/svgcheck.rb +56 -0
  56. data/lib/svg_conform/external_checkers.rb +34 -0
  57. data/lib/svg_conform/fixer.rb +56 -0
  58. data/lib/svg_conform/profile.rb +164 -0
  59. data/lib/svg_conform/profiles.rb +60 -0
  60. data/lib/svg_conform/remediation_engine.rb +92 -0
  61. data/lib/svg_conform/remediation_result.rb +36 -0
  62. data/lib/svg_conform/remediation_runner.rb +225 -0
  63. data/lib/svg_conform/remediations/base_remediation.rb +165 -0
  64. data/lib/svg_conform/remediations/color_remediation.rb +226 -0
  65. data/lib/svg_conform/remediations/font_embedding_remediation.rb +145 -0
  66. data/lib/svg_conform/remediations/font_remediation.rb +122 -0
  67. data/lib/svg_conform/remediations/image_embedding_remediation.rb +154 -0
  68. data/lib/svg_conform/remediations/invalid_id_references_remediation.rb +129 -0
  69. data/lib/svg_conform/remediations/namespace_attribute_remediation.rb +244 -0
  70. data/lib/svg_conform/remediations/namespace_remediation.rb +151 -0
  71. data/lib/svg_conform/remediations/no_external_css_remediation.rb +192 -0
  72. data/lib/svg_conform/remediations/style_promotion_remediation.rb +93 -0
  73. data/lib/svg_conform/remediations/viewbox_remediation.rb +127 -0
  74. data/lib/svg_conform/remediations.rb +40 -0
  75. data/lib/svg_conform/report_comparator.rb +772 -0
  76. data/lib/svg_conform/requirements/allowed_elements_requirement.rb +367 -0
  77. data/lib/svg_conform/requirements/base_requirement.rb +98 -0
  78. data/lib/svg_conform/requirements/color_restrictions_requirement.rb +126 -0
  79. data/lib/svg_conform/requirements/element_requirement_config.rb +75 -0
  80. data/lib/svg_conform/requirements/font_family_requirement.rb +133 -0
  81. data/lib/svg_conform/requirements/forbidden_content_requirement.rb +60 -0
  82. data/lib/svg_conform/requirements/id_reference_requirement.rb +133 -0
  83. data/lib/svg_conform/requirements/invalid_id_references_requirement.rb +132 -0
  84. data/lib/svg_conform/requirements/link_validation_requirement.rb +55 -0
  85. data/lib/svg_conform/requirements/namespace_attributes_requirement.rb +211 -0
  86. data/lib/svg_conform/requirements/namespace_requirement.rb +294 -0
  87. data/lib/svg_conform/requirements/no_external_css_requirement.rb +132 -0
  88. data/lib/svg_conform/requirements/no_external_fonts_requirement.rb +121 -0
  89. data/lib/svg_conform/requirements/no_external_images_requirement.rb +91 -0
  90. data/lib/svg_conform/requirements/style_promotion_requirement.rb +72 -0
  91. data/lib/svg_conform/requirements/style_requirement.rb +226 -0
  92. data/lib/svg_conform/requirements/viewbox_required_requirement.rb +96 -0
  93. data/lib/svg_conform/requirements.rb +49 -0
  94. data/lib/svg_conform/semantic_comparator.rb +829 -0
  95. data/lib/svg_conform/validation_context.rb +408 -0
  96. data/lib/svg_conform/validation_result.rb +146 -0
  97. data/lib/svg_conform/validator.rb +91 -0
  98. data/lib/svg_conform/version.rb +5 -0
  99. data/lib/svg_conform.rb +68 -0
  100. data/lib/tasks/fixtures.rake +321 -0
  101. data/lib/tasks/svgcheck.rake +111 -0
  102. data/reference-docs/SVG-1.2-RFC.rnc.txt +1676 -0
  103. data/reference-docs/Scalable Vector Graphics (SVG) 1.1 (Second Edition).html +40764 -0
  104. data/reference-docs/Scalable Vector Graphics (SVG) Tiny 1.2 Specification.html +44591 -0
  105. data/reference-docs/rfc7996.txt +2971 -0
  106. data/sig/svg_conform.rbs +4 -0
  107. data/spec/fixtures/allowed_elements/inputs/basic_violations.svg +21 -0
  108. data/spec/fixtures/allowed_elements/repair/basic_violations.svg +18 -0
  109. data/spec/fixtures/color_restrictions/inputs/basic_violations.svg +23 -0
  110. data/spec/fixtures/color_restrictions/repair/basic_violations.svg +23 -0
  111. data/spec/fixtures/comprehensive/inputs/multiple_violations.svg +21 -0
  112. data/spec/fixtures/comprehensive/repair/multiple_violations.svg +16 -0
  113. data/spec/fixtures/font_family/inputs/basic_violations.svg +17 -0
  114. data/spec/fixtures/font_family/repair/basic_violations.svg +17 -0
  115. data/spec/fixtures/forbidden_content/inputs/basic_violations.svg +27 -0
  116. data/spec/fixtures/forbidden_content/repair/basic_violations.svg +19 -0
  117. data/spec/fixtures/id_reference/inputs/basic_violations.svg +17 -0
  118. data/spec/fixtures/id_reference/repair/basic_violations.svg +15 -0
  119. data/spec/fixtures/link_validation/inputs/basic_violations.svg +20 -0
  120. data/spec/fixtures/link_validation/repair/basic_violations.svg +16 -0
  121. data/spec/fixtures/lucid/inputs/simple.svg +67 -0
  122. data/spec/fixtures/lucid/repair/simple.svg +63 -0
  123. data/spec/fixtures/namespace/inputs/basic_violations.svg +20 -0
  124. data/spec/fixtures/namespace/repair/basic_violations.svg +17 -0
  125. data/spec/fixtures/namespace_attributes/inputs/basic_violations.svg +16 -0
  126. data/spec/fixtures/namespace_attributes/repair/basic_violations.svg +15 -0
  127. data/spec/fixtures/no_external_css/inputs/basic_violations.svg +20 -0
  128. data/spec/fixtures/no_external_css/repair/basic_violations.svg +18 -0
  129. data/spec/fixtures/style/inputs/basic_violations.svg +22 -0
  130. data/spec/fixtures/style/repair/basic_violations.svg +22 -0
  131. data/spec/fixtures/style_promotion/inputs/basic_test.svg +15 -0
  132. data/spec/fixtures/style_promotion/repair/basic_test.svg +15 -0
  133. data/spec/fixtures/svg_1_2_rfc/inputs/allowed_elements_violations.svg +18 -0
  134. data/spec/fixtures/svg_1_2_rfc/inputs/color_restrictions_violations.svg +23 -0
  135. data/spec/fixtures/svgcheck/check/DrawBerry-sample-2.svg.code +1 -0
  136. data/spec/fixtures/svgcheck/check/DrawBerry-sample-2.svg.err +0 -0
  137. data/spec/fixtures/svgcheck/check/DrawBerry-sample-2.svg.out +23 -0
  138. data/spec/fixtures/svgcheck/check/IETF-test.svg.code +1 -0
  139. data/spec/fixtures/svgcheck/check/IETF-test.svg.err +0 -0
  140. data/spec/fixtures/svgcheck/check/IETF-test.svg.out +20 -0
  141. data/spec/fixtures/svgcheck/check/circle.svg.code +1 -0
  142. data/spec/fixtures/svgcheck/check/circle.svg.err +0 -0
  143. data/spec/fixtures/svgcheck/check/circle.svg.out +2 -0
  144. data/spec/fixtures/svgcheck/check/colors.svg.code +1 -0
  145. data/spec/fixtures/svgcheck/check/colors.svg.err +0 -0
  146. data/spec/fixtures/svgcheck/check/colors.svg.out +13 -0
  147. data/spec/fixtures/svgcheck/check/dia-sample-svg.svg.code +1 -0
  148. data/spec/fixtures/svgcheck/check/dia-sample-svg.svg.err +0 -0
  149. data/spec/fixtures/svgcheck/check/dia-sample-svg.svg.out +76 -0
  150. data/spec/fixtures/svgcheck/check/example-dot.svg.code +1 -0
  151. data/spec/fixtures/svgcheck/check/example-dot.svg.err +0 -0
  152. data/spec/fixtures/svgcheck/check/example-dot.svg.out +11 -0
  153. data/spec/fixtures/svgcheck/check/full-tiny.svg.code +1 -0
  154. data/spec/fixtures/svgcheck/check/full-tiny.svg.err +0 -0
  155. data/spec/fixtures/svgcheck/check/full-tiny.svg.out +5835 -0
  156. data/spec/fixtures/svgcheck/check/good.svg.code +1 -0
  157. data/spec/fixtures/svgcheck/check/good.svg.err +0 -0
  158. data/spec/fixtures/svgcheck/check/good.svg.out +1 -0
  159. data/spec/fixtures/svgcheck/check/httpbis-proxy20-fig6.svg.code +1 -0
  160. data/spec/fixtures/svgcheck/check/httpbis-proxy20-fig6.svg.err +0 -0
  161. data/spec/fixtures/svgcheck/check/httpbis-proxy20-fig6.svg.out +5 -0
  162. data/spec/fixtures/svgcheck/check/malformed.svg.code +1 -0
  163. data/spec/fixtures/svgcheck/check/malformed.svg.err +0 -0
  164. data/spec/fixtures/svgcheck/check/malformed.svg.out +8 -0
  165. data/spec/fixtures/svgcheck/check/rfc-svg.svg.code +1 -0
  166. data/spec/fixtures/svgcheck/check/rfc-svg.svg.err +0 -0
  167. data/spec/fixtures/svgcheck/check/rfc-svg.svg.out +1 -0
  168. data/spec/fixtures/svgcheck/check/rfc.xml.code +1 -0
  169. data/spec/fixtures/svgcheck/check/rfc.xml.err +0 -0
  170. data/spec/fixtures/svgcheck/check/rfc.xml.out +2 -0
  171. data/spec/fixtures/svgcheck/check/rgb.svg.code +1 -0
  172. data/spec/fixtures/svgcheck/check/rgb.svg.err +0 -0
  173. data/spec/fixtures/svgcheck/check/rgb.svg.out +9 -0
  174. data/spec/fixtures/svgcheck/check/svg-wordle.svg.code +1 -0
  175. data/spec/fixtures/svgcheck/check/svg-wordle.svg.err +0 -0
  176. data/spec/fixtures/svgcheck/check/svg-wordle.svg.out +508 -0
  177. data/spec/fixtures/svgcheck/check/threshold.svg.code +1 -0
  178. data/spec/fixtures/svgcheck/check/threshold.svg.err +0 -0
  179. data/spec/fixtures/svgcheck/check/threshold.svg.out +20 -0
  180. data/spec/fixtures/svgcheck/check/utf8.svg.code +1 -0
  181. data/spec/fixtures/svgcheck/check/utf8.svg.err +0 -0
  182. data/spec/fixtures/svgcheck/check/utf8.svg.out +162 -0
  183. data/spec/fixtures/svgcheck/check/viewBox-both.svg.code +1 -0
  184. data/spec/fixtures/svgcheck/check/viewBox-both.svg.err +0 -0
  185. data/spec/fixtures/svgcheck/check/viewBox-both.svg.out +4 -0
  186. data/spec/fixtures/svgcheck/check/viewBox-height.svg.code +1 -0
  187. data/spec/fixtures/svgcheck/check/viewBox-height.svg.err +0 -0
  188. data/spec/fixtures/svgcheck/check/viewBox-height.svg.out +3 -0
  189. data/spec/fixtures/svgcheck/check/viewBox-none.svg.code +1 -0
  190. data/spec/fixtures/svgcheck/check/viewBox-none.svg.err +0 -0
  191. data/spec/fixtures/svgcheck/check/viewBox-none.svg.out +3 -0
  192. data/spec/fixtures/svgcheck/check/viewBox-width.svg.code +1 -0
  193. data/spec/fixtures/svgcheck/check/viewBox-width.svg.err +0 -0
  194. data/spec/fixtures/svgcheck/check/viewBox-width.svg.out +3 -0
  195. data/spec/fixtures/svgcheck/inputs/DrawBerry-sample-2.svg +28 -0
  196. data/spec/fixtures/svgcheck/inputs/IETF-test.svg +28 -0
  197. data/spec/fixtures/svgcheck/inputs/circle.svg +3 -0
  198. data/spec/fixtures/svgcheck/inputs/colors.svg +18 -0
  199. data/spec/fixtures/svgcheck/inputs/dia-sample-svg.svg +47 -0
  200. data/spec/fixtures/svgcheck/inputs/example-dot.svg +75 -0
  201. data/spec/fixtures/svgcheck/inputs/full-tiny.svg +16194 -0
  202. data/spec/fixtures/svgcheck/inputs/good.svg +19 -0
  203. data/spec/fixtures/svgcheck/inputs/httpbis-proxy20-fig6.svg +2 -0
  204. data/spec/fixtures/svgcheck/inputs/malformed.svg +11 -0
  205. data/spec/fixtures/svgcheck/inputs/rfc-svg.svg +1028 -0
  206. data/spec/fixtures/svgcheck/inputs/rfc.xml +37 -0
  207. data/spec/fixtures/svgcheck/inputs/rgb.svg +9 -0
  208. data/spec/fixtures/svgcheck/inputs/svg-wordle.svg +330 -0
  209. data/spec/fixtures/svgcheck/inputs/threshold.svg +26 -0
  210. data/spec/fixtures/svgcheck/inputs/utf8.svg +448 -0
  211. data/spec/fixtures/svgcheck/inputs/viewBox-both.svg +3 -0
  212. data/spec/fixtures/svgcheck/inputs/viewBox-height.svg +3 -0
  213. data/spec/fixtures/svgcheck/inputs/viewBox-none.svg +3 -0
  214. data/spec/fixtures/svgcheck/inputs/viewBox-width.svg +3 -0
  215. data/spec/fixtures/svgcheck/repair/DrawBerry-sample-2.svg.code +1 -0
  216. data/spec/fixtures/svgcheck/repair/DrawBerry-sample-2.svg.err +0 -0
  217. data/spec/fixtures/svgcheck/repair/DrawBerry-sample-2.svg.file +0 -0
  218. data/spec/fixtures/svgcheck/repair/DrawBerry-sample-2.svg.out +23 -0
  219. data/spec/fixtures/svgcheck/repair/IETF-test.svg.code +1 -0
  220. data/spec/fixtures/svgcheck/repair/IETF-test.svg.err +0 -0
  221. data/spec/fixtures/svgcheck/repair/IETF-test.svg.file +29 -0
  222. data/spec/fixtures/svgcheck/repair/IETF-test.svg.out +20 -0
  223. data/spec/fixtures/svgcheck/repair/circle.svg.code +1 -0
  224. data/spec/fixtures/svgcheck/repair/circle.svg.err +0 -0
  225. data/spec/fixtures/svgcheck/repair/circle.svg.file +4 -0
  226. data/spec/fixtures/svgcheck/repair/circle.svg.out +2 -0
  227. data/spec/fixtures/svgcheck/repair/colors.svg.code +1 -0
  228. data/spec/fixtures/svgcheck/repair/colors.svg.err +0 -0
  229. data/spec/fixtures/svgcheck/repair/colors.svg.file +19 -0
  230. data/spec/fixtures/svgcheck/repair/colors.svg.out +13 -0
  231. data/spec/fixtures/svgcheck/repair/dia-sample-svg.svg.code +1 -0
  232. data/spec/fixtures/svgcheck/repair/dia-sample-svg.svg.err +0 -0
  233. data/spec/fixtures/svgcheck/repair/dia-sample-svg.svg.file +47 -0
  234. data/spec/fixtures/svgcheck/repair/dia-sample-svg.svg.out +76 -0
  235. data/spec/fixtures/svgcheck/repair/example-dot.svg.code +1 -0
  236. data/spec/fixtures/svgcheck/repair/example-dot.svg.err +0 -0
  237. data/spec/fixtures/svgcheck/repair/example-dot.svg.file +69 -0
  238. data/spec/fixtures/svgcheck/repair/example-dot.svg.out +11 -0
  239. data/spec/fixtures/svgcheck/repair/good.svg.code +1 -0
  240. data/spec/fixtures/svgcheck/repair/good.svg.err +0 -0
  241. data/spec/fixtures/svgcheck/repair/good.svg.file +0 -0
  242. data/spec/fixtures/svgcheck/repair/good.svg.out +1 -0
  243. data/spec/fixtures/svgcheck/repair/httpbis-proxy20-fig6.svg.code +1 -0
  244. data/spec/fixtures/svgcheck/repair/httpbis-proxy20-fig6.svg.err +0 -0
  245. data/spec/fixtures/svgcheck/repair/httpbis-proxy20-fig6.svg.file +73 -0
  246. data/spec/fixtures/svgcheck/repair/httpbis-proxy20-fig6.svg.out +5 -0
  247. data/spec/fixtures/svgcheck/repair/malformed.svg.code +1 -0
  248. data/spec/fixtures/svgcheck/repair/malformed.svg.err +0 -0
  249. data/spec/fixtures/svgcheck/repair/malformed.svg.file +9 -0
  250. data/spec/fixtures/svgcheck/repair/malformed.svg.out +8 -0
  251. data/spec/fixtures/svgcheck/repair/rfc-svg.svg.code +1 -0
  252. data/spec/fixtures/svgcheck/repair/rfc-svg.svg.err +0 -0
  253. data/spec/fixtures/svgcheck/repair/rfc-svg.svg.file +0 -0
  254. data/spec/fixtures/svgcheck/repair/rfc-svg.svg.out +1 -0
  255. data/spec/fixtures/svgcheck/repair/rfc.xml.code +1 -0
  256. data/spec/fixtures/svgcheck/repair/rfc.xml.err +0 -0
  257. data/spec/fixtures/svgcheck/repair/rfc.xml.file +37 -0
  258. data/spec/fixtures/svgcheck/repair/rfc.xml.out +2 -0
  259. data/spec/fixtures/svgcheck/repair/rgb.svg.code +1 -0
  260. data/spec/fixtures/svgcheck/repair/rgb.svg.err +0 -0
  261. data/spec/fixtures/svgcheck/repair/rgb.svg.file +10 -0
  262. data/spec/fixtures/svgcheck/repair/rgb.svg.out +9 -0
  263. data/spec/fixtures/svgcheck/repair/svg-wordle.svg.code +1 -0
  264. data/spec/fixtures/svgcheck/repair/svg-wordle.svg.err +0 -0
  265. data/spec/fixtures/svgcheck/repair/svg-wordle.svg.file +112 -0
  266. data/spec/fixtures/svgcheck/repair/svg-wordle.svg.out +508 -0
  267. data/spec/fixtures/svgcheck/repair/threshold.svg.code +1 -0
  268. data/spec/fixtures/svgcheck/repair/threshold.svg.err +0 -0
  269. data/spec/fixtures/svgcheck/repair/threshold.svg.file +27 -0
  270. data/spec/fixtures/svgcheck/repair/threshold.svg.out +20 -0
  271. data/spec/fixtures/svgcheck/repair/utf8.svg.code +1 -0
  272. data/spec/fixtures/svgcheck/repair/utf8.svg.err +0 -0
  273. data/spec/fixtures/svgcheck/repair/utf8.svg.file +381 -0
  274. data/spec/fixtures/svgcheck/repair/utf8.svg.out +162 -0
  275. data/spec/fixtures/svgcheck/repair/viewBox-both.svg.code +1 -0
  276. data/spec/fixtures/svgcheck/repair/viewBox-both.svg.err +0 -0
  277. data/spec/fixtures/svgcheck/repair/viewBox-both.svg.file +4 -0
  278. data/spec/fixtures/svgcheck/repair/viewBox-both.svg.out +4 -0
  279. data/spec/fixtures/svgcheck/repair/viewBox-height.svg.code +1 -0
  280. data/spec/fixtures/svgcheck/repair/viewBox-height.svg.err +0 -0
  281. data/spec/fixtures/svgcheck/repair/viewBox-height.svg.file +4 -0
  282. data/spec/fixtures/svgcheck/repair/viewBox-height.svg.out +3 -0
  283. data/spec/fixtures/svgcheck/repair/viewBox-none.svg.code +1 -0
  284. data/spec/fixtures/svgcheck/repair/viewBox-none.svg.err +0 -0
  285. data/spec/fixtures/svgcheck/repair/viewBox-none.svg.file +4 -0
  286. data/spec/fixtures/svgcheck/repair/viewBox-none.svg.out +3 -0
  287. data/spec/fixtures/svgcheck/repair/viewBox-width.svg.code +1 -0
  288. data/spec/fixtures/svgcheck/repair/viewBox-width.svg.err +0 -0
  289. data/spec/fixtures/svgcheck/repair/viewBox-width.svg.file +4 -0
  290. data/spec/fixtures/svgcheck/repair/viewBox-width.svg.out +3 -0
  291. data/spec/fixtures/viewbox_required/inputs/missing_viewbox.svg +10 -0
  292. data/spec/fixtures/viewbox_required/repair/missing_viewbox.svg +10 -0
  293. data/spec/spec_helper.rb +16 -0
  294. data/spec/svg_conform/batch_report_spec.rb +99 -0
  295. data/spec/svg_conform/commands/check_command_spec.rb +90 -0
  296. data/spec/svg_conform/commands/profiles_command_spec.rb +20 -0
  297. data/spec/svg_conform/commands/svgcheck_compare_command_spec.rb +13 -0
  298. data/spec/svg_conform/commands/svgcheck_compatibility_command_spec.rb +13 -0
  299. data/spec/svg_conform/commands/svgcheck_generate_command_spec.rb +14 -0
  300. data/spec/svg_conform/profiles/base_profile_spec.rb +42 -0
  301. data/spec/svg_conform/profiles/lucid_fix_profile_spec.rb +46 -0
  302. data/spec/svg_conform/profiles/lucid_profile_spec.rb +84 -0
  303. data/spec/svg_conform/profiles/metanorma_profile_spec.rb +62 -0
  304. data/spec/svg_conform/profiles/no_external_css_profile_spec.rb +66 -0
  305. data/spec/svg_conform/profiles/svg_1_2_rfc_profile_spec.rb +200 -0
  306. data/spec/svg_conform/profiles/svg_1_2_rfc_with_rdf_profile_spec.rb +81 -0
  307. data/spec/svg_conform/remediations/color_remediation_spec.rb +95 -0
  308. data/spec/svg_conform/remediations/font_embedding_remediation_spec.rb +20 -0
  309. data/spec/svg_conform/remediations/font_remediation_spec.rb +95 -0
  310. data/spec/svg_conform/remediations/image_embedding_remediation_spec.rb +20 -0
  311. data/spec/svg_conform/remediations/invalid_id_references_remediation_spec.rb +97 -0
  312. data/spec/svg_conform/remediations/namespace_attribute_remediation_spec.rb +97 -0
  313. data/spec/svg_conform/remediations/namespace_remediation_spec.rb +95 -0
  314. data/spec/svg_conform/remediations/no_external_css_remediation_spec.rb +97 -0
  315. data/spec/svg_conform/remediations/style_promotion_remediation_spec.rb +97 -0
  316. data/spec/svg_conform/remediations/viewbox_remediation_spec.rb +95 -0
  317. data/spec/svg_conform/requirements/allowed_elements_requirement_spec.rb +118 -0
  318. data/spec/svg_conform/requirements/color_restrictions_requirement_spec.rb +168 -0
  319. data/spec/svg_conform/requirements/font_family_requirement_spec.rb +188 -0
  320. data/spec/svg_conform/requirements/forbidden_content_requirement_spec.rb +195 -0
  321. data/spec/svg_conform/requirements/id_reference_requirement_spec.rb +78 -0
  322. data/spec/svg_conform/requirements/invalid_id_references_requirement_spec.rb +78 -0
  323. data/spec/svg_conform/requirements/link_validation_requirement_spec.rb +78 -0
  324. data/spec/svg_conform/requirements/namespace_attributes_requirement_spec.rb +86 -0
  325. data/spec/svg_conform/requirements/namespace_requirement_spec.rb +184 -0
  326. data/spec/svg_conform/requirements/no_external_css_requirement_spec.rb +78 -0
  327. data/spec/svg_conform/requirements/no_external_fonts_requirement_spec.rb +20 -0
  328. data/spec/svg_conform/requirements/no_external_images_requirement_spec.rb +20 -0
  329. data/spec/svg_conform/requirements/style_promotion_requirement_spec.rb +78 -0
  330. data/spec/svg_conform/requirements/style_requirement_spec.rb +76 -0
  331. data/spec/svg_conform/requirements/viewbox_required_requirement_spec.rb +165 -0
  332. data/spec/svg_conform_spec.rb +32 -0
  333. data/spec/svgcheck_compatibility_spec.rb +355 -0
  334. data/svg_conform.gemspec +35 -0
  335. metadata +436 -0
@@ -0,0 +1,109 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../external_checkers/svgcheck"
4
+
5
+ module SvgConform
6
+ module Compatibility
7
+ # Handles file system operations and validation for compatibility analysis
8
+ class FileProcessor
9
+ def initialize(context)
10
+ @context = context
11
+ end
12
+
13
+ def validate_environment
14
+ if @context.single_file_analysis?
15
+ validate_single_file
16
+ else
17
+ validate_batch_environment
18
+ end
19
+ end
20
+
21
+ def discover_files
22
+ return [@context.file] if @context.single_file_analysis?
23
+
24
+ discover_batch_files
25
+ end
26
+
27
+ def parse_svgcheck_outputs(filename)
28
+ # Use the new external checker report generator
29
+ report_generator = SvgConform::ExternalCheckers::Svgcheck::ReportGenerator.new
30
+
31
+ output_file = File.join(@context.outputs_dir, "#{filename}.out")
32
+ error_file = File.join(@context.outputs_dir, "#{filename}.err")
33
+ code_file = File.join(@context.outputs_dir, "#{filename}.code")
34
+
35
+ report_generator.generate_from_files(filename,
36
+ output_file: output_file,
37
+ error_file: error_file,
38
+ code_file: code_file)
39
+ end
40
+
41
+ def file_exists?(filename)
42
+ File.exist?(File.join(@context.inputs_dir, filename))
43
+ end
44
+
45
+ def input_file_path(filename)
46
+ File.join(@context.inputs_dir, filename)
47
+ end
48
+
49
+ def xml_file?(filename)
50
+ filename.end_with?(".xml")
51
+ end
52
+
53
+ def svg_file?(filename)
54
+ filename.end_with?(".svg")
55
+ end
56
+
57
+ def read_file_content(filename)
58
+ File.read(input_file_path(filename))
59
+ end
60
+
61
+ def svgcheck_repaired_file_path(filename)
62
+ File.join(@context.outputs_dir, "#{filename}.file")
63
+ end
64
+
65
+ def svgcheck_repaired_file_exists?(filename)
66
+ File.exist?(svgcheck_repaired_file_path(filename))
67
+ end
68
+
69
+ def read_svgcheck_repaired_content(filename)
70
+ File.read(svgcheck_repaired_file_path(filename))
71
+ end
72
+
73
+ private
74
+
75
+ def validate_single_file
76
+ input_file = @context.input_file_path
77
+
78
+ raise "Input file not found: #{input_file}" unless File.exist?(input_file)
79
+
80
+ raise "Svgcheck outputs directory not found: #{@context.outputs_dir}" unless Dir.exist?(@context.outputs_dir)
81
+
82
+ true
83
+ end
84
+
85
+ def validate_batch_environment
86
+ raise "Inputs directory not found: #{@context.inputs_dir}" unless Dir.exist?(@context.inputs_dir)
87
+
88
+ raise "Outputs directory not found: #{@context.outputs_dir}" unless Dir.exist?(@context.outputs_dir)
89
+
90
+ true
91
+ end
92
+
93
+ def discover_batch_files
94
+ all_files = Dir.glob(File.join(@context.inputs_dir, "*")).map do |f|
95
+ File.basename(f)
96
+ end
97
+ svg_files = all_files.select { |f| svg_file?(f) }
98
+
99
+ raise "No SVG files found in #{@context.inputs_dir}" if svg_files.empty?
100
+
101
+ # Report filtered files for user awareness
102
+ non_svg_files = all_files - svg_files
103
+ puts "ℹ️ Skipping #{non_svg_files.length} non-SVG files: #{non_svg_files.join(', ')}" if non_svg_files.any?
104
+
105
+ svg_files
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,319 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "validity_analysis"
4
+
5
+ module SvgConform
6
+ module Compatibility
7
+ # Model for discovered validation patterns
8
+ class DiscoveredPattern < Lutaml::Model::Serializable
9
+ attribute :source_tool, :string
10
+ attribute :message_text, :string
11
+ attribute :pattern_category, :string
12
+ attribute :frequency, :integer
13
+ attribute :files_affected, :string, collection: true
14
+ attribute :suggested_semantic_key, :string
15
+ attribute :confidence_level, :float
16
+
17
+ def initialize(source_tool:, message_text:, pattern_category: "unknown")
18
+ @source_tool = source_tool
19
+ @message_text = message_text
20
+ @pattern_category = pattern_category
21
+ @frequency = 1
22
+ @files_affected = []
23
+ @confidence_level = 0.0
24
+ end
25
+
26
+ def increment_frequency(filename)
27
+ @frequency += 1
28
+ @files_affected << filename unless @files_affected.include?(filename)
29
+ end
30
+
31
+ def suggest_semantic_key(key, confidence)
32
+ @suggested_semantic_key = key
33
+ @confidence_level = confidence
34
+ end
35
+
36
+ def high_confidence?
37
+ @confidence_level >= 0.8
38
+ end
39
+
40
+ def common_pattern?
41
+ @frequency >= 3
42
+ end
43
+ end
44
+
45
+ # Enhanced pattern discovery engine
46
+ class PatternDiscoveryEngine
47
+ attr_reader :discovered_patterns, :unmapped_patterns
48
+
49
+ def initialize
50
+ @discovered_patterns = {}
51
+ @unmapped_patterns = []
52
+ @semantic_comparator = SvgConform::SemanticComparator.new
53
+ end
54
+
55
+ def discover_patterns_from_files(target_files)
56
+ puts "🔍 Discovering validation patterns from #{target_files.length} files..."
57
+
58
+ target_files.each do |filename|
59
+ analyze_file_patterns(filename)
60
+ end
61
+
62
+ categorize_patterns
63
+ suggest_semantic_mappings
64
+ identify_unmapped_patterns
65
+
66
+ generate_discovery_report
67
+ end
68
+
69
+ def analyze_file_patterns(filename)
70
+ puts " 📄 Analyzing patterns in: #{filename}"
71
+
72
+ # Analyze SvgConform patterns
73
+ svg_conform_patterns = extract_svg_conform_patterns(filename)
74
+ svg_conform_patterns.each do |pattern|
75
+ record_pattern("svg_conform", pattern, filename)
76
+ end
77
+
78
+ # Analyze svgcheck patterns
79
+ svgcheck_patterns = extract_svgcheck_patterns(filename)
80
+ svgcheck_patterns.each do |pattern|
81
+ record_pattern("svgcheck", pattern, filename)
82
+ end
83
+ end
84
+
85
+ private
86
+
87
+ def extract_svg_conform_patterns(filename)
88
+ patterns = []
89
+
90
+ begin
91
+ # Run SvgConform validation to get patterns
92
+ file_path = File.join("spec/fixtures/svgcheck/inputs", filename)
93
+ return patterns unless File.exist?(file_path)
94
+
95
+ validator = SvgConform::Validator.new(
96
+ profile: "svg_1_2_rfc",
97
+ )
98
+
99
+ result = validator.validate(file_path)
100
+
101
+ if result.respond_to?(:issues)
102
+ result.issues.each do |issue|
103
+ patterns << normalize_pattern(issue.to_s)
104
+ end
105
+ end
106
+ rescue StandardError => e
107
+ puts " ⚠️ Error extracting SvgConform patterns: #{e.message}"
108
+ end
109
+
110
+ patterns
111
+ end
112
+
113
+ def extract_svgcheck_patterns(filename)
114
+ patterns = []
115
+
116
+ begin
117
+ # Read svgcheck repair output
118
+ repair_file = File.join("spec/fixtures/svgcheck/repair",
119
+ "#{filename}.out")
120
+ return patterns unless File.exist?(repair_file)
121
+
122
+ content = File.read(repair_file)
123
+
124
+ # Extract validation messages using raw parser
125
+ parser = SvgConform::SvgcheckRawParser.new
126
+ parsed_result = parser.parse_content(content)
127
+
128
+ if parsed_result.respond_to?(:messages)
129
+ parsed_result.messages.each do |message|
130
+ patterns << normalize_pattern(message.to_s)
131
+ end
132
+ end
133
+ rescue StandardError => e
134
+ puts " ⚠️ Error extracting svgcheck patterns: #{e.message}"
135
+ end
136
+
137
+ patterns
138
+ end
139
+
140
+ def normalize_pattern(message)
141
+ # Normalize patterns for better matching
142
+ normalized = message.to_s.strip
143
+
144
+ # Remove file-specific details
145
+ normalized = normalized.gsub(/line \d+/i, "line X")
146
+ normalized = normalized.gsub(/column \d+/i, "column X")
147
+ normalized = normalized.gsub(/"[^"]*"/, '"VALUE"')
148
+ normalized = normalized.gsub(/'[^']*'/, "'VALUE'")
149
+
150
+ # Normalize common variations
151
+ normalized = normalized.gsub(/\s+/, " ")
152
+ normalized.downcase
153
+ end
154
+
155
+ def record_pattern(source_tool, pattern_text, filename)
156
+ key = "#{source_tool}:#{pattern_text}"
157
+
158
+ if @discovered_patterns[key]
159
+ @discovered_patterns[key].increment_frequency(filename)
160
+ else
161
+ pattern = DiscoveredPattern.new(
162
+ source_tool: source_tool,
163
+ message_text: pattern_text,
164
+ pattern_category: categorize_pattern(pattern_text),
165
+ )
166
+ pattern.increment_frequency(filename)
167
+ @discovered_patterns[key] = pattern
168
+ end
169
+ end
170
+
171
+ def categorize_pattern(pattern_text)
172
+ case pattern_text
173
+ when /namespace/i
174
+ "namespace_validation"
175
+ when /viewbox/i
176
+ "viewbox_validation"
177
+ when /font/i
178
+ "font_validation"
179
+ when /color/i
180
+ "color_validation"
181
+ when /attribute/i
182
+ "attribute_validation"
183
+ when /element/i
184
+ "element_validation"
185
+ when /style/i
186
+ "style_validation"
187
+ else
188
+ "unknown_validation"
189
+ end
190
+ end
191
+
192
+ def categorize_patterns
193
+ @discovered_patterns.each_value do |pattern|
194
+ pattern.pattern_category = categorize_pattern(pattern.message_text) if pattern.pattern_category == "unknown_validation"
195
+ end
196
+ end
197
+
198
+ def suggest_semantic_mappings
199
+ @discovered_patterns.each_value do |pattern|
200
+ semantic_key = find_semantic_mapping(pattern)
201
+ if semantic_key
202
+ confidence = calculate_semantic_confidence(pattern, semantic_key)
203
+ pattern.suggest_semantic_key(semantic_key, confidence)
204
+ end
205
+ end
206
+ end
207
+
208
+ def find_semantic_mapping(pattern)
209
+ # Use existing semantic comparator to find mappings
210
+ existing_mappings = @semantic_comparator.instance_variable_get(:@semantic_mappings)
211
+
212
+ # Try to find existing mapping
213
+ existing_mappings.each do |key, variations|
214
+ variations.each do |variation|
215
+ return key if pattern_matches_variation?(pattern.message_text,
216
+ variation)
217
+ end
218
+ end
219
+
220
+ # Generate new semantic key suggestion
221
+ generate_semantic_key_suggestion(pattern)
222
+ end
223
+
224
+ def pattern_matches_variation?(pattern_text, variation)
225
+ # Simple similarity check
226
+ normalized_pattern = normalize_pattern(pattern_text)
227
+ normalized_variation = normalize_pattern(variation)
228
+
229
+ # Check for substring match or similar keywords
230
+ normalized_pattern.include?(normalized_variation) ||
231
+ normalized_variation.include?(normalized_pattern) ||
232
+ share_keywords?(normalized_pattern, normalized_variation)
233
+ end
234
+
235
+ def share_keywords?(text1, text2)
236
+ keywords1 = extract_keywords(text1)
237
+ keywords2 = extract_keywords(text2)
238
+
239
+ common_keywords = keywords1 & keywords2
240
+ common_keywords.length >= 2
241
+ end
242
+
243
+ def extract_keywords(text)
244
+ # Extract meaningful keywords
245
+ words = text.split(/\s+/)
246
+ words.select do |word|
247
+ word.length > 3 &&
248
+ !%w[the and or but with from that this].include?(word)
249
+ end
250
+ end
251
+
252
+ def generate_semantic_key_suggestion(pattern)
253
+ # Generate semantic key based on pattern category and content
254
+ category = pattern.pattern_category.gsub("_validation", "")
255
+
256
+ keywords = extract_keywords(pattern.message_text)
257
+ key_suffix = keywords.first(2).join("_")
258
+
259
+ "#{category}_#{key_suffix}".downcase
260
+ end
261
+
262
+ def calculate_semantic_confidence(pattern, semantic_key)
263
+ confidence = 0.5 # Base confidence
264
+
265
+ # Increase confidence for common patterns
266
+ confidence += 0.2 if pattern.common_pattern?
267
+
268
+ # Increase confidence for well-categorized patterns
269
+ confidence += 0.2 if pattern.pattern_category != "unknown_validation"
270
+
271
+ # Increase confidence for existing mappings
272
+ confidence += 0.3 if semantic_key_exists?(semantic_key)
273
+
274
+ [confidence, 1.0].min
275
+ end
276
+
277
+ def semantic_key_exists?(semantic_key)
278
+ existing_mappings = @semantic_comparator.instance_variable_get(:@semantic_mappings)
279
+ existing_mappings.key?(semantic_key)
280
+ end
281
+
282
+ def identify_unmapped_patterns
283
+ @unmapped_patterns = @discovered_patterns.values.select do |pattern|
284
+ pattern.suggested_semantic_key.nil? ||
285
+ pattern.confidence_level < 0.6
286
+ end
287
+ end
288
+
289
+ def generate_discovery_report
290
+ puts
291
+ puts "=== Pattern Discovery Report ==="
292
+ puts "Total patterns discovered: #{@discovered_patterns.length}"
293
+ puts "Unmapped patterns: #{@unmapped_patterns.length}"
294
+ puts
295
+
296
+ puts "🔍 High-confidence new mappings:"
297
+ high_confidence_new = @discovered_patterns.values.select do |pattern|
298
+ pattern.high_confidence? &&
299
+ !semantic_key_exists?(pattern.suggested_semantic_key)
300
+ end
301
+
302
+ high_confidence_new.each do |pattern|
303
+ puts " #{pattern.suggested_semantic_key}: #{pattern.message_text}"
304
+ puts " Confidence: #{(pattern.confidence_level * 100).round(1)}%"
305
+ puts " Frequency: #{pattern.frequency} files"
306
+ puts
307
+ end
308
+
309
+ puts "❓ Unmapped patterns requiring investigation:"
310
+ @unmapped_patterns.each do |pattern|
311
+ puts " [#{pattern.source_tool}] #{pattern.message_text}"
312
+ puts " Category: #{pattern.pattern_category}"
313
+ puts " Frequency: #{pattern.frequency} files"
314
+ puts
315
+ end
316
+ end
317
+ end
318
+ end
319
+ end