apex-ruby 1.0.17 → 1.0.20

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 (207) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +17 -3
  3. data/ext/apex_ext/apex_ext.c +260 -91
  4. data/ext/apex_ext/apex_src/CHANGELOG.md +440 -0
  5. data/ext/apex_ext/apex_src/CMakeLists.txt +15 -1
  6. data/ext/apex_ext/apex_src/Formula/apex.rb +7 -2
  7. data/ext/apex_ext/apex_src/Package.swift +15 -4
  8. data/ext/apex_ext/apex_src/README.md +94 -35
  9. data/ext/apex_ext/apex_src/VERSION +1 -1
  10. data/ext/apex_ext/apex_src/apex-debug.log +4 -0
  11. data/ext/apex_ext/apex_src/apex.code-workspace +38 -0
  12. data/ext/apex_ext/apex_src/apex.taskpaper +12 -0
  13. data/ext/apex_ext/apex_src/apex_deflist_debug.log +25 -0
  14. data/ext/apex_ext/apex_src/buildnotes.md +1435 -0
  15. data/ext/apex_ext/apex_src/cli/main.c +262 -33
  16. data/ext/apex_ext/apex_src/debug.log +7 -0
  17. data/ext/apex_ext/apex_src/docs/CITATIONS_EXAMPLES.md +274 -0
  18. data/ext/apex_ext/apex_src/docs/CITATIONS_IMPLEMENTATION_PLAN.md +749 -0
  19. data/ext/apex_ext/apex_src/docs/CITATIONS_PLAN.md +744 -0
  20. data/ext/apex_ext/apex_src/docs/INDEX_IMPLEMENTATION_ANALYSIS.md +382 -0
  21. data/ext/apex_ext/apex_src/docs/plans/2025-02-27-man-page-output-implementation.md +351 -0
  22. data/ext/apex_ext/apex_src/docs/superpowers/plans/2026-07-12-toc-output-format.md +745 -0
  23. data/ext/apex_ext/apex_src/docs/superpowers/plans/2026-07-18-bear-image-attributes.md +829 -0
  24. data/ext/apex_ext/apex_src/docs/superpowers/plans/2026-07-19-apex-node-npm.md +1148 -0
  25. data/ext/apex_ext/apex_src/docs/superpowers/specs/2026-07-12-toc-output-format-design.md +161 -0
  26. data/ext/apex_ext/apex_src/docs/superpowers/specs/2026-07-18-bear-image-attributes-design.md +184 -0
  27. data/ext/apex_ext/apex_src/docs/superpowers/specs/2026-07-19-apex-node-npm-design.md +211 -0
  28. data/ext/apex_ext/apex_src/documentation/app-settings-table.md +67 -0
  29. data/ext/apex_ext/apex_src/documentation/app-transformed/Citations.md +340 -0
  30. data/ext/apex_ext/apex_src/documentation/app-transformed/Credits.md +11 -0
  31. data/ext/apex_ext/apex_src/documentation/app-transformed/Header-IDs.md +234 -0
  32. data/ext/apex_ext/apex_src/documentation/app-transformed/Inline-Attribute-Lists.md +516 -0
  33. data/ext/apex_ext/apex_src/documentation/app-transformed/Metadata-Transforms.md +461 -0
  34. data/ext/apex_ext/apex_src/documentation/app-transformed/Modes.md +193 -0
  35. data/ext/apex_ext/apex_src/documentation/app-transformed/Multi-File-Documents.md +201 -0
  36. data/ext/apex_ext/apex_src/documentation/app-transformed/Plugins.md +678 -0
  37. data/ext/apex_ext/apex_src/documentation/app-transformed/Syntax.md +1367 -0
  38. data/ext/apex_ext/apex_src/documentation/docsets/Apex Command Line Options.cheatsheet.txt +6 -0
  39. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/C-API.html +774 -300
  40. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Callouts.html +1194 -0
  41. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Citations.html +416 -216
  42. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Command-Line-Options.html +3544 -1094
  43. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Configuration.html +371 -97
  44. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Credits.html +153 -23
  45. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Examples.html +358 -124
  46. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Filters.html +1656 -0
  47. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Generating-Man-Pages.html +1226 -0
  48. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Getting-Started.html +201 -56
  49. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Header-IDs.html +279 -109
  50. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Home.html +200 -53
  51. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Indices.html +2327 -0
  52. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Inline-Attribute-Lists.html +690 -271
  53. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Installation.html +201 -55
  54. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Limitations-and-Roadmap.html +238 -68
  55. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Metadata-Transforms.html +421 -221
  56. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Modes.html +340 -78
  57. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Multi-File-Documents.html +251 -86
  58. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Multi-Format-Images.html +1362 -0
  59. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Pandoc-Integration.html +277 -90
  60. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Plugins.html +673 -346
  61. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Quarto-Mode.html +1405 -0
  62. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Rendering-Markdown-In-Terminal.html +1902 -0
  63. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Syntax.html +1939 -1698
  64. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Tables.html +1781 -0
  65. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Troubleshooting.html +315 -140
  66. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Usage.html +307 -113
  67. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Using-Apex-with-Jekyll.html +1132 -0
  68. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Writing-Tests.html +1754 -0
  69. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Xcode-Integration.html +872 -376
  70. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/docSet.dsidx +0 -0
  71. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/optimizedIndex.dsidx +0 -0
  72. data/ext/apex_ext/apex_src/documentation/html/apex-app-docs.html +8746 -0
  73. data/ext/apex_ext/apex_src/documentation/shared_styles.css +20 -15
  74. data/ext/apex_ext/apex_src/documentation/transform_for_app.md +55 -0
  75. data/ext/apex_ext/apex_src/escaping-repro.md +103 -0
  76. data/ext/apex_ext/apex_src/examples/quick-actions/Markdown to RTF.workflow/Contents/Info.plist +8 -0
  77. data/ext/apex_ext/apex_src/examples/quick-actions/Markdown to RTF.workflow/Contents/QuickLook/Preview.png +0 -0
  78. data/ext/apex_ext/apex_src/examples/quick-actions/Markdown to RTF.workflow/Contents/document.wflow +547 -0
  79. data/ext/apex_ext/apex_src/examples/quick-actions/Markdown-to-RTF.workflow.zip +0 -0
  80. data/ext/apex_ext/apex_src/examples/quick-actions/README.md +33 -0
  81. data/ext/apex_ext/apex_src/include/apex/apex.h +92 -6
  82. data/ext/apex_ext/apex_src/include/apex/ast_rtf.h +23 -0
  83. data/ext/apex_ext/apex_src/include/apex/ast_terminal.h +6 -0
  84. data/ext/apex_ext/apex_src/include/apex/module.modulemap +5 -0
  85. data/ext/apex_ext/apex_src/include/apex/plugins.h +105 -0
  86. data/ext/apex_ext/apex_src/include/apexc.h +1 -0
  87. data/ext/apex_ext/apex_src/man/apex.1 +82 -78
  88. data/ext/apex_ext/apex_src/man/apex.1.md +81 -4
  89. data/ext/apex_ext/apex_src/objc/Apex.swift +73 -0
  90. data/ext/apex_ext/apex_src/objc/ApexPlugins.swift +79 -0
  91. data/ext/apex_ext/apex_src/objc/NSString+Apex.h +83 -5
  92. data/ext/apex_ext/apex_src/objc/NSString+Apex.m +244 -1
  93. data/ext/apex_ext/apex_src/objc/NSString+ApexPlugins.h +76 -0
  94. data/ext/apex_ext/apex_src/objc/NSString+ApexPlugins.m +169 -0
  95. data/ext/apex_ext/apex_src/output.html +87 -0
  96. data/ext/apex_ext/apex_src/plans/quarto-mode.md +442 -0
  97. data/ext/apex_ext/apex_src/src/_README.md +85 -32
  98. data/ext/apex_ext/apex_src/src/apex.c +770 -200
  99. data/ext/apex_ext/apex_src/src/ast_rtf.c +848 -0
  100. data/ext/apex_ext/apex_src/src/ast_terminal.c +184 -7
  101. data/ext/apex_ext/apex_src/src/extensions/abbreviations.c +10 -3
  102. data/ext/apex_ext/apex_src/src/extensions/advanced_tables.c +7 -11
  103. data/ext/apex_ext/apex_src/src/extensions/bear_image_attrs.c +467 -0
  104. data/ext/apex_ext/apex_src/src/extensions/bear_image_attrs.h +27 -0
  105. data/ext/apex_ext/apex_src/src/extensions/callouts.c +400 -4
  106. data/ext/apex_ext/apex_src/src/extensions/callouts.h +15 -5
  107. data/ext/apex_ext/apex_src/src/extensions/citations.c +26 -5
  108. data/ext/apex_ext/apex_src/src/extensions/code_fence_attrs.c +632 -0
  109. data/ext/apex_ext/apex_src/src/extensions/code_fence_attrs.h +22 -0
  110. data/ext/apex_ext/apex_src/src/extensions/concordance.c +632 -0
  111. data/ext/apex_ext/apex_src/src/extensions/definition_list.c +129 -15
  112. data/ext/apex_ext/apex_src/src/extensions/grid_tables.c +1050 -121
  113. data/ext/apex_ext/apex_src/src/extensions/html_markdown.c +569 -16
  114. data/ext/apex_ext/apex_src/src/extensions/ial.c +502 -52
  115. data/ext/apex_ext/apex_src/src/extensions/ial.h +2 -1
  116. data/ext/apex_ext/apex_src/src/extensions/includes.c +532 -33
  117. data/ext/apex_ext/apex_src/src/extensions/includes.h +7 -1
  118. data/ext/apex_ext/apex_src/src/extensions/index.c +1427 -140
  119. data/ext/apex_ext/apex_src/src/extensions/index.h +28 -0
  120. data/ext/apex_ext/apex_src/src/extensions/metadata.c +200 -161
  121. data/ext/apex_ext/apex_src/src/extensions/quarto_diagrams.c +251 -0
  122. data/ext/apex_ext/apex_src/src/extensions/quarto_diagrams.h +22 -0
  123. data/ext/apex_ext/apex_src/src/extensions/quarto_lists.c +624 -0
  124. data/ext/apex_ext/apex_src/src/extensions/quarto_lists.h +35 -0
  125. data/ext/apex_ext/apex_src/src/extensions/quarto_polish.c +264 -0
  126. data/ext/apex_ext/apex_src/src/extensions/quarto_polish.h +23 -0
  127. data/ext/apex_ext/apex_src/src/extensions/quarto_shortcodes.c +307 -0
  128. data/ext/apex_ext/apex_src/src/extensions/quarto_shortcodes.h +21 -0
  129. data/ext/apex_ext/apex_src/src/extensions/raw_content.c +351 -0
  130. data/ext/apex_ext/apex_src/src/extensions/raw_content.h +20 -0
  131. data/ext/apex_ext/apex_src/src/extensions/relaxed_tables.c +117 -3
  132. data/ext/apex_ext/apex_src/src/extensions/special_markers.c +53 -0
  133. data/ext/apex_ext/apex_src/src/extensions/syntax_highlight.c +23 -1
  134. data/ext/apex_ext/apex_src/src/extensions/table_html_postprocess.c +83 -92
  135. data/ext/apex_ext/apex_src/src/extensions/toc.c +446 -25
  136. data/ext/apex_ext/apex_src/src/extensions/toc.h +26 -1
  137. data/ext/apex_ext/apex_src/src/extensions/wiki_links.c +28 -0
  138. data/ext/apex_ext/apex_src/src/html_renderer.c +387 -17
  139. data/ext/apex_ext/apex_src/src/plugin_catalog.c +517 -0
  140. data/ext/apex_ext/apex_src/src/plugins_remote.c +88 -14
  141. data/ext/apex_ext/apex_src/src/plugins_remote.h +34 -0
  142. data/ext/apex_ext/apex_src/src/pretty_html.c +6 -1
  143. data/ext/apex_ext/apex_src/tests/fixtures/comprehensive_test.md +21 -0
  144. data/ext/apex_ext/apex_src/tests/fixtures/images/bear_image_attributes.md +10 -0
  145. data/ext/apex_ext/apex_src/tests/fixtures/includes/sections.md +19 -0
  146. data/ext/apex_ext/apex_src/tests/fixtures/includes/sections.txt +11 -0
  147. data/ext/apex_ext/apex_src/tests/fixtures/minimal_pb.md +2 -0
  148. data/ext/apex_ext/apex_src/tests/fixtures/obsidian-callouts.md +46 -0
  149. data/ext/apex_ext/apex_src/tests/fixtures/pagebreak_html_repro.md +5 -0
  150. data/ext/apex_ext/apex_src/tests/fixtures/python-callouts.md +47 -0
  151. data/ext/apex_ext/apex_src/tests/fixtures/quarto/callouts.md +3 -0
  152. data/ext/apex_ext/apex_src/tests/fixtures/quarto/code-attrs.md +3 -0
  153. data/ext/apex_ext/apex_src/tests/fixtures/quarto/diagrams.md +8 -0
  154. data/ext/apex_ext/apex_src/tests/fixtures/quarto/lists.md +19 -0
  155. data/ext/apex_ext/apex_src/tests/fixtures/quarto/raw-content.md +5 -0
  156. data/ext/apex_ext/apex_src/tests/fixtures/quarto/shortcodes.md +7 -0
  157. data/ext/apex_ext/apex_src/tests/fixtures/quarto/smoke.md +81 -0
  158. data/ext/apex_ext/apex_src/tests/fixtures/quarto/spans.md +5 -0
  159. data/ext/apex_ext/apex_src/tests/fixtures/quarto-callouts.md +47 -0
  160. data/ext/apex_ext/apex_src/tests/fixtures/speed.md +192 -0
  161. data/ext/apex_ext/apex_src/tests/fixtures/tables/grid-tables.md +37 -0
  162. data/ext/apex_ext/apex_src/tests/paginate_cli_test.sh +16 -0
  163. data/ext/apex_ext/apex_src/tests/test_bear_image_attrs.c +301 -0
  164. data/ext/apex_ext/apex_src/tests/test_concordance.tsv +4 -0
  165. data/ext/apex_ext/apex_src/tests/test_escaping_repro.c +82 -0
  166. data/ext/apex_ext/apex_src/tests/test_extensions.c +821 -1
  167. data/ext/apex_ext/apex_src/tests/test_ial.c +7 -0
  168. data/ext/apex_ext/apex_src/tests/test_marked_integration.c +25 -0
  169. data/ext/apex_ext/apex_src/tests/test_metadata.c +129 -0
  170. data/ext/apex_ext/apex_src/tests/test_output.c +568 -2
  171. data/ext/apex_ext/apex_src/tests/test_runner.c +11 -0
  172. data/ext/apex_ext/apex_src/tests/test_tables.c +420 -0
  173. data/ext/apex_ext/apex_src/vendor/cmark-gfm/CMakeLists.txt +1 -1
  174. data/ext/apex_ext/apex_src/vendor/cmark-gfm/extensions/autolink.c +77 -1
  175. data/ext/apex_ext/apex_src/vendor/cmark-gfm/extensions/table.c +135 -5
  176. data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/blocks.c +56 -1
  177. data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/config.h +38 -0
  178. data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/main.c +1 -1
  179. data/ext/apex_ext/apex_src/vendor/cmark-gfm/test/__pycache__/cmark.cpython-314.pyc +0 -0
  180. data/ext/apex_ext/apex_src/vendor/cmark-gfm/test/__pycache__/normalize.cpython-314.pyc +0 -0
  181. data/ext/apex_ext/apex_src/vendor/cmark-gfm/test/extensions.txt +69 -0
  182. data/ext/apex_ext/apex_src/xcode_build/CMakeScripts/ReRunCMake.make +74 -0
  183. data/ext/apex_ext/apex_src/xcode_build/CTestTestfile.cmake +22 -0
  184. data/ext/apex_ext/apex_src/xcode_build/Debug/Apex.framework/Versions/A/Apex +0 -0
  185. data/ext/apex_ext/apex_src/xcode_build/Debug/Apex.framework/Versions/A/Resources/Info.plist +44 -0
  186. data/ext/apex_ext/apex_src/xcode_build/Debug/Apex.framework/Versions/A/_CodeSignature/CodeResources +128 -0
  187. data/ext/apex_ext/apex_src/xcode_build/apex.xcodeproj/project.pbxproj +5118 -0
  188. data/ext/apex_ext/apex_src/xcode_build/apex.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +8 -0
  189. data/ext/apex_ext/apex_src/xcode_build/apex.xcodeproj/project.xcworkspace/xcuserdata/ttscoff.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  190. data/ext/apex_ext/apex_src/xcode_build/apex.xcodeproj/project.xcworkspace/xcuserdata/ttscoff.xcuserdatad/WorkspaceSettings.xcsettings +8 -0
  191. data/ext/apex_ext/apex_src/xcode_build/apex.xcodeproj/xcuserdata/ttscoff.xcuserdatad/xcschemes/xcschememanagement.plist +99 -0
  192. data/ext/apex_ext/apex_src/xcode_build/cmake_install.cmake +452 -0
  193. data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/CMakeScripts/ReRunCMake.make +52 -0
  194. data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/cmake_install.cmake +55 -0
  195. data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/cmark-gfm.xcodeproj/project.pbxproj +2455 -0
  196. data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/cmark-gfm.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +8 -0
  197. data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/extensions/cmake_install.cmake +171 -0
  198. data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/man/cmake_install.cmake +55 -0
  199. data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/src/cmake_install.cmake +220 -0
  200. data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/src/cmark-gfm_export.h +43 -0
  201. data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/src/cmark-gfm_version.h +7 -0
  202. data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/src/config.h +76 -0
  203. data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/src/libcmark-gfm.pc +10 -0
  204. data/ext/apex_ext/extconf.rb +35 -0
  205. data/lib/apex/version.rb +2 -2
  206. metadata +117 -2
  207. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/tempOptimizedIndex.dsidx +0 -0
