react-native-enriched-markdown 0.1.0 → 0.2.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.
- package/LICENSE +20 -0
- package/README.md +551 -0
- package/ReactNativeEnrichedMarkdown.podspec +27 -0
- package/android/build.gradle +101 -0
- package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextManagerDelegate.java +54 -0
- package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextManagerInterface.java +26 -0
- package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/ComponentDescriptors.cpp +22 -0
- package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/ComponentDescriptors.h +24 -0
- package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/EventEmitters.cpp +33 -0
- package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/EventEmitters.h +31 -0
- package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/Props.cpp +82 -0
- package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/Props.h +1388 -0
- package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/ShadowNodes.cpp +17 -0
- package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/ShadowNodes.h +32 -0
- package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/States.cpp +16 -0
- package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/States.h +20 -0
- package/android/gradle.properties +5 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/baseline-prof.txt +65 -0
- package/android/src/main/cpp/jni-adapter.cpp +220 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownText.kt +270 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownTextLayoutManager.kt +15 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownTextManager.kt +173 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownTextPackage.kt +17 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/MeasurementStore.kt +385 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/accessibility/MarkdownAccessibilityHelper.kt +279 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/events/LinkLongPressEvent.kt +23 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/events/LinkPressEvent.kt +23 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/parser/MarkdownASTNode.kt +31 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/parser/Parser.kt +62 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/BlockStyleContext.kt +166 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/BlockquoteRenderer.kt +84 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/CodeBlockRenderer.kt +104 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/CodeRenderer.kt +36 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/DocumentRenderer.kt +16 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/EmphasisRenderer.kt +27 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/HeadingRenderer.kt +70 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ImageRenderer.kt +68 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/LineBreakRenderer.kt +16 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/LinkRenderer.kt +29 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ListContextManager.kt +105 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ListItemRenderer.kt +59 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ListRenderer.kt +76 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/NodeRenderer.kt +103 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ParagraphRenderer.kt +80 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/Renderer.kt +109 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/SpanStyleCache.kt +86 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/StrikethroughRenderer.kt +27 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/StrongRenderer.kt +27 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/TextRenderer.kt +30 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ThematicBreakRenderer.kt +45 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/UnderlineRenderer.kt +27 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/BaseListSpan.kt +136 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/BlockquoteSpan.kt +135 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/CodeBackgroundSpan.kt +180 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/CodeBlockSpan.kt +196 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/CodeSpan.kt +27 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/EmphasisSpan.kt +34 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/HeadingSpan.kt +38 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/ImageSpan.kt +321 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/LineHeightSpan.kt +27 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/LinkSpan.kt +51 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/MarginBottomSpan.kt +76 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/OrderedListSpan.kt +87 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/StrikethroughSpan.kt +12 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/StrongSpan.kt +37 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/TextSpan.kt +26 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/ThematicBreakSpan.kt +69 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/UnorderedListSpan.kt +69 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/styles/BaseBlockStyle.kt +11 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/styles/BlockquoteStyle.kt +51 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/styles/CodeBlockStyle.kt +54 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/styles/CodeStyle.kt +21 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/styles/EmphasisStyle.kt +17 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/styles/HeadingStyle.kt +33 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/styles/ImageStyle.kt +23 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/styles/InlineImageStyle.kt +17 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/styles/LinkStyle.kt +19 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/styles/ListStyle.kt +57 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/styles/ParagraphStyle.kt +33 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/styles/StrikethroughStyle.kt +17 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/styles/StrongStyle.kt +17 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/styles/StyleConfig.kt +211 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/styles/StyleParser.kt +92 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/styles/TextAlignment.kt +32 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/styles/ThematicBreakStyle.kt +23 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/styles/UnderlineStyle.kt +17 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/AsyncDrawable.kt +91 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/HTMLGenerator.kt +827 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/LinkLongPressMovementMethod.kt +121 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/MarkdownExtractor.kt +375 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/SelectionActionMode.kt +139 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/Utils.kt +183 -0
- package/android/src/main/jni/CMakeLists.txt +70 -0
- package/android/src/main/jni/EnrichedMarkdownTextSpec.cpp +21 -0
- package/android/src/main/jni/EnrichedMarkdownTextSpec.h +25 -0
- package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextComponentDescriptor.h +29 -0
- package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextMeasurementManager.cpp +45 -0
- package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextMeasurementManager.h +21 -0
- package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextShadowNode.cpp +20 -0
- package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextShadowNode.h +37 -0
- package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/conversions.h +22 -0
- package/cpp/md4c/md4c.c +6492 -0
- package/cpp/md4c/md4c.h +402 -0
- package/cpp/parser/MD4CParser.cpp +327 -0
- package/cpp/parser/MD4CParser.hpp +27 -0
- package/cpp/parser/MarkdownASTNode.hpp +51 -0
- package/ios/EnrichedMarkdownText.h +18 -0
- package/ios/EnrichedMarkdownText.mm +1401 -0
- package/ios/attachments/EnrichedMarkdownImageAttachment.h +23 -0
- package/ios/attachments/EnrichedMarkdownImageAttachment.m +185 -0
- package/ios/attachments/ThematicBreakAttachment.h +15 -0
- package/ios/attachments/ThematicBreakAttachment.m +33 -0
- package/ios/generated/EnrichedMarkdownTextSpec/ComponentDescriptors.cpp +22 -0
- package/ios/generated/EnrichedMarkdownTextSpec/ComponentDescriptors.h +24 -0
- package/ios/generated/EnrichedMarkdownTextSpec/EventEmitters.cpp +33 -0
- package/ios/generated/EnrichedMarkdownTextSpec/EventEmitters.h +31 -0
- package/ios/generated/EnrichedMarkdownTextSpec/Props.cpp +82 -0
- package/ios/generated/EnrichedMarkdownTextSpec/Props.h +1388 -0
- package/ios/generated/EnrichedMarkdownTextSpec/RCTComponentViewHelpers.h +20 -0
- package/ios/generated/EnrichedMarkdownTextSpec/ShadowNodes.cpp +17 -0
- package/ios/generated/EnrichedMarkdownTextSpec/ShadowNodes.h +32 -0
- package/ios/generated/EnrichedMarkdownTextSpec/States.cpp +16 -0
- package/ios/generated/EnrichedMarkdownTextSpec/States.h +20 -0
- package/ios/internals/EnrichedMarkdownTextComponentDescriptor.h +19 -0
- package/ios/internals/EnrichedMarkdownTextShadowNode.h +43 -0
- package/ios/internals/EnrichedMarkdownTextShadowNode.mm +85 -0
- package/ios/internals/EnrichedMarkdownTextState.h +24 -0
- package/ios/parser/MarkdownASTNode.h +35 -0
- package/ios/parser/MarkdownASTNode.m +32 -0
- package/ios/parser/MarkdownParser.h +17 -0
- package/ios/parser/MarkdownParser.mm +42 -0
- package/ios/parser/MarkdownParserBridge.mm +120 -0
- package/ios/renderer/AttributedRenderer.h +11 -0
- package/ios/renderer/AttributedRenderer.m +152 -0
- package/ios/renderer/BlockquoteRenderer.h +7 -0
- package/ios/renderer/BlockquoteRenderer.m +160 -0
- package/ios/renderer/CodeBlockRenderer.h +10 -0
- package/ios/renderer/CodeBlockRenderer.m +90 -0
- package/ios/renderer/CodeRenderer.h +10 -0
- package/ios/renderer/CodeRenderer.m +60 -0
- package/ios/renderer/EmphasisRenderer.h +6 -0
- package/ios/renderer/EmphasisRenderer.m +96 -0
- package/ios/renderer/HeadingRenderer.h +7 -0
- package/ios/renderer/HeadingRenderer.m +105 -0
- package/ios/renderer/ImageRenderer.h +12 -0
- package/ios/renderer/ImageRenderer.m +83 -0
- package/ios/renderer/LinkRenderer.h +7 -0
- package/ios/renderer/LinkRenderer.m +69 -0
- package/ios/renderer/ListItemRenderer.h +16 -0
- package/ios/renderer/ListItemRenderer.m +103 -0
- package/ios/renderer/ListRenderer.h +13 -0
- package/ios/renderer/ListRenderer.m +70 -0
- package/ios/renderer/NodeRenderer.h +8 -0
- package/ios/renderer/ParagraphRenderer.h +7 -0
- package/ios/renderer/ParagraphRenderer.m +80 -0
- package/ios/renderer/RenderContext.h +105 -0
- package/ios/renderer/RenderContext.m +312 -0
- package/ios/renderer/RendererFactory.h +12 -0
- package/ios/renderer/RendererFactory.m +116 -0
- package/ios/renderer/StrikethroughRenderer.h +6 -0
- package/ios/renderer/StrikethroughRenderer.m +40 -0
- package/ios/renderer/StrongRenderer.h +6 -0
- package/ios/renderer/StrongRenderer.m +83 -0
- package/ios/renderer/TextRenderer.h +6 -0
- package/ios/renderer/TextRenderer.m +16 -0
- package/ios/renderer/ThematicBreakRenderer.h +5 -0
- package/ios/renderer/ThematicBreakRenderer.m +53 -0
- package/ios/renderer/UnderlineRenderer.h +6 -0
- package/ios/renderer/UnderlineRenderer.m +39 -0
- package/ios/styles/StyleConfig.h +274 -0
- package/ios/styles/StyleConfig.mm +1806 -0
- package/ios/utils/AccessibilityInfo.h +35 -0
- package/ios/utils/AccessibilityInfo.m +24 -0
- package/ios/utils/BlockquoteBorder.h +20 -0
- package/ios/utils/BlockquoteBorder.m +92 -0
- package/ios/utils/CodeBackground.h +19 -0
- package/ios/utils/CodeBackground.m +191 -0
- package/ios/utils/CodeBlockBackground.h +17 -0
- package/ios/utils/CodeBlockBackground.m +82 -0
- package/ios/utils/EditMenuUtils.h +22 -0
- package/ios/utils/EditMenuUtils.m +118 -0
- package/ios/utils/FontUtils.h +25 -0
- package/ios/utils/FontUtils.m +27 -0
- package/ios/utils/HTMLGenerator.h +20 -0
- package/ios/utils/HTMLGenerator.m +793 -0
- package/ios/utils/LastElementUtils.h +53 -0
- package/ios/utils/ListMarkerDrawer.h +15 -0
- package/ios/utils/ListMarkerDrawer.m +127 -0
- package/ios/utils/MarkdownAccessibilityElementBuilder.h +45 -0
- package/ios/utils/MarkdownAccessibilityElementBuilder.m +323 -0
- package/ios/utils/MarkdownExtractor.h +17 -0
- package/ios/utils/MarkdownExtractor.m +308 -0
- package/ios/utils/ParagraphStyleUtils.h +21 -0
- package/ios/utils/ParagraphStyleUtils.m +111 -0
- package/ios/utils/PasteboardUtils.h +36 -0
- package/ios/utils/PasteboardUtils.m +134 -0
- package/ios/utils/RTFExportUtils.h +24 -0
- package/ios/utils/RTFExportUtils.m +297 -0
- package/ios/utils/RuntimeKeys.h +38 -0
- package/ios/utils/RuntimeKeys.m +11 -0
- package/ios/utils/TextViewLayoutManager.h +14 -0
- package/ios/utils/TextViewLayoutManager.mm +113 -0
- package/lib/module/EnrichedMarkdownText.js +65 -0
- package/lib/module/EnrichedMarkdownText.js.map +1 -0
- package/lib/module/EnrichedMarkdownTextNativeComponent.ts +210 -0
- package/lib/module/index.js +4 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/normalizeMarkdownStyle.js +384 -0
- package/lib/module/normalizeMarkdownStyle.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/EnrichedMarkdownText.d.ts +183 -0
- package/lib/typescript/src/EnrichedMarkdownText.d.ts.map +1 -0
- package/lib/typescript/src/EnrichedMarkdownTextNativeComponent.d.ts +185 -0
- package/lib/typescript/src/EnrichedMarkdownTextNativeComponent.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +4 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/normalizeMarkdownStyle.d.ts +6 -0
- package/lib/typescript/src/normalizeMarkdownStyle.d.ts.map +1 -0
- package/package.json +186 -1
- package/react-native.config.js +13 -0
- package/src/EnrichedMarkdownText.tsx +280 -0
- package/src/EnrichedMarkdownTextNativeComponent.ts +210 -0
- package/src/index.tsx +10 -0
- package/src/normalizeMarkdownStyle.ts +423 -0
|
@@ -0,0 +1,327 @@
|
|
|
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_U: {
|
|
198
|
+
impl->pushNode(std::make_shared<MarkdownASTNode>(NodeType::Underline));
|
|
199
|
+
break;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
case MD_SPAN_CODE: {
|
|
203
|
+
impl->pushNode(std::make_shared<MarkdownASTNode>(NodeType::Code));
|
|
204
|
+
break;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
case MD_SPAN_DEL: {
|
|
208
|
+
impl->pushNode(std::make_shared<MarkdownASTNode>(NodeType::Strikethrough));
|
|
209
|
+
break;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
case MD_SPAN_IMG: {
|
|
213
|
+
auto node = std::make_shared<MarkdownASTNode>(NodeType::Image);
|
|
214
|
+
if (detail) {
|
|
215
|
+
auto *imgDetail = static_cast<MD_SPAN_IMG_DETAIL *>(detail);
|
|
216
|
+
std::string url = impl->getAttributeText(&imgDetail->src);
|
|
217
|
+
if (!url.empty()) {
|
|
218
|
+
node->setAttribute(ATTR_URL, url);
|
|
219
|
+
}
|
|
220
|
+
std::string title = impl->getAttributeText(&imgDetail->title);
|
|
221
|
+
if (!title.empty()) {
|
|
222
|
+
node->setAttribute(ATTR_TITLE, title);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
impl->pushNode(node);
|
|
226
|
+
break;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
default:
|
|
230
|
+
break;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return 0;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
static int leaveSpan(MD_SPANTYPE type, void *detail, void *userdata) {
|
|
237
|
+
(void)detail;
|
|
238
|
+
if (!userdata)
|
|
239
|
+
return 1;
|
|
240
|
+
auto *impl = static_cast<Impl *>(userdata);
|
|
241
|
+
|
|
242
|
+
if (!impl->nodeStack.empty()) {
|
|
243
|
+
impl->popNode();
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
return 0;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
static int text(MD_TEXTTYPE type, const MD_CHAR *text, MD_SIZE size, void *userdata) {
|
|
250
|
+
if (!userdata || !text || size == 0)
|
|
251
|
+
return 0;
|
|
252
|
+
auto *impl = static_cast<Impl *>(userdata);
|
|
253
|
+
|
|
254
|
+
// Handle soft/hard line breaks
|
|
255
|
+
if (type == MD_TEXT_SOFTBR || type == MD_TEXT_BR) {
|
|
256
|
+
auto brNode = std::make_shared<MarkdownASTNode>(NodeType::LineBreak);
|
|
257
|
+
impl->addInlineNode(brNode);
|
|
258
|
+
return 0;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// Handle text content (normal text, code text, etc.)
|
|
262
|
+
if (type == MD_TEXT_NORMAL || type == MD_TEXT_CODE) {
|
|
263
|
+
impl->currentText.append(text, size);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
return 0;
|
|
267
|
+
}
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
MD4CParser::MD4CParser() : impl_(std::make_unique<Impl>()) {}
|
|
271
|
+
|
|
272
|
+
MD4CParser::~MD4CParser() = default;
|
|
273
|
+
|
|
274
|
+
std::shared_ptr<MarkdownASTNode> MD4CParser::parse(const std::string &markdown, const Md4cFlags &md4cFlags) {
|
|
275
|
+
if (markdown.empty()) {
|
|
276
|
+
return std::make_shared<MarkdownASTNode>(NodeType::Document);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// Estimate stack depth based on markdown size
|
|
280
|
+
// Heuristic: ~1 nesting level per 500-1000 characters for typical markdown
|
|
281
|
+
// This is a rough estimate - actual depth depends on structure, not just size
|
|
282
|
+
// Base depth of 12 covers typical nested structures (blockquotes, future lists)
|
|
283
|
+
size_t estimatedDepth = 12; // Base depth for small documents
|
|
284
|
+
if (markdown.size() > 1000) {
|
|
285
|
+
// Scale up for larger documents, but cap the growth
|
|
286
|
+
estimatedDepth = std::min(static_cast<size_t>(12 + (markdown.size() / 1000)), static_cast<size_t>(64));
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
impl_->reset(estimatedDepth);
|
|
290
|
+
impl_->inputText = markdown.c_str();
|
|
291
|
+
|
|
292
|
+
// MD_FLAG_NOHTML: Disable HTML parsing
|
|
293
|
+
// MD_FLAG_STRIKETHROUGH: Enable ~~strikethrough~~ syntax
|
|
294
|
+
// MD_FLAG_UNDERLINE: When enabled, __ creates underline; when disabled, __ creates emphasis
|
|
295
|
+
unsigned flags = MD_FLAG_NOHTML | MD_FLAG_STRIKETHROUGH;
|
|
296
|
+
if (md4cFlags.underline) {
|
|
297
|
+
flags |= MD_FLAG_UNDERLINE;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// Configure MD4C parser with callbacks
|
|
301
|
+
MD_PARSER parser = {
|
|
302
|
+
0, // abi_version
|
|
303
|
+
flags, &Impl::enterBlock, &Impl::leaveBlock, &Impl::enterSpan, &Impl::leaveSpan, &Impl::text,
|
|
304
|
+
nullptr, // debug_log
|
|
305
|
+
nullptr // syntax
|
|
306
|
+
};
|
|
307
|
+
|
|
308
|
+
// Parse the markdown
|
|
309
|
+
int result = md_parse(markdown.c_str(), static_cast<MD_SIZE>(markdown.size()), &parser, impl_.get());
|
|
310
|
+
|
|
311
|
+
if (result != 0) {
|
|
312
|
+
// Parsing failed, return empty document
|
|
313
|
+
return std::make_shared<MarkdownASTNode>(NodeType::Document);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
impl_->flushText();
|
|
317
|
+
return impl_->root ? impl_->root : std::make_shared<MarkdownASTNode>(NodeType::Document);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// Static member definitions
|
|
321
|
+
const std::string MD4CParser::Impl::ATTR_LEVEL = "level";
|
|
322
|
+
const std::string MD4CParser::Impl::ATTR_URL = "url";
|
|
323
|
+
const std::string MD4CParser::Impl::ATTR_TITLE = "title";
|
|
324
|
+
const std::string MD4CParser::Impl::ATTR_FENCE_CHAR = "fenceChar";
|
|
325
|
+
const std::string MD4CParser::Impl::ATTR_LANGUAGE = "language";
|
|
326
|
+
|
|
327
|
+
} // namespace Markdown
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include "MarkdownASTNode.hpp"
|
|
4
|
+
#include <string>
|
|
5
|
+
#include <memory>
|
|
6
|
+
|
|
7
|
+
namespace Markdown {
|
|
8
|
+
|
|
9
|
+
struct Md4cFlags {
|
|
10
|
+
bool underline = false;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
class MD4CParser {
|
|
14
|
+
public:
|
|
15
|
+
MD4CParser();
|
|
16
|
+
~MD4CParser();
|
|
17
|
+
|
|
18
|
+
// Parse markdown string and return AST root node
|
|
19
|
+
std::shared_ptr<MarkdownASTNode> parse(const std::string& markdown, const Md4cFlags& flags = Md4cFlags{});
|
|
20
|
+
|
|
21
|
+
private:
|
|
22
|
+
class Impl;
|
|
23
|
+
std::unique_ptr<Impl> impl_;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
} // namespace Markdown
|
|
27
|
+
|
|
@@ -0,0 +1,51 @@
|
|
|
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
|
+
Strikethrough,
|
|
20
|
+
Underline,
|
|
21
|
+
Code,
|
|
22
|
+
Image,
|
|
23
|
+
Blockquote,
|
|
24
|
+
UnorderedList,
|
|
25
|
+
OrderedList,
|
|
26
|
+
ListItem,
|
|
27
|
+
CodeBlock,
|
|
28
|
+
ThematicBreak
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
struct MarkdownASTNode {
|
|
32
|
+
NodeType type;
|
|
33
|
+
std::string content;
|
|
34
|
+
std::unordered_map<std::string, std::string> attributes;
|
|
35
|
+
std::vector<std::shared_ptr<MarkdownASTNode>> children;
|
|
36
|
+
|
|
37
|
+
explicit MarkdownASTNode(NodeType t) : type(t) {}
|
|
38
|
+
|
|
39
|
+
void addChild(std::shared_ptr<MarkdownASTNode> child) {
|
|
40
|
+
if (child) {
|
|
41
|
+
children.push_back(std::move(child));
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
void setAttribute(const std::string& key, const std::string& value) {
|
|
46
|
+
attributes[key] = value;
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
} // namespace Markdown
|
|
51
|
+
|
|
@@ -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
|