react-native-enriched-markdown 0.1.0 → 0.1.1

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 (211) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +479 -0
  3. package/ReactNativeEnrichedMarkdown.podspec +27 -0
  4. package/android/build.gradle +101 -0
  5. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextManagerDelegate.java +39 -0
  6. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextManagerInterface.java +21 -0
  7. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/ComponentDescriptors.cpp +22 -0
  8. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/ComponentDescriptors.h +24 -0
  9. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/EventEmitters.cpp +24 -0
  10. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/EventEmitters.h +25 -0
  11. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/Props.cpp +57 -0
  12. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/Props.h +1164 -0
  13. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/ShadowNodes.cpp +17 -0
  14. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/ShadowNodes.h +32 -0
  15. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/States.cpp +16 -0
  16. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/States.h +20 -0
  17. package/android/gradle.properties +5 -0
  18. package/android/src/main/AndroidManifest.xml +2 -0
  19. package/android/src/main/baseline-prof.txt +65 -0
  20. package/android/src/main/cpp/jni-adapter.cpp +203 -0
  21. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownText.kt +153 -0
  22. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownTextLayoutManager.kt +30 -0
  23. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownTextManager.kt +119 -0
  24. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownTextPackage.kt +17 -0
  25. package/android/src/main/java/com/swmansion/enriched/markdown/MeasurementStore.kt +165 -0
  26. package/android/src/main/java/com/swmansion/enriched/markdown/events/LinkPressEvent.kt +23 -0
  27. package/android/src/main/java/com/swmansion/enriched/markdown/parser/MarkdownASTNode.kt +29 -0
  28. package/android/src/main/java/com/swmansion/enriched/markdown/parser/Parser.kt +48 -0
  29. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/BlockStyleContext.kt +166 -0
  30. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/BlockquoteRenderer.kt +89 -0
  31. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/CodeBlockRenderer.kt +105 -0
  32. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/CodeRenderer.kt +35 -0
  33. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/DocumentRenderer.kt +15 -0
  34. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/EmphasisRenderer.kt +26 -0
  35. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/HeadingRenderer.kt +54 -0
  36. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ImageRenderer.kt +52 -0
  37. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/LineBreakRenderer.kt +15 -0
  38. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/LinkRenderer.kt +28 -0
  39. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ListContextManager.kt +105 -0
  40. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ListItemRenderer.kt +58 -0
  41. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ListRenderer.kt +69 -0
  42. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/NodeRenderer.kt +99 -0
  43. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ParagraphRenderer.kt +66 -0
  44. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/Renderer.kt +95 -0
  45. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/SpanStyleCache.kt +85 -0
  46. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/StrongRenderer.kt +26 -0
  47. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/TextRenderer.kt +29 -0
  48. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ThematicBreakRenderer.kt +44 -0
  49. package/android/src/main/java/com/swmansion/enriched/markdown/spans/BaseListSpan.kt +136 -0
  50. package/android/src/main/java/com/swmansion/enriched/markdown/spans/BlockquoteSpan.kt +135 -0
  51. package/android/src/main/java/com/swmansion/enriched/markdown/spans/CodeBackgroundSpan.kt +180 -0
  52. package/android/src/main/java/com/swmansion/enriched/markdown/spans/CodeBlockSpan.kt +196 -0
  53. package/android/src/main/java/com/swmansion/enriched/markdown/spans/CodeSpan.kt +27 -0
  54. package/android/src/main/java/com/swmansion/enriched/markdown/spans/EmphasisSpan.kt +34 -0
  55. package/android/src/main/java/com/swmansion/enriched/markdown/spans/HeadingSpan.kt +38 -0
  56. package/android/src/main/java/com/swmansion/enriched/markdown/spans/ImageSpan.kt +320 -0
  57. package/android/src/main/java/com/swmansion/enriched/markdown/spans/LineHeightSpan.kt +36 -0
  58. package/android/src/main/java/com/swmansion/enriched/markdown/spans/LinkSpan.kt +37 -0
  59. package/android/src/main/java/com/swmansion/enriched/markdown/spans/MarginBottomSpan.kt +76 -0
  60. package/android/src/main/java/com/swmansion/enriched/markdown/spans/OrderedListSpan.kt +87 -0
  61. package/android/src/main/java/com/swmansion/enriched/markdown/spans/StrongSpan.kt +37 -0
  62. package/android/src/main/java/com/swmansion/enriched/markdown/spans/TextSpan.kt +26 -0
  63. package/android/src/main/java/com/swmansion/enriched/markdown/spans/ThematicBreakSpan.kt +69 -0
  64. package/android/src/main/java/com/swmansion/enriched/markdown/spans/UnorderedListSpan.kt +69 -0
  65. package/android/src/main/java/com/swmansion/enriched/markdown/styles/BaseBlockStyle.kt +10 -0
  66. package/android/src/main/java/com/swmansion/enriched/markdown/styles/BlockquoteStyle.kt +48 -0
  67. package/android/src/main/java/com/swmansion/enriched/markdown/styles/CodeBlockStyle.kt +51 -0
  68. package/android/src/main/java/com/swmansion/enriched/markdown/styles/CodeStyle.kt +21 -0
  69. package/android/src/main/java/com/swmansion/enriched/markdown/styles/EmphasisStyle.kt +17 -0
  70. package/android/src/main/java/com/swmansion/enriched/markdown/styles/HeadingStyle.kt +29 -0
  71. package/android/src/main/java/com/swmansion/enriched/markdown/styles/ImageStyle.kt +21 -0
  72. package/android/src/main/java/com/swmansion/enriched/markdown/styles/InlineImageStyle.kt +17 -0
  73. package/android/src/main/java/com/swmansion/enriched/markdown/styles/LinkStyle.kt +19 -0
  74. package/android/src/main/java/com/swmansion/enriched/markdown/styles/ListStyle.kt +54 -0
  75. package/android/src/main/java/com/swmansion/enriched/markdown/styles/ParagraphStyle.kt +29 -0
  76. package/android/src/main/java/com/swmansion/enriched/markdown/styles/StrongStyle.kt +17 -0
  77. package/android/src/main/java/com/swmansion/enriched/markdown/styles/StyleConfig.kt +180 -0
  78. package/android/src/main/java/com/swmansion/enriched/markdown/styles/StyleParser.kt +75 -0
  79. package/android/src/main/java/com/swmansion/enriched/markdown/styles/ThematicBreakStyle.kt +23 -0
  80. package/android/src/main/java/com/swmansion/enriched/markdown/utils/AsyncDrawable.kt +91 -0
  81. package/android/src/main/java/com/swmansion/enriched/markdown/utils/HTMLGenerator.kt +809 -0
  82. package/android/src/main/java/com/swmansion/enriched/markdown/utils/MarkdownExtractor.kt +365 -0
  83. package/android/src/main/java/com/swmansion/enriched/markdown/utils/SelectionActionMode.kt +139 -0
  84. package/android/src/main/java/com/swmansion/enriched/markdown/utils/Utils.kt +181 -0
  85. package/android/src/main/jni/CMakeLists.txt +82 -0
  86. package/android/src/main/jni/EnrichedMarkdownTextSpec.cpp +21 -0
  87. package/android/src/main/jni/EnrichedMarkdownTextSpec.h +25 -0
  88. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextComponentDescriptor.h +29 -0
  89. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextMeasurementManager.cpp +45 -0
  90. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextMeasurementManager.h +21 -0
  91. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextShadowNode.cpp +33 -0
  92. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextShadowNode.h +49 -0
  93. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextState.cpp +9 -0
  94. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextState.h +25 -0
  95. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/conversions.h +19 -0
  96. package/cpp/md4c/md4c.c +6492 -0
  97. package/cpp/md4c/md4c.h +402 -0
  98. package/cpp/parser/MD4CParser.cpp +314 -0
  99. package/cpp/parser/MD4CParser.hpp +23 -0
  100. package/cpp/parser/MarkdownASTNode.hpp +49 -0
  101. package/ios/EnrichedMarkdownText.h +18 -0
  102. package/ios/EnrichedMarkdownText.mm +1074 -0
  103. package/ios/attachments/ImageAttachment.h +23 -0
  104. package/ios/attachments/ImageAttachment.m +185 -0
  105. package/ios/attachments/ThematicBreakAttachment.h +15 -0
  106. package/ios/attachments/ThematicBreakAttachment.m +33 -0
  107. package/ios/generated/EnrichedMarkdownTextSpec/ComponentDescriptors.cpp +22 -0
  108. package/ios/generated/EnrichedMarkdownTextSpec/ComponentDescriptors.h +24 -0
  109. package/ios/generated/EnrichedMarkdownTextSpec/EventEmitters.cpp +24 -0
  110. package/ios/generated/EnrichedMarkdownTextSpec/EventEmitters.h +25 -0
  111. package/ios/generated/EnrichedMarkdownTextSpec/Props.cpp +57 -0
  112. package/ios/generated/EnrichedMarkdownTextSpec/Props.h +1164 -0
  113. package/ios/generated/EnrichedMarkdownTextSpec/RCTComponentViewHelpers.h +20 -0
  114. package/ios/generated/EnrichedMarkdownTextSpec/ShadowNodes.cpp +17 -0
  115. package/ios/generated/EnrichedMarkdownTextSpec/ShadowNodes.h +32 -0
  116. package/ios/generated/EnrichedMarkdownTextSpec/States.cpp +16 -0
  117. package/ios/generated/EnrichedMarkdownTextSpec/States.h +20 -0
  118. package/ios/internals/EnrichedMarkdownTextComponentDescriptor.h +19 -0
  119. package/ios/internals/EnrichedMarkdownTextShadowNode.h +43 -0
  120. package/ios/internals/EnrichedMarkdownTextShadowNode.mm +85 -0
  121. package/ios/internals/EnrichedMarkdownTextState.h +24 -0
  122. package/ios/parser/MarkdownASTNode.h +33 -0
  123. package/ios/parser/MarkdownASTNode.m +32 -0
  124. package/ios/parser/MarkdownParser.h +8 -0
  125. package/ios/parser/MarkdownParser.mm +13 -0
  126. package/ios/parser/MarkdownParserBridge.mm +110 -0
  127. package/ios/renderer/AttributedRenderer.h +9 -0
  128. package/ios/renderer/AttributedRenderer.m +119 -0
  129. package/ios/renderer/BlockquoteRenderer.h +7 -0
  130. package/ios/renderer/BlockquoteRenderer.m +159 -0
  131. package/ios/renderer/CodeBlockRenderer.h +10 -0
  132. package/ios/renderer/CodeBlockRenderer.m +89 -0
  133. package/ios/renderer/CodeRenderer.h +10 -0
  134. package/ios/renderer/CodeRenderer.m +60 -0
  135. package/ios/renderer/EmphasisRenderer.h +6 -0
  136. package/ios/renderer/EmphasisRenderer.m +96 -0
  137. package/ios/renderer/HeadingRenderer.h +7 -0
  138. package/ios/renderer/HeadingRenderer.m +98 -0
  139. package/ios/renderer/ImageRenderer.h +12 -0
  140. package/ios/renderer/ImageRenderer.m +62 -0
  141. package/ios/renderer/LinkRenderer.h +7 -0
  142. package/ios/renderer/LinkRenderer.m +69 -0
  143. package/ios/renderer/ListItemRenderer.h +16 -0
  144. package/ios/renderer/ListItemRenderer.m +91 -0
  145. package/ios/renderer/ListRenderer.h +13 -0
  146. package/ios/renderer/ListRenderer.m +67 -0
  147. package/ios/renderer/NodeRenderer.h +8 -0
  148. package/ios/renderer/ParagraphRenderer.h +7 -0
  149. package/ios/renderer/ParagraphRenderer.m +69 -0
  150. package/ios/renderer/RenderContext.h +88 -0
  151. package/ios/renderer/RenderContext.m +248 -0
  152. package/ios/renderer/RendererFactory.h +12 -0
  153. package/ios/renderer/RendererFactory.m +110 -0
  154. package/ios/renderer/StrongRenderer.h +6 -0
  155. package/ios/renderer/StrongRenderer.m +83 -0
  156. package/ios/renderer/TextRenderer.h +6 -0
  157. package/ios/renderer/TextRenderer.m +16 -0
  158. package/ios/renderer/ThematicBreakRenderer.h +5 -0
  159. package/ios/renderer/ThematicBreakRenderer.m +53 -0
  160. package/ios/styles/StyleConfig.h +228 -0
  161. package/ios/styles/StyleConfig.mm +1467 -0
  162. package/ios/utils/BlockquoteBorder.h +20 -0
  163. package/ios/utils/BlockquoteBorder.m +92 -0
  164. package/ios/utils/CodeBackground.h +19 -0
  165. package/ios/utils/CodeBackground.m +191 -0
  166. package/ios/utils/CodeBlockBackground.h +17 -0
  167. package/ios/utils/CodeBlockBackground.m +87 -0
  168. package/ios/utils/EditMenuUtils.h +22 -0
  169. package/ios/utils/EditMenuUtils.m +118 -0
  170. package/ios/utils/FontUtils.h +20 -0
  171. package/ios/utils/FontUtils.m +13 -0
  172. package/ios/utils/HTMLGenerator.h +20 -0
  173. package/ios/utils/HTMLGenerator.m +779 -0
  174. package/ios/utils/LastElementUtils.h +53 -0
  175. package/ios/utils/ListMarkerDrawer.h +15 -0
  176. package/ios/utils/ListMarkerDrawer.m +127 -0
  177. package/ios/utils/MarkdownExtractor.h +17 -0
  178. package/ios/utils/MarkdownExtractor.m +295 -0
  179. package/ios/utils/ParagraphStyleUtils.h +13 -0
  180. package/ios/utils/ParagraphStyleUtils.m +56 -0
  181. package/ios/utils/PasteboardUtils.h +36 -0
  182. package/ios/utils/PasteboardUtils.m +134 -0
  183. package/ios/utils/RTFExportUtils.h +24 -0
  184. package/ios/utils/RTFExportUtils.m +297 -0
  185. package/ios/utils/RuntimeKeys.h +38 -0
  186. package/ios/utils/RuntimeKeys.m +11 -0
  187. package/ios/utils/TextViewLayoutManager.h +14 -0
  188. package/ios/utils/TextViewLayoutManager.mm +113 -0
  189. package/lib/module/EnrichedMarkdownText.js +34 -0
  190. package/lib/module/EnrichedMarkdownText.js.map +1 -0
  191. package/lib/module/EnrichedMarkdownTextNativeComponent.ts +130 -0
  192. package/lib/module/index.js +5 -0
  193. package/lib/module/index.js.map +1 -0
  194. package/lib/module/normalizeMarkdownStyle.js +340 -0
  195. package/lib/module/normalizeMarkdownStyle.js.map +1 -0
  196. package/lib/module/package.json +1 -0
  197. package/lib/typescript/package.json +1 -0
  198. package/lib/typescript/src/EnrichedMarkdownText.d.ts +101 -0
  199. package/lib/typescript/src/EnrichedMarkdownText.d.ts.map +1 -0
  200. package/lib/typescript/src/EnrichedMarkdownTextNativeComponent.d.ts +111 -0
  201. package/lib/typescript/src/EnrichedMarkdownTextNativeComponent.d.ts.map +1 -0
  202. package/lib/typescript/src/index.d.ts +5 -0
  203. package/lib/typescript/src/index.d.ts.map +1 -0
  204. package/lib/typescript/src/normalizeMarkdownStyle.d.ts +6 -0
  205. package/lib/typescript/src/normalizeMarkdownStyle.d.ts.map +1 -0
  206. package/package.json +186 -1
  207. package/react-native.config.js +13 -0
  208. package/src/EnrichedMarkdownText.tsx +152 -0
  209. package/src/EnrichedMarkdownTextNativeComponent.ts +130 -0
  210. package/src/index.tsx +7 -0
  211. package/src/normalizeMarkdownStyle.ts +377 -0