@@ -0,0 +1,301 @@
1
+ #include "test_helpers.h"
2
+ #include "apex/apex.h"
3
+ #include "extensions/bear_image_attrs.h"
4
+
5
+ #include <string.h>
6
+
7
+ static const char *bear_value(const apex_bear_image_attrs *attrs,
8
+ const char *key) {
9
+ for (size_t i = 0; i < attrs->count; i++) {
10
+ if (strcmp(attrs->items[i].key, key) == 0) {
11
+ return attrs->items[i].value;
12
+ }
13
+ }
14
+ return NULL;
15
+ }
16
+
17
+ static char *render_bear(
18
+ const char *markdown, apex_mode_t mode, bool unsafe) {
19
+ apex_options opts = apex_options_for_mode(mode);
20
+ opts.unsafe = unsafe;
21
+ return apex_markdown_to_html(markdown, strlen(markdown), &opts);
22
+ }
23
+
24
+ static void test_bear_inline_modes(void) {
25
+ const char *md =
26
+ "![](emperor-1.jpg)<!-- {\"width\":259} -->";
27
+ const apex_mode_t modes[] = {
28
+ APEX_MODE_COMMONMARK,
29
+ APEX_MODE_GFM,
30
+ APEX_MODE_MULTIMARKDOWN,
31
+ APEX_MODE_UNIFIED
32
+ };
33
+
34
+ for (size_t i = 0; i < sizeof(modes) / sizeof(modes[0]); i++) {
35
+ char *html = render_bear(md, modes[i], true);
36
+ assert_contains(html, "width=\"259\"", "Bear width is applied");
37
+ assert_contains(
38
+ html,
39
+ "<!-- {\"width\":259} -->",
40
+ "Bear comment is preserved");
41
+ apex_free_string(html);
42
+ }
43
+
44
+ char *safe = render_bear(md, APEX_MODE_COMMONMARK, false);
45
+ assert_contains(safe, "width=\"259\"", "Safe mode applies Bear width");
46
+ assert_contains(
47
+ safe, "raw HTML omitted", "Safe mode keeps raw HTML policy");
48
+ apex_free_string(safe);
49
+
50
+ char *spaced = render_bear(
51
+ "![](x.jpg) \t<!-- {\"width\":\"50%\",\"height\":\"20px\"} -->",
52
+ APEX_MODE_UNIFIED,
53
+ true);
54
+ assert_contains(
55
+ spaced, "height=\"20\"", "Pixel height uses an HTML attribute");
56
+ assert_contains(
57
+ spaced, "style=\"width: 50%\"", "Percent width uses style");
58
+ apex_free_string(spaced);
59
+
60
+ char *escaped = render_bear(
61
+ "![](x.jpg)<!-- {\"title\":\"x\\\" onerror=\\\"boom\"} -->",
62
+ APEX_MODE_UNIFIED,
63
+ true);
64
+ assert_contains(
65
+ escaped,
66
+ "title=\"x&quot; onerror=&quot;boom\"",
67
+ "Bear values are HTML attribute escaped");
68
+ assert_not_contains(
69
+ escaped, " onerror=\"boom\"", "Bear values cannot inject attributes");
70
+ apex_free_string(escaped);
71
+
72
+ char *kramdown = render_bear(
73
+ "![](x.jpg)<!-- {\"width\":259} -->", APEX_MODE_KRAMDOWN, true);
74
+ assert_not_contains(
75
+ kramdown,
76
+ "width=\"259\"",
77
+ "Kramdown does not apply Bear metadata");
78
+ apex_free_string(kramdown);
79
+ }
80
+
81
+ static void test_bear_reference_definitions(void) {
82
+ const char *md =
83
+ "![One][Emperor]\n\n"
84
+ "![Emperor][]\n\n"
85
+ "![Emperor]\n\n"
86
+ "[ emperor ]: emperor.jpg "
87
+ "<!-- {\"width\":259,\"title\":\"Ruler\"} -->";
88
+ char *html = render_bear(md, APEX_MODE_UNIFIED, true);
89
+
90
+ const char *cursor = html;
91
+ int widths = 0;
92
+ while ((cursor = strstr(cursor, "width=\"259\"")) != NULL) {
93
+ widths++;
94
+ cursor += strlen("width=\"259\"");
95
+ }
96
+ test_result(widths == 3, "Definition metadata applies to every use");
97
+ assert_contains(
98
+ html,
99
+ "<!-- {\"width\":259,\"title\":\"Ruler\"} -->",
100
+ "Definition comment is preserved once");
101
+
102
+ cursor = html;
103
+ int comments = 0;
104
+ while ((cursor = strstr(cursor, "<!-- {\"width\":259")) != NULL) {
105
+ comments++;
106
+ cursor++;
107
+ }
108
+ test_result(comments == 1, "Definition comment renders exactly once");
109
+ apex_free_string(html);
110
+
111
+ html = render_bear(
112
+ "![Crown][EMPEROR OF ROME]\n\n"
113
+ "[ emperor of rome ]: emperor.jpg "
114
+ "<!-- {\"height\":100} -->",
115
+ APEX_MODE_UNIFIED,
116
+ true);
117
+ assert_contains(
118
+ html,
119
+ "height=\"100\"",
120
+ "Reference matching normalizes case and internal whitespace");
121
+ apex_free_string(html);
122
+
123
+ html = render_bear(
124
+ "![Use][ref]\n\n"
125
+ "[ref]: pic.jpg junk <!-- {\"width\":259} -->",
126
+ APEX_MODE_UNIFIED,
127
+ true);
128
+ assert_not_contains(
129
+ html,
130
+ "width=\"259\"",
131
+ "Non-adjacent definition comment does not apply metadata");
132
+ apex_free_string(html);
133
+
134
+ html = render_bear(
135
+ "![Use][ref]\n\n"
136
+ "[ref]: pic.jpg <!-- {\"width\":259} -->\n"
137
+ "After paragraph.",
138
+ APEX_MODE_UNIFIED,
139
+ true);
140
+ assert_contains(
141
+ html, "width=\"259\"", "Definition before text applies metadata");
142
+ assert_contains(
143
+ html,
144
+ "<p>After paragraph.</p>",
145
+ "Removed definition keeps its line ending");
146
+ apex_free_string(html);
147
+
148
+ html = render_bear(
149
+ "![Use][ref]\n\n"
150
+ "[ref]: pic.jpg \"MD Title\" "
151
+ "<!-- {\"title\":\"Bear Title\",\"width\":120} -->",
152
+ APEX_MODE_UNIFIED,
153
+ true);
154
+ assert_contains(
155
+ html,
156
+ "title=\"Bear Title\"",
157
+ "Bear title overrides the definition title");
158
+ assert_not_contains(
159
+ html,
160
+ "title=\"MD Title\"",
161
+ "Definition title does not shadow the Bear title");
162
+ apex_free_string(html);
163
+ }
164
+
165
+ static void test_bear_reference_overrides(void) {
166
+ const char *md =
167
+ "![Default][shared]\n\n"
168
+ "![Wide][shared]<!-- {\"width\":320,\"title\":\"Wide\"} -->\n\n"
169
+ "![Default again][shared]\n\n"
170
+ "[shared]: shared.jpg <!-- {\"width\":200,\"height\":100} -->";
171
+ char *html = render_bear(md, APEX_MODE_UNIFIED, true);
172
+
173
+ const char *cursor = html;
174
+ int defaults = 0;
175
+ while ((cursor = strstr(cursor, "width=\"200\"")) != NULL) {
176
+ defaults++;
177
+ cursor += strlen("width=\"200\"");
178
+ }
179
+ test_result(defaults == 2, "Sibling references retain definition width");
180
+ test_result(
181
+ strstr(html, "width=\"320\"") != NULL,
182
+ "Per-use metadata overrides the definition width");
183
+ assert_contains(
184
+ html, "title=\"Wide\"", "Per-use title is applied");
185
+
186
+ cursor = html;
187
+ int inherited_heights = 0;
188
+ while ((cursor = strstr(cursor, "height=\"100\"")) != NULL) {
189
+ inherited_heights++;
190
+ cursor += strlen("height=\"100\"");
191
+ }
192
+ test_result(
193
+ inherited_heights == 3,
194
+ "Per-use metadata inherits the definition height");
195
+
196
+ assert_contains(
197
+ html,
198
+ "<!-- {\"width\":320,\"title\":\"Wide\"} -->",
199
+ "Per-use comment is preserved");
200
+ apex_free_string(html);
201
+
202
+ char *unresolved = render_bear(
203
+ "![Missing][none]<!-- {\"width\":999} -->",
204
+ APEX_MODE_UNIFIED,
205
+ true);
206
+ assert_not_contains(
207
+ unresolved, "<img", "Unresolved reference remains unresolved");
208
+ assert_contains(
209
+ unresolved,
210
+ "<!-- {\"width\":999} -->",
211
+ "Unresolved metadata comment is preserved");
212
+ apex_free_string(unresolved);
213
+ }
214
+
215
+ void test_bear_image_attributes(void) {
216
+ int failures = suite_start();
217
+ print_suite_title("Bear Image Attribute Tests", false, true);
218
+
219
+ const char *input = "<!-- {\"width\":259,\"title\":\"A & B\"} -->";
220
+ const char *end = input + strlen(input);
221
+ const char *comment_end = NULL;
222
+ apex_bear_image_attrs attrs = {0};
223
+
224
+ bool ok = apex_parse_bear_image_comment(
225
+ input, end, &comment_end, &attrs);
226
+ test_result(ok, "Bear parser accepts a flat JSON object");
227
+ assert_option_string(
228
+ bear_value(&attrs, "width"), "259", "Numeric width is normalized");
229
+ assert_option_string(
230
+ bear_value(&attrs, "title"), "A & B", "String value is decoded");
231
+ test_result(comment_end == end, "Parser returns the comment end");
232
+ apex_free_bear_image_attrs(&attrs);
233
+
234
+ const char *unsafe =
235
+ "<!-- {\"width\":259,\"onclick\":\"alert(1)\","
236
+ "\"data-x\":\"bad\"} -->";
237
+ end = unsafe + strlen(unsafe);
238
+ attrs = (apex_bear_image_attrs){0};
239
+ ok = apex_parse_bear_image_comment(
240
+ unsafe, end, &comment_end, &attrs);
241
+ test_result(ok, "Unsupported keys do not invalidate metadata");
242
+ test_result(
243
+ attrs.count == 1, "Only allowlisted attributes are returned");
244
+ apex_free_bear_image_attrs(&attrs);
245
+
246
+ const char *nested =
247
+ "<!-- {\"width\":259,\"title\":{\"nested\":true}} -->";
248
+ end = nested + strlen(nested);
249
+ attrs = (apex_bear_image_attrs){0};
250
+ ok = apex_parse_bear_image_comment(
251
+ nested, end, &comment_end, &attrs);
252
+ test_result(ok, "Unsupported nested values are skipped");
253
+ test_result(attrs.count == 1, "Supported sibling value is retained");
254
+ apex_free_bear_image_attrs(&attrs);
255
+
256
+ const char *bad = "<!-- {\"width\":259,} -->";
257
+ end = bad + strlen(bad);
258
+ attrs = (apex_bear_image_attrs){0};
259
+ test_result(
260
+ !apex_parse_bear_image_comment(
261
+ bad, end, &comment_end, &attrs),
262
+ "Malformed JSON is rejected");
263
+
264
+ /* Reusing a populated result for a failing parse must clean it. */
265
+ const char *reused = "<!-- {\"width\":259,\"title\":\"A\"} -->";
266
+ end = reused + strlen(reused);
267
+ attrs = (apex_bear_image_attrs){0};
268
+ ok = apex_parse_bear_image_comment(
269
+ reused, end, &comment_end, &attrs);
270
+ test_result(ok && attrs.count == 2, "Reused struct starts populated");
271
+
272
+ const char *too_short = "<!-- x";
273
+ end = too_short + strlen(too_short);
274
+ ok = apex_parse_bear_image_comment(
275
+ too_short, end, &comment_end, &attrs);
276
+ test_result(!ok, "Too-short comment fails on a reused struct");
277
+ test_result(
278
+ attrs.count == 0, "Early failure leaves the reused struct empty");
279
+
280
+ attrs = (apex_bear_image_attrs){0};
281
+ ok = apex_parse_bear_image_comment(
282
+ reused, end = reused + strlen(reused), &comment_end, &attrs);
283
+ test_result(ok && attrs.count == 2, "Struct repopulated for reuse");
284
+
285
+ const char *unterminated = "<!-- {\"width\":259}";
286
+ end = unterminated + strlen(unterminated);
287
+ ok = apex_parse_bear_image_comment(
288
+ unterminated, end, &comment_end, &attrs);
289
+ test_result(!ok, "Unterminated comment fails on a reused struct");
290
+ test_result(
291
+ attrs.count == 0,
292
+ "Missing terminator leaves the reused struct empty");
293
+ apex_free_bear_image_attrs(&attrs);
294
+
295
+ test_bear_inline_modes();
296
+ test_bear_reference_definitions();
297
+ test_bear_reference_overrides();
298
+
299
+ bool had_failures = suite_end(failures);
300
+ print_suite_title("Bear Image Attribute Tests", had_failures, false);
301
+ }
@@ -0,0 +1,4 @@
1
+ # Test concordance for Apex TextIndex support
2
+ widget gadget
3
+ =MacBook "Apple laptop"
4
+ config(uration)?s?\b |firmware
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Regression tests from escaping-repro.md (CommonMark escapes, false ![, U+2033).
3
+ */
4
+
5
+ #include "test_helpers.h"
6
+ #include "apex/apex.h"
7
+ #include <stdio.h>
8
+ #include <string.h>
9
+
10
+ /* U+2033 DOUBLE PRIME in UTF-8 */
11
+ #define UTF8_DOUBLE_PRIME "\xe2\x80\xb3"
12
+
13
+ void test_escaping_repro(void) {
14
+ int suite_failures = suite_start();
15
+ print_suite_title("Escaping & Unicode repro (escaping-repro.md)", false, true);
16
+
17
+ apex_options opts = apex_options_for_mode(APEX_MODE_UNIFIED);
18
+ char *html;
19
+
20
+ /* 1a: Backslash before [ after ! — not an image (CommonMark) */
21
+ const char *escaped_bang_bracket = "Not an image: !\\[literal bracket after bang]";
22
+ html = apex_markdown_to_html(escaped_bang_bracket, strlen(escaped_bang_bracket), &opts);
23
+ assert_not_contains(html, "<img", "escaped ![ is not an image (no img tag)");
24
+ assert_contains(html, "literal bracket after bang", "escaped case preserves link text as plain text");
25
+ apex_free_string(html);
26
+
27
+ /* 1b: Sentence with ! immediately before [ — not a valid image; no runaway parse */
28
+ const char *blog_glitch = "I'm so glad you're all here![ Now that the update is slowing down, I will continue.";
29
+ html = apex_markdown_to_html(blog_glitch, strlen(blog_glitch), &opts);
30
+ assert_not_contains(html, "<img", "false ![ opener (blog case) does not emit img");
31
+ assert_contains(html, "I will continue", "false ![ opener preserves tail of sentence");
32
+ apex_free_string(html);
33
+
34
+ /* 2–3: U+2033 must not truncate output vs same line with ASCII \" */
35
+ char height_utf8[512];
36
+ snprintf(height_utf8, sizeof(height_utf8),
37
+ "Height in parentheses: (He's 5'7%s if you're wondering.) More text after the parens.",
38
+ UTF8_DOUBLE_PRIME);
39
+ html = apex_markdown_to_html(height_utf8, strlen(height_utf8), &opts);
40
+ assert_contains(html, "More text after the parens", "U+2033 height line: full sentence preserved");
41
+ assert_contains(html, "wondering", "U+2033 height line: middle of sentence preserved");
42
+ apex_free_string(html);
43
+
44
+ const char *height_ascii =
45
+ "Height in parentheses: (He's 5'7\" if you're wondering.) More text after the parens.";
46
+ html = apex_markdown_to_html(height_ascii, strlen(height_ascii), &opts);
47
+ assert_contains(html, "More text after the parens", "ASCII quote height line: full sentence preserved");
48
+ apex_free_string(html);
49
+
50
+ char minimal_prime[64];
51
+ snprintf(minimal_prime, sizeof(minimal_prime), "X%s Y", UTF8_DOUBLE_PRIME);
52
+ html = apex_markdown_to_html(minimal_prime, strlen(minimal_prime), &opts);
53
+ assert_contains(html, ">X", "minimal U+2033 line: leading X preserved");
54
+ assert_contains(html, " Y", "minimal U+2033 line: space+Y preserved");
55
+ apex_free_string(html);
56
+
57
+ html = apex_markdown_to_html("X\" Y", 5, &opts);
58
+ assert_contains(html, " Y", "minimal ASCII quote line: space+Y preserved");
59
+ apex_free_string(html);
60
+
61
+ /* 4: True image still parses */
62
+ const char *real_img = "![alt text](https://example.com/image.png)";
63
+ html = apex_markdown_to_html(real_img, strlen(real_img), &opts);
64
+ assert_contains(html, "<img", "real ![alt](url) still produces img");
65
+ assert_contains(html, "example.com/image.png", "real image preserves src");
66
+ apex_free_string(html);
67
+
68
+ /* 5: Glued ** after paragraph (stress) */
69
+ char glued_buf[512];
70
+ snprintf(glued_buf, sizeof(glued_buf),
71
+ "End of paragraph with a closing paren. (He's 5'7%s if you're wondering.) Hope this "
72
+ "helps.**Next section** starts here.",
73
+ UTF8_DOUBLE_PRIME);
74
+ html = apex_markdown_to_html(glued_buf, strlen(glued_buf), &opts);
75
+ assert_contains(html, "Hope this helps", "glued bold: text before ** preserved");
76
+ assert_contains(html, "<strong>Next section</strong>", "glued bold: **Next section** is strong");
77
+ assert_contains(html, "starts here", "glued bold: tail preserved");
78
+ apex_free_string(html);
79
+
80
+ bool had_failures = suite_end(suite_failures);
81
+ print_suite_title("Escaping & Unicode repro (escaping-repro.md)", had_failures, false);
82
+ }