@@ -0,0 +1,314 @@
1
+ #include "MD4CParser.hpp"
2
+ #include "../md4c/md4c.h"
3
+ #include <cstring>
4
+ #include <vector>
5
+
6
+ namespace Markdown {
7
+
8
+ class MD4CParser::Impl {
9
+ public:
10
+ std::shared_ptr<MarkdownASTNode> root;
11
+ std::vector<std::shared_ptr<MarkdownASTNode>> nodeStack;
12
+ std::string currentText;
13
+ const char *inputText = nullptr;
14
+
15
+ static const std::string ATTR_LEVEL;
16
+ static const std::string ATTR_URL;
17
+ static const std::string ATTR_TITLE;
18
+ static const std::string ATTR_FENCE_CHAR;
19
+ static const std::string ATTR_LANGUAGE;
20
+
21
+ void reset(size_t estimatedDepth) {
22
+ root = std::make_shared<MarkdownASTNode>(NodeType::Document);
23
+ nodeStack.clear();
24
+ // Reserve based on estimated depth, with reasonable bounds
25
+ // Typical markdown has 5-15 levels, but can go deeper with nested structures
26
+ // Cap at 128 to avoid excessive memory for extreme cases
27
+ nodeStack.reserve(std::min(estimatedDepth, static_cast<size_t>(128)));
28
+ nodeStack.push_back(root);
29
+ currentText.clear();
30
+ currentText.reserve(256);
31
+ }
32
+
33
+ void flushText() {
34
+ if (!currentText.empty() && !nodeStack.empty()) {
35
+ auto textNode = std::make_shared<MarkdownASTNode>(NodeType::Text);
36
+ textNode->content = std::move(currentText);
37
+ nodeStack.back()->addChild(std::move(textNode));
38
+ currentText.clear();
39
+ }
40
+ }
41
+
42
+ void pushNode(std::shared_ptr<MarkdownASTNode> node) {
43
+ flushText();
44
+ if (node && !nodeStack.empty()) {
45
+ nodeStack.back()->addChild(node);
46
+ nodeStack.push_back(std::move(node));
47
+ }
48
+ }
49
+
50
+ void popNode() {
51
+ flushText();
52
+ if (nodeStack.size() > 1) {
53
+ nodeStack.pop_back();
54
+ }
55
+ }
56
+
57
+ void addInlineNode(std::shared_ptr<MarkdownASTNode> node) {
58
+ if (node && !nodeStack.empty()) {
59
+ nodeStack.back()->addChild(node);
60
+ }
61
+ }
62
+
63
+ std::string getAttributeText(const MD_ATTRIBUTE *attr) {
64
+ if (!attr || attr->size == 0 || !attr->text)
65
+ return {};
66
+
67
+ // Use string constructor directly - let SSO handle small strings efficiently
68
+ // Empty return {} avoids allocating empty string object
69
+ return std::string(attr->text, attr->size);
70
+ }
71
+
72
+ static int enterBlock(MD_BLOCKTYPE type, void *detail, void *userdata) {
73
+ if (!userdata)
74
+ return 1;
75
+ auto *impl = static_cast<Impl *>(userdata);
76
+
77
+ switch (type) {
78
+ case MD_BLOCK_DOC:
79
+ // Document node already created in reset()
80
+ break;
81
+
82
+ case MD_BLOCK_P: {
83
+ impl->pushNode(std::make_shared<MarkdownASTNode>(NodeType::Paragraph));
84
+ break;
85
+ }
86
+
87
+ case MD_BLOCK_H: {
88
+ auto node = std::make_shared<MarkdownASTNode>(NodeType::Heading);
89
+ if (detail) {
90
+ auto *h = static_cast<MD_BLOCK_H_DETAIL *>(detail);
91
+ int level = static_cast<int>(h->level);
92
+ // Clamp level to valid range (1-6)
93
+ level = (level < 1) ? 1 : (level > 6) ? 6 : level;
94
+ // Use char conversion for small integers (1-6)
95
+ // Avoids std::to_string() allocation overhead
96
+ char levelStr[2] = {static_cast<char>('0' + level), '\0'};
97
+ node->setAttribute(ATTR_LEVEL, levelStr);
98
+ }
99
+ impl->pushNode(node);
100
+ break;
101
+ }
102
+
103
+ case MD_BLOCK_QUOTE: {
104
+ impl->pushNode(std::make_shared<MarkdownASTNode>(NodeType::Blockquote));
105
+ break;
106
+ }
107
+
108
+ case MD_BLOCK_UL: {
109
+ impl->pushNode(std::make_shared<MarkdownASTNode>(NodeType::UnorderedList));
110
+ break;
111
+ }
112
+
113
+ case MD_BLOCK_OL: {
114
+ impl->pushNode(std::make_shared<MarkdownASTNode>(NodeType::OrderedList));
115
+ break;
116
+ }
117
+
118
+ case MD_BLOCK_LI: {
119
+ impl->pushNode(std::make_shared<MarkdownASTNode>(NodeType::ListItem));
120
+ break;
121
+ }
122
+
123
+ case MD_BLOCK_CODE: {
124
+ auto node = std::make_shared<MarkdownASTNode>(NodeType::CodeBlock);
125
+ if (detail) {
126
+ auto *codeDetail = static_cast<MD_BLOCK_CODE_DETAIL *>(detail);
127
+ // Extract fence character (if fenced code block)
128
+ if (codeDetail->fence_char != 0) {
129
+ char fenceStr[2] = {static_cast<char>(codeDetail->fence_char), '\0'};
130
+ node->setAttribute(ATTR_FENCE_CHAR, fenceStr);
131
+ }
132
+ // Extract language from lang attribute
133
+ std::string lang = impl->getAttributeText(&codeDetail->lang);
134
+ if (!lang.empty()) {
135
+ node->setAttribute(ATTR_LANGUAGE, lang);
136
+ }
137
+ }
138
+ impl->pushNode(node);
139
+ break;
140
+ }
141
+
142
+ case MD_BLOCK_HR: {
143
+ impl->pushNode(std::make_shared<MarkdownASTNode>(NodeType::ThematicBreak));
144
+ break;
145
+ }
146
+
147
+ default:
148
+ // Other block types not yet implemented
149
+ break;
150
+ }
151
+
152
+ return 0;
153
+ }
154
+
155
+ static int leaveBlock(MD_BLOCKTYPE type, void *detail, void *userdata) {
156
+ (void)detail;
157
+ if (!userdata)
158
+ return 1;
159
+ auto *impl = static_cast<Impl *>(userdata);
160
+
161
+ if (type != MD_BLOCK_DOC && !impl->nodeStack.empty()) {
162
+ impl->popNode();
163
+ }
164
+
165
+ return 0;
166
+ }
167
+
168
+ static int enterSpan(MD_SPANTYPE type, void *detail, void *userdata) {
169
+ if (!userdata)
170
+ return 1;
171
+ auto *impl = static_cast<Impl *>(userdata);
172
+
173
+ switch (type) {
174
+ case MD_SPAN_A: {
175
+ auto node = std::make_shared<MarkdownASTNode>(NodeType::Link);
176
+ if (detail) {
177
+ auto *linkDetail = static_cast<MD_SPAN_A_DETAIL *>(detail);
178
+ std::string url = impl->getAttributeText(&linkDetail->href);
179
+ if (!url.empty()) {
180
+ node->setAttribute(ATTR_URL, url);
181
+ }
182
+ }
183
+ impl->pushNode(node);
184
+ break;
185
+ }
186
+
187
+ case MD_SPAN_STRONG: {
188
+ impl->pushNode(std::make_shared<MarkdownASTNode>(NodeType::Strong));
189
+ break;
190
+ }
191
+
192
+ case MD_SPAN_EM: {
193
+ impl->pushNode(std::make_shared<MarkdownASTNode>(NodeType::Emphasis));
194
+ break;
195
+ }
196
+
197
+ case MD_SPAN_CODE: {
198
+ impl->pushNode(std::make_shared<MarkdownASTNode>(NodeType::Code));
199
+ break;
200
+ }
201
+
202
+ case MD_SPAN_IMG: {
203
+ auto node = std::make_shared<MarkdownASTNode>(NodeType::Image);
204
+ if (detail) {
205
+ auto *imgDetail = static_cast<MD_SPAN_IMG_DETAIL *>(detail);
206
+ std::string url = impl->getAttributeText(&imgDetail->src);
207
+ if (!url.empty()) {
208
+ node->setAttribute(ATTR_URL, url);
209
+ }
210
+ std::string title = impl->getAttributeText(&imgDetail->title);
211
+ if (!title.empty()) {
212
+ node->setAttribute(ATTR_TITLE, title);
213
+ }
214
+ }
215
+ impl->pushNode(node);
216
+ break;
217
+ }
218
+
219
+ default:
220
+ break;
221
+ }
222
+
223
+ return 0;
224
+ }
225
+
226
+ static int leaveSpan(MD_SPANTYPE type, void *detail, void *userdata) {
227
+ (void)detail;
228
+ if (!userdata)
229
+ return 1;
230
+ auto *impl = static_cast<Impl *>(userdata);
231
+
232
+ if (!impl->nodeStack.empty()) {
233
+ impl->popNode();
234
+ }
235
+
236
+ return 0;
237
+ }
238
+
239
+ static int text(MD_TEXTTYPE type, const MD_CHAR *text, MD_SIZE size, void *userdata) {
240
+ if (!userdata || !text || size == 0)
241
+ return 0;
242
+ auto *impl = static_cast<Impl *>(userdata);
243
+
244
+ // Handle soft/hard line breaks
245
+ if (type == MD_TEXT_SOFTBR || type == MD_TEXT_BR) {
246
+ auto brNode = std::make_shared<MarkdownASTNode>(NodeType::LineBreak);
247
+ impl->addInlineNode(brNode);
248
+ return 0;
249
+ }
250
+
251
+ // Handle text content (normal text, code text, etc.)
252
+ if (type == MD_TEXT_NORMAL || type == MD_TEXT_CODE) {
253
+ impl->currentText.append(text, size);
254
+ }
255
+
256
+ return 0;
257
+ }
258
+ };
259
+
260
+ MD4CParser::MD4CParser() : impl_(std::make_unique<Impl>()) {}
261
+
262
+ MD4CParser::~MD4CParser() = default;
263
+
264
+ std::shared_ptr<MarkdownASTNode> MD4CParser::parse(const std::string &markdown) {
265
+ if (markdown.empty()) {
266
+ return std::make_shared<MarkdownASTNode>(NodeType::Document);
267
+ }
268
+
269
+ // Estimate stack depth based on markdown size
270
+ // Heuristic: ~1 nesting level per 500-1000 characters for typical markdown
271
+ // This is a rough estimate - actual depth depends on structure, not just size
272
+ // Base depth of 12 covers typical nested structures (blockquotes, future lists)
273
+ size_t estimatedDepth = 12; // Base depth for small documents
274
+ if (markdown.size() > 1000) {
275
+ // Scale up for larger documents, but cap the growth
276
+ estimatedDepth = std::min(static_cast<size_t>(12 + (markdown.size() / 1000)), static_cast<size_t>(64));
277
+ }
278
+
279
+ impl_->reset(estimatedDepth);
280
+ impl_->inputText = markdown.c_str();
281
+
282
+ // Configure MD4C parser with callbacks
283
+ MD_PARSER parser = {
284
+ 0, // abi_version
285
+ MD_FLAG_NOHTML, // flags - disable HTML for security
286
+ &Impl::enterBlock,
287
+ &Impl::leaveBlock,
288
+ &Impl::enterSpan,
289
+ &Impl::leaveSpan,
290
+ &Impl::text,
291
+ nullptr, // debug_log
292
+ nullptr // syntax
293
+ };
294
+
295
+ // Parse the markdown
296
+ int result = md_parse(markdown.c_str(), static_cast<MD_SIZE>(markdown.size()), &parser, impl_.get());
297
+
298
+ if (result != 0) {
299
+ // Parsing failed, return empty document
300
+ return std::make_shared<MarkdownASTNode>(NodeType::Document);
301
+ }
302
+
303
+ impl_->flushText();
304
+ return impl_->root ? impl_->root : std::make_shared<MarkdownASTNode>(NodeType::Document);
305
+ }
306
+
307
+ // Static member definitions
308
+ const std::string MD4CParser::Impl::ATTR_LEVEL = "level";
309
+ const std::string MD4CParser::Impl::ATTR_URL = "url";
310
+ const std::string MD4CParser::Impl::ATTR_TITLE = "title";
311
+ const std::string MD4CParser::Impl::ATTR_FENCE_CHAR = "fenceChar";
312
+ const std::string MD4CParser::Impl::ATTR_LANGUAGE = "language";
313
+
314
+ } // namespace Markdown
@@ -0,0 +1,23 @@
1
+ #pragma once
2
+
3
+ #include "MarkdownASTNode.hpp"
4
+ #include <string>
5
+ #include <memory>
6
+
7
+ namespace Markdown {
8
+
9
+ class MD4CParser {
10
+ public:
11
+ MD4CParser();
12
+ ~MD4CParser();
13
+
14
+ // Parse markdown string and return AST root node
15
+ std::shared_ptr<MarkdownASTNode> parse(const std::string& markdown);
16
+
17
+ private:
18
+ class Impl;
19
+ std::unique_ptr<Impl> impl_;
20
+ };
21
+
22
+ } // namespace Markdown
23
+
@@ -0,0 +1,49 @@
1
+ #pragma once
2
+
3
+ #include <string>
4
+ #include <memory>
5
+ #include <vector>
6
+ #include <unordered_map>
7
+
8
+ namespace Markdown {
9
+
10
+ enum class NodeType {
11
+ Document,
12
+ Paragraph,
13
+ Text,
14
+ Link,
15
+ Heading,
16
+ LineBreak,
17
+ Strong,
18
+ Emphasis,
19
+ Code,
20
+ Image,
21
+ Blockquote,
22
+ UnorderedList,
23
+ OrderedList,
24
+ ListItem,
25
+ CodeBlock,
26
+ ThematicBreak
27
+ };
28
+
29
+ struct MarkdownASTNode {
30
+ NodeType type;
31
+ std::string content;
32
+ std::unordered_map<std::string, std::string> attributes;
33
+ std::vector<std::shared_ptr<MarkdownASTNode>> children;
34
+
35
+ explicit MarkdownASTNode(NodeType t) : type(t) {}
36
+
37
+ void addChild(std::shared_ptr<MarkdownASTNode> child) {
38
+ if (child) {
39
+ children.push_back(std::move(child));
40
+ }
41
+ }
42
+
43
+ void setAttribute(const std::string& key, const std::string& value) {
44
+ attributes[key] = value;
45
+ }
46
+ };
47
+
48
+ } // namespace Markdown
49
+
@@ -0,0 +1,18 @@
1
+ #import "StyleConfig.h"
2
+ #import <React/RCTViewComponentView.h>
3
+ #import <UIKit/UIKit.h>
4
+
5
+ #ifndef EnrichedMarkdownTextNativeComponent_h
6
+ #define EnrichedMarkdownTextNativeComponent_h
7
+
8
+ NS_ASSUME_NONNULL_BEGIN
9
+
10
+ @interface EnrichedMarkdownText : RCTViewComponentView
11
+ @property (nonatomic, strong) StyleConfig *config;
12
+ - (CGSize)measureSize:(CGFloat)maxWidth;
13
+ - (void)renderMarkdownSynchronously:(NSString *)markdownString;
14
+ @end
15
+
16
+ NS_ASSUME_NONNULL_END
17
+
18
+ #endif