react-native-marcus 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/README.md +220 -63
- package/RNMarcus.podspec +6 -0
- package/android/src/main/java/app/getbullet/marcus/MarcusPackage.kt +2 -1
- package/android/src/main/java/app/getbullet/marcus/MarcusTextDecoratorView.kt +168 -0
- package/android/src/main/java/app/getbullet/marcus/MarcusTextDecoratorViewManager.kt +38 -0
- package/android/src/main/java/app/getbullet/marcus/MarcusTextDecoratorViewManagerSpec.kt +19 -0
- package/android/src/main/java/app/getbullet/marcus/MarcusTextInputDecoratorView.kt +23 -1
- package/android/src/main/java/app/getbullet/marcus/MarkdownBackgroundPainter.kt +147 -0
- package/android/src/main/java/app/getbullet/marcus/MarkdownBackgroundPass.kt +19 -0
- package/android/src/main/java/app/getbullet/marcus/MarkdownCopy.kt +87 -0
- package/android/src/main/java/app/getbullet/marcus/MarkdownFormatter.kt +652 -113
- package/android/src/main/java/app/getbullet/marcus/MarkdownRanges.kt +47 -0
- package/android/src/main/java/app/getbullet/marcus/MarkdownStyle.kt +140 -61
- package/android/src/main/java/app/getbullet/marcus/MarkdownUtils.kt +37 -7
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownAbsoluteLineHeightSpan.kt +48 -0
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownBackgroundSpan.kt +102 -48
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownBlockIndentSpan.kt +22 -4
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownBulletSpan.kt +78 -0
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownCodeBlockSpan.kt +177 -0
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownFontStyleSpan.kt +32 -0
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownFontWeightSpan.kt +34 -0
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownGapSpan.kt +24 -11
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownLetterSpacingSpan.kt +32 -0
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownTextShadowSpan.kt +32 -0
- package/android/src/main/new_arch/CMakeLists.txt +17 -0
- package/android/src/main/new_arch/RNMarcusSpec.h +1 -0
- package/android/src/main/new_arch/react/renderer/components/RNMarcusSpec/MarcusTextDecoratorShadowNode.cpp +235 -0
- package/android/src/main/new_arch/react/renderer/components/RNMarcusSpec/MarcusTextDecoratorShadowNode.h +62 -0
- package/android/src/reactNativeVersionPatch/CustomMountingManager/81/app/getbullet/marcus/CustomFabricUIManager.java +22 -3
- package/android/src/reactNativeVersionPatch/CustomMountingManager/latest/app/getbullet/marcus/CustomFabricUIManager.java +22 -3
- package/android/src/test/java/app/getbullet/marcus/MarkdownCopyTest.kt +69 -0
- package/android/src/test/java/app/getbullet/marcus/MarkdownFormatterTest.kt +170 -25
- package/android/src/test/java/app/getbullet/marcus/RenderModel.kt +22 -5
- package/android/src/test/java/app/getbullet/marcus/spans/MarkdownCodeBlockSpanTest.kt +91 -0
- package/android/src/test/resources/render-model.txt +221 -16
- package/apple/MarcusSwizzle.h +25 -0
- package/apple/MarcusTextDecoratorComponentView.h +22 -0
- package/apple/MarcusTextDecoratorComponentView.mm +72 -0
- package/apple/MarcusTextDecoratorShadowNode.h +62 -0
- package/apple/MarcusTextDecoratorShadowNode.mm +192 -0
- package/apple/MarcusTextDecoratorViewManager.h +4 -0
- package/apple/MarcusTextDecoratorViewManager.mm +11 -0
- package/apple/MarcusTextInputDecoratorComponentView.mm +1 -1
- package/apple/MarcusTextInputDecoratorShadowNode.mm +1 -1
- package/apple/MarcusTextLayoutManager.h +40 -0
- package/apple/MarcusTextLayoutManager.mm +173 -0
- package/apple/MarkdownAttributes.h +23 -2
- package/apple/MarkdownAttributes.m +6 -0
- package/apple/MarkdownCopy.swift +63 -0
- package/apple/MarkdownDecorator.swift +2 -2
- package/apple/MarkdownFormatter+React.swift +23 -0
- package/apple/MarkdownFormatter.swift +869 -148
- package/apple/MarkdownParagraphLayoutManager.swift +455 -0
- package/apple/MarkdownSwiftInterop.h +0 -1
- package/apple/MarkdownTextBackground.swift +59 -1
- package/apple/MarkdownTextFieldObserver.swift +2 -2
- package/apple/MarkdownTextLayoutFragment.swift +159 -33
- package/apple/MarkdownTextLayoutManagerDelegate.swift +67 -3
- package/apple/MarkdownTextStorageDelegate.swift +2 -2
- package/apple/MarkdownTextViewObserver.swift +2 -2
- package/apple/MarkdownUtils.swift +38 -0
- package/apple/MarkdownWritingDirection.swift +132 -0
- package/apple/RCTMarcusStyle+Codegen.h +115 -9
- package/apple/RCTMarcusStyle.h +128 -31
- package/apple/RCTMarcusStyle.m +48 -0
- package/apple/RCTParagraphComponentView+Marcus.h +17 -0
- package/apple/RCTParagraphComponentView+Marcus.mm +38 -0
- package/apple/RCTTextInputComponentView+Marcus.mm +1 -25
- package/cpp/react/renderer/components/RNMarcusSpec/MarcusTextDecoratorState.h +37 -0
- package/cpp/react/renderer/components/RNMarcusSpec/MarcusTextDecoratorViewComponentDescriptor.h +17 -0
- package/lib/commonjs/MarcusTextDecoratorViewNativeComponent.ts +199 -0
- package/lib/commonjs/MarcusTextInputDecoratorViewNativeComponent.ts +145 -58
- package/lib/commonjs/MarkdownText.js +330 -0
- package/lib/commonjs/MarkdownText.js.map +1 -0
- package/lib/commonjs/MarkdownText.web.js +529 -0
- package/lib/commonjs/MarkdownText.web.js.map +1 -0
- package/lib/commonjs/MarkdownTextInput.js +22 -27
- package/lib/commonjs/MarkdownTextInput.js.map +1 -1
- package/lib/commonjs/MarkdownTextInput.web.js +12 -7
- package/lib/commonjs/MarkdownTextInput.web.js.map +1 -1
- package/lib/commonjs/atomUtils.js +112 -0
- package/lib/commonjs/atomUtils.js.map +1 -0
- package/lib/commonjs/childrenUtils.js +36 -0
- package/lib/commonjs/childrenUtils.js.map +1 -0
- package/lib/commonjs/index.js +8 -7
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/math/environment.js +69 -0
- package/lib/commonjs/math/environment.js.map +1 -0
- package/lib/commonjs/math/index.js +61 -0
- package/lib/commonjs/math/index.js.map +1 -0
- package/lib/commonjs/math/mathjax.js +548 -0
- package/lib/commonjs/math/mathjax.js.map +1 -0
- package/lib/commonjs/metro.js +172 -0
- package/lib/commonjs/metro.js.map +1 -0
- package/lib/commonjs/parser/index.d.ts +3 -0
- package/lib/commonjs/parser/index.js +450 -42
- package/lib/commonjs/parser/index.js.map +4 -4
- package/lib/commonjs/stripUtils.js +743 -0
- package/lib/commonjs/stripUtils.js.map +1 -0
- package/lib/commonjs/styleUtils.js +194 -23
- package/lib/commonjs/styleUtils.js.map +1 -1
- package/lib/commonjs/web/MarkdownElements.css +67 -0
- package/lib/commonjs/web/MarkdownTextInput.css +9 -7
- package/lib/commonjs/web/utils/blockLayout.js +95 -7
- package/lib/commonjs/web/utils/blockLayout.js.map +1 -1
- package/lib/commonjs/web/utils/blockUtils.js +327 -54
- package/lib/commonjs/web/utils/blockUtils.js.map +1 -1
- package/lib/commonjs/web/utils/elementUtils.js +80 -0
- package/lib/commonjs/web/utils/elementUtils.js.map +1 -0
- package/lib/commonjs/web/utils/parserUtils.js +84 -28
- package/lib/commonjs/web/utils/parserUtils.js.map +1 -1
- package/lib/commonjs/web/utils/treeUtils.js +6 -0
- package/lib/commonjs/web/utils/treeUtils.js.map +1 -1
- package/lib/commonjs/web/utils/webStyleUtils.js +25 -5
- package/lib/commonjs/web/utils/webStyleUtils.js.map +1 -1
- package/lib/module/MarcusTextDecoratorViewNativeComponent.ts +199 -0
- package/lib/module/MarcusTextInputDecoratorViewNativeComponent.ts +145 -58
- package/lib/module/MarkdownText.js +325 -0
- package/lib/module/MarkdownText.js.map +1 -0
- package/lib/module/MarkdownText.web.js +524 -0
- package/lib/module/MarkdownText.web.js.map +1 -0
- package/lib/module/MarkdownTextInput.js +24 -29
- package/lib/module/MarkdownTextInput.js.map +1 -1
- package/lib/module/MarkdownTextInput.web.js +12 -7
- package/lib/module/MarkdownTextInput.web.js.map +1 -1
- package/lib/module/atomUtils.js +106 -0
- package/lib/module/atomUtils.js.map +1 -0
- package/lib/module/childrenUtils.js +33 -0
- package/lib/module/childrenUtils.js.map +1 -0
- package/lib/module/index.js +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/math/environment.js +67 -0
- package/lib/module/math/environment.js.map +1 -0
- package/lib/module/math/index.js +56 -0
- package/lib/module/math/index.js.map +1 -0
- package/lib/module/math/mathjax.js +541 -0
- package/lib/module/math/mathjax.js.map +1 -0
- package/lib/module/metro.js +169 -0
- package/lib/module/metro.js.map +1 -0
- package/lib/module/parser/index.d.ts +3 -0
- package/lib/module/parser/index.js +450 -42
- package/lib/module/parser/index.js.map +4 -4
- package/lib/module/stripUtils.js +739 -0
- package/lib/module/stripUtils.js.map +1 -0
- package/lib/module/styleUtils.js +196 -25
- package/lib/module/styleUtils.js.map +1 -1
- package/lib/module/web/MarkdownElements.css +67 -0
- package/lib/module/web/MarkdownTextInput.css +9 -7
- package/lib/module/web/utils/blockLayout.js +94 -8
- package/lib/module/web/utils/blockLayout.js.map +1 -1
- package/lib/module/web/utils/blockUtils.js +328 -56
- package/lib/module/web/utils/blockUtils.js.map +1 -1
- package/lib/module/web/utils/elementUtils.js +75 -0
- package/lib/module/web/utils/elementUtils.js.map +1 -0
- package/lib/module/web/utils/parserUtils.js +86 -30
- package/lib/module/web/utils/parserUtils.js.map +1 -1
- package/lib/module/web/utils/treeUtils.js +6 -0
- package/lib/module/web/utils/treeUtils.js.map +1 -1
- package/lib/module/web/utils/webStyleUtils.js +25 -5
- package/lib/module/web/utils/webStyleUtils.js.map +1 -1
- package/lib/typescript/commonjs/e2e/links.test.d.ts +2 -0
- package/lib/typescript/commonjs/e2e/links.test.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/MarcusTextDecoratorViewNativeComponent.d.ts +93 -0
- package/lib/typescript/commonjs/src/MarcusTextDecoratorViewNativeComponent.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/MarcusTextInputDecoratorViewNativeComponent.d.ts +64 -51
- package/lib/typescript/commonjs/src/MarcusTextInputDecoratorViewNativeComponent.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/MarkdownText.d.ts +127 -0
- package/lib/typescript/commonjs/src/MarkdownText.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/MarkdownText.web.d.ts +126 -0
- package/lib/typescript/commonjs/src/MarkdownText.web.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/MarkdownTextInput.d.ts +23 -1
- package/lib/typescript/commonjs/src/MarkdownTextInput.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/MarkdownTextInput.web.d.ts +26 -4
- package/lib/typescript/commonjs/src/MarkdownTextInput.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/atomUtils.d.ts +58 -0
- package/lib/typescript/commonjs/src/atomUtils.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/childrenUtils.d.ts +12 -0
- package/lib/typescript/commonjs/src/childrenUtils.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/commonTypes.d.ts +39 -3
- package/lib/typescript/commonjs/src/commonTypes.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/index.d.ts +2 -1
- package/lib/typescript/commonjs/src/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/math/environment.d.ts +7 -0
- package/lib/typescript/commonjs/src/math/environment.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/math/index.d.ts +64 -0
- package/lib/typescript/commonjs/src/math/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/math/mathjax.d.ts +63 -0
- package/lib/typescript/commonjs/src/math/mathjax.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/metro.d.ts +59 -0
- package/lib/typescript/commonjs/src/metro.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/parser/index.d.ts +3 -3
- package/lib/typescript/commonjs/src/parser/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/parser/micromark-extension-mentions.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/rangeUtils.d.ts +1 -1
- package/lib/typescript/commonjs/src/stripUtils.d.ts +108 -0
- package/lib/typescript/commonjs/src/stripUtils.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/styleUtils.d.ts +62 -4
- package/lib/typescript/commonjs/src/styleUtils.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/web/utils/blockLayout.d.ts +32 -4
- package/lib/typescript/commonjs/src/web/utils/blockLayout.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/web/utils/blockUtils.d.ts +20 -8
- package/lib/typescript/commonjs/src/web/utils/blockUtils.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/web/utils/elementUtils.d.ts +37 -0
- package/lib/typescript/commonjs/src/web/utils/elementUtils.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/web/utils/parserUtils.d.ts +5 -5
- package/lib/typescript/commonjs/src/web/utils/parserUtils.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/web/utils/treeUtils.d.ts +6 -1
- package/lib/typescript/commonjs/src/web/utils/treeUtils.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/web/utils/webStyleUtils.d.ts +2 -2
- package/lib/typescript/commonjs/src/web/utils/webStyleUtils.d.ts.map +1 -1
- package/lib/typescript/module/e2e/links.test.d.ts +2 -0
- package/lib/typescript/module/e2e/links.test.d.ts.map +1 -0
- package/lib/typescript/module/src/MarcusTextDecoratorViewNativeComponent.d.ts +93 -0
- package/lib/typescript/module/src/MarcusTextDecoratorViewNativeComponent.d.ts.map +1 -0
- package/lib/typescript/module/src/MarcusTextInputDecoratorViewNativeComponent.d.ts +64 -51
- package/lib/typescript/module/src/MarcusTextInputDecoratorViewNativeComponent.d.ts.map +1 -1
- package/lib/typescript/module/src/MarkdownText.d.ts +127 -0
- package/lib/typescript/module/src/MarkdownText.d.ts.map +1 -0
- package/lib/typescript/module/src/MarkdownText.web.d.ts +126 -0
- package/lib/typescript/module/src/MarkdownText.web.d.ts.map +1 -0
- package/lib/typescript/module/src/MarkdownTextInput.d.ts +23 -1
- package/lib/typescript/module/src/MarkdownTextInput.d.ts.map +1 -1
- package/lib/typescript/module/src/MarkdownTextInput.web.d.ts +26 -4
- package/lib/typescript/module/src/MarkdownTextInput.web.d.ts.map +1 -1
- package/lib/typescript/module/src/atomUtils.d.ts +58 -0
- package/lib/typescript/module/src/atomUtils.d.ts.map +1 -0
- package/lib/typescript/module/src/childrenUtils.d.ts +12 -0
- package/lib/typescript/module/src/childrenUtils.d.ts.map +1 -0
- package/lib/typescript/module/src/commonTypes.d.ts +39 -3
- package/lib/typescript/module/src/commonTypes.d.ts.map +1 -1
- package/lib/typescript/module/src/index.d.ts +2 -1
- package/lib/typescript/module/src/index.d.ts.map +1 -1
- package/lib/typescript/module/src/math/environment.d.ts +7 -0
- package/lib/typescript/module/src/math/environment.d.ts.map +1 -0
- package/lib/typescript/module/src/math/index.d.ts +64 -0
- package/lib/typescript/module/src/math/index.d.ts.map +1 -0
- package/lib/typescript/module/src/math/mathjax.d.ts +63 -0
- package/lib/typescript/module/src/math/mathjax.d.ts.map +1 -0
- package/lib/typescript/module/src/metro.d.ts +59 -0
- package/lib/typescript/module/src/metro.d.ts.map +1 -0
- package/lib/typescript/module/src/parser/index.d.ts +3 -3
- package/lib/typescript/module/src/parser/index.d.ts.map +1 -1
- package/lib/typescript/module/src/parser/micromark-extension-mentions.d.ts.map +1 -1
- package/lib/typescript/module/src/rangeUtils.d.ts +1 -1
- package/lib/typescript/module/src/stripUtils.d.ts +108 -0
- package/lib/typescript/module/src/stripUtils.d.ts.map +1 -0
- package/lib/typescript/module/src/styleUtils.d.ts +62 -4
- package/lib/typescript/module/src/styleUtils.d.ts.map +1 -1
- package/lib/typescript/module/src/web/utils/blockLayout.d.ts +32 -4
- package/lib/typescript/module/src/web/utils/blockLayout.d.ts.map +1 -1
- package/lib/typescript/module/src/web/utils/blockUtils.d.ts +20 -8
- package/lib/typescript/module/src/web/utils/blockUtils.d.ts.map +1 -1
- package/lib/typescript/module/src/web/utils/elementUtils.d.ts +37 -0
- package/lib/typescript/module/src/web/utils/elementUtils.d.ts.map +1 -0
- package/lib/typescript/module/src/web/utils/parserUtils.d.ts +5 -5
- package/lib/typescript/module/src/web/utils/parserUtils.d.ts.map +1 -1
- package/lib/typescript/module/src/web/utils/treeUtils.d.ts +6 -1
- package/lib/typescript/module/src/web/utils/treeUtils.d.ts.map +1 -1
- package/lib/typescript/module/src/web/utils/webStyleUtils.d.ts +2 -2
- package/lib/typescript/module/src/web/utils/webStyleUtils.d.ts.map +1 -1
- package/package.json +29 -2
- package/react-native.config.js +8 -1
- package/src/MarcusTextDecoratorViewNativeComponent.ts +199 -0
- package/src/MarcusTextInputDecoratorViewNativeComponent.ts +145 -58
- package/src/MarkdownText.tsx +472 -0
- package/src/MarkdownText.web.tsx +668 -0
- package/src/MarkdownTextInput.tsx +42 -38
- package/src/MarkdownTextInput.web.tsx +36 -13
- package/src/atomUtils.ts +112 -0
- package/src/childrenUtils.ts +39 -0
- package/src/commonTypes.ts +69 -9
- package/src/index.tsx +2 -1
- package/src/math/environment.ts +68 -0
- package/src/math/index.ts +78 -0
- package/src/math/mathjax.ts +604 -0
- package/src/metro.ts +238 -0
- package/src/parser/index.ts +175 -10
- package/src/parser/micromark-extension-mentions.ts +104 -11
- package/src/stripUtils.ts +919 -0
- package/src/styleUtils.ts +290 -26
- package/src/web/MarkdownElements.css +67 -0
- package/src/web/MarkdownTextInput.css +9 -7
- package/src/web/utils/blockLayout.ts +124 -14
- package/src/web/utils/blockUtils.ts +365 -59
- package/src/web/utils/elementUtils.ts +87 -0
- package/src/web/utils/parserUtils.ts +119 -31
- package/src/web/utils/treeUtils.ts +6 -1
- package/src/web/utils/webStyleUtils.ts +32 -8
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownBackgroundColorSpan.kt +0 -6
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownBoldSpan.kt +0 -6
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownItalicSpan.kt +0 -6
- package/apple/RCTMarcusStyle+Codegen.mm +0 -64
- package/apple/RCTMarcusUtils.h +0 -26
- package/apple/RCTMarcusUtils.mm +0 -26
|
@@ -0,0 +1,739 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
// Removing the markdown syntax from the string before it reaches the platform
|
|
4
|
+
// is what separates the display component from the input one: the input shows
|
|
5
|
+
// what you typed, the display shows what it meant. Everything downstream --
|
|
6
|
+
// measurement, drawing, selection, VoiceOver -- then sees only the text that is
|
|
7
|
+
// meant to be read, without any of the hiding tricks that a formatter would
|
|
8
|
+
// otherwise have to play on characters that are still there.
|
|
9
|
+
//
|
|
10
|
+
// The parser's offsets are into the original string, so cutting characters out
|
|
11
|
+
// invalidates every range it emitted. Both halves happen here, in one pass, so
|
|
12
|
+
// there is never a moment where a range and the string it indexes disagree.
|
|
13
|
+
|
|
14
|
+
/** What an image stood for, for a caller that has something to show instead. */
|
|
15
|
+
|
|
16
|
+
/** A maths span, for a caller that has something to draw it with. */
|
|
17
|
+
|
|
18
|
+
/** A link the display can hand to whatever is going to act on a press. */
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The character standing in for an embed, matching what the platforms use for
|
|
22
|
+
* an attachment so that the stripped text and the string that reaches the
|
|
23
|
+
* formatters are the same length.
|
|
24
|
+
*/
|
|
25
|
+
const OBJECT_REPLACEMENT = "\uFFFC";
|
|
26
|
+
|
|
27
|
+
/** Shared so that the common case of a document with no embeds allocates nothing. */
|
|
28
|
+
const NO_EMBEDS = [];
|
|
29
|
+
|
|
30
|
+
/** Shared for the same reason. */
|
|
31
|
+
const NO_MATHS = [];
|
|
32
|
+
|
|
33
|
+
/** Shared for the same reason. */
|
|
34
|
+
const NO_LINKS = [];
|
|
35
|
+
const TAB = 9;
|
|
36
|
+
const LINE_FEED = 10;
|
|
37
|
+
const CARRIAGE_RETURN = 13;
|
|
38
|
+
const SPACE = 32;
|
|
39
|
+
const GREATER_THAN = 62;
|
|
40
|
+
const LEFT_PAREN = 40;
|
|
41
|
+
const RIGHT_PAREN = 41;
|
|
42
|
+
function isBlank(code) {
|
|
43
|
+
return code === SPACE || code === TAB;
|
|
44
|
+
}
|
|
45
|
+
function isLineBreak(code) {
|
|
46
|
+
return code === LINE_FEED || code === CARRIAGE_RETURN;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Spans of the block markers that survive stripping, in original offsets.
|
|
51
|
+
*
|
|
52
|
+
* A list's marker is the only syntax that carries meaning of its own -- `1.`
|
|
53
|
+
* numbers the item and `-` stands in for a bullet -- so it stays in the string
|
|
54
|
+
* and is laid out the way the input lays it out. A blockquote's `>` says
|
|
55
|
+
* nothing the ribbon beside it does not already say, so it goes.
|
|
56
|
+
*
|
|
57
|
+
* `flushLine` emits a `block-prefix` immediately before the container that owns
|
|
58
|
+
* it, which is the same pairing the native formatters read, so the container is
|
|
59
|
+
* simply the range that follows.
|
|
60
|
+
*/
|
|
61
|
+
function listMarkers(ranges) {
|
|
62
|
+
const markers = [];
|
|
63
|
+
for (let i = 0; i < ranges.length; i++) {
|
|
64
|
+
const range = ranges[i];
|
|
65
|
+
if (range.type !== "block-prefix") {
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
const container = ranges[i + 1];
|
|
69
|
+
if (container && (container.type === "list-ordered" || container.type === "list-unordered")) {
|
|
70
|
+
markers.push({
|
|
71
|
+
start: range.start,
|
|
72
|
+
end: range.start + range.length
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return markers;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Whether a syntax range is a quote marker sitting inside a list's prefix.
|
|
81
|
+
*
|
|
82
|
+
* A prefix is measured from wherever the previous container's marker ended, so
|
|
83
|
+
* the ordered list in `- > 1. ` is handed the whole run `> 1. ` -- quote marker
|
|
84
|
+
* included. Containment alone would therefore keep a `>` that belongs to
|
|
85
|
+
* something else, and `>` is the only block marker that can appear there.
|
|
86
|
+
*/
|
|
87
|
+
function isQuoteMarker(text, start, end) {
|
|
88
|
+
for (let i = start; i < end; i++) {
|
|
89
|
+
if (text.charCodeAt(i) !== GREATER_THAN) {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** The `( ... )` an inline link or image carries, and what it carries in it. */
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* The resources in `text`, in the order they are written.
|
|
100
|
+
*
|
|
101
|
+
* The parser reports the brackets and parentheses as syntax but the destination
|
|
102
|
+
* itself as a `link`, which is right for an input -- the URL is text you can
|
|
103
|
+
* edit -- and wrong for a display, where cutting only the punctuation out of
|
|
104
|
+
* `[text](url)` leaves `texturl`. So the whole run between the markers goes,
|
|
105
|
+
* and reading it on the way past is what leaves something to hand a press
|
|
106
|
+
* handler afterwards.
|
|
107
|
+
*
|
|
108
|
+
* `(` is emitted as syntax only by `resourceMarker`, so there is nothing else
|
|
109
|
+
* this can match, and one resource cannot hold another: the inner parentheses
|
|
110
|
+
* of `[a](b(c))` are part of the destination rather than markers of their own.
|
|
111
|
+
* Reference links and their definitions are not covered: their label is
|
|
112
|
+
* punctuation around prose the way emphasis is, and telling `[text]` a
|
|
113
|
+
* reference from `[text]` a label needs more than the ranges carry.
|
|
114
|
+
*/
|
|
115
|
+
function resourceSpans(text, ranges) {
|
|
116
|
+
const spans = [];
|
|
117
|
+
let current = null;
|
|
118
|
+
for (const range of ranges) {
|
|
119
|
+
if (range.type === "syntax" && range.length === 1) {
|
|
120
|
+
const code = text.charCodeAt(range.start);
|
|
121
|
+
if (code === LEFT_PAREN) {
|
|
122
|
+
current = {
|
|
123
|
+
open: range.start,
|
|
124
|
+
close: -1,
|
|
125
|
+
uri: "",
|
|
126
|
+
title: ""
|
|
127
|
+
};
|
|
128
|
+
} else if (code === RIGHT_PAREN && current !== null) {
|
|
129
|
+
current.close = range.start;
|
|
130
|
+
spans.push(current);
|
|
131
|
+
current = null;
|
|
132
|
+
}
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// A destination and a title are emitted between the two markers, so
|
|
137
|
+
// whichever resource is open is the one they belong to. Anything else that
|
|
138
|
+
// arrives in between -- a container flushed at a line break inside a title
|
|
139
|
+
// -- is neither and is passed over.
|
|
140
|
+
if (current === null) {
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
if (range.type === "link") {
|
|
144
|
+
current.uri = text.slice(range.start, range.start + range.length);
|
|
145
|
+
} else if (range.type === "title") {
|
|
146
|
+
current.title = text.slice(range.start, range.start + range.length);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return spans;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/** Marks every resource for removal, markers and all. */
|
|
153
|
+
function cutResources(resources, cut) {
|
|
154
|
+
let cutSomething = false;
|
|
155
|
+
for (const resource of resources) {
|
|
156
|
+
for (let i = resource.open; i <= resource.close; i++) {
|
|
157
|
+
cut[i] = 1;
|
|
158
|
+
cutSomething = true;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return cutSomething;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Whether anything but block markers shares a line with the character at
|
|
166
|
+
* `index`.
|
|
167
|
+
*
|
|
168
|
+
* Read off the stripped text, which is the text that will be laid out: by this
|
|
169
|
+
* point a quote's marker is gone entirely and a list's is a `block-prefix`
|
|
170
|
+
* range over characters that were kept to be laid out rather than read.
|
|
171
|
+
*/
|
|
172
|
+
function sharesItsLine(text, prefixes, index) {
|
|
173
|
+
let start = index;
|
|
174
|
+
while (start > 0 && !isLineBreak(text.charCodeAt(start - 1))) {
|
|
175
|
+
start--;
|
|
176
|
+
}
|
|
177
|
+
let end = index;
|
|
178
|
+
while (end < text.length && !isLineBreak(text.charCodeAt(end))) {
|
|
179
|
+
end++;
|
|
180
|
+
}
|
|
181
|
+
for (let i = start; i < end; i++) {
|
|
182
|
+
if (i === index || isBlank(text.charCodeAt(i))) {
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
if (prefixes.some(prefix => i >= prefix.start && i < prefix.start + prefix.length)) {
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
return true;
|
|
189
|
+
}
|
|
190
|
+
return false;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/** The characters of a span that survive the cut, which is CommonMark's `alt`. */
|
|
194
|
+
function flatten(text, cut, start, end) {
|
|
195
|
+
let flattened = "";
|
|
196
|
+
let segmentStart = start;
|
|
197
|
+
for (let i = start; i < end; i++) {
|
|
198
|
+
if (cut[i] === 1) {
|
|
199
|
+
if (segmentStart < i) {
|
|
200
|
+
flattened += text.slice(segmentStart, i);
|
|
201
|
+
}
|
|
202
|
+
segmentStart = i + 1;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return segmentStart < end ? flattened + text.slice(segmentStart, end) : flattened;
|
|
206
|
+
}
|
|
207
|
+
/** Shared for the same reason `NO_EMBEDS` is. */
|
|
208
|
+
const NO_IMAGES = [];
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* The images in `text`, with the three things a renderer needs to show one.
|
|
212
|
+
*
|
|
213
|
+
* Read straight off the ranges, because the parser has already made an image
|
|
214
|
+
* flat: inside a label it emits nothing but the `syntax` the markup is spelled
|
|
215
|
+
* with and one `alt` range over the lot. So there is exactly one `link`
|
|
216
|
+
* range in a span -- the destination -- and no image nested in another, and
|
|
217
|
+
* neither case needs guarding here.
|
|
218
|
+
*
|
|
219
|
+
* `alt` still has to be flattened, since a single range cannot skip the `**` in
|
|
220
|
+
* ``. `cut` is what does it: it already marks every character the
|
|
221
|
+
* strip is removing, so reading the label through it gives exactly the string
|
|
222
|
+
* CommonMark would have put in the attribute.
|
|
223
|
+
*/
|
|
224
|
+
function imageSpans(text, ranges, cut) {
|
|
225
|
+
const spans = [];
|
|
226
|
+
for (let i = 0; i < ranges.length; i++) {
|
|
227
|
+
const image = ranges[i];
|
|
228
|
+
if (image.type !== "image") {
|
|
229
|
+
continue;
|
|
230
|
+
}
|
|
231
|
+
const start = image.start;
|
|
232
|
+
const end = Math.min(start + image.length, text.length);
|
|
233
|
+
const span = {
|
|
234
|
+
start,
|
|
235
|
+
end,
|
|
236
|
+
uri: "",
|
|
237
|
+
alt: "",
|
|
238
|
+
title: ""
|
|
239
|
+
};
|
|
240
|
+
for (let j = i + 1; j < ranges.length; j++) {
|
|
241
|
+
const inner = ranges[j];
|
|
242
|
+
const innerEnd = inner.start + inner.length;
|
|
243
|
+
|
|
244
|
+
// Ranges are not sorted -- a container is emitted after the content of
|
|
245
|
+
// the line it encloses -- so anything reaching past the image is one of
|
|
246
|
+
// those and is skipped rather than ending the walk.
|
|
247
|
+
if (inner.start >= end) {
|
|
248
|
+
break;
|
|
249
|
+
}
|
|
250
|
+
if (innerEnd > end) {
|
|
251
|
+
continue;
|
|
252
|
+
}
|
|
253
|
+
if (inner.type === "alt") {
|
|
254
|
+
span.alt = flatten(text, cut, inner.start, innerEnd);
|
|
255
|
+
} else if (inner.type === "link") {
|
|
256
|
+
span.uri = text.slice(inner.start, innerEnd);
|
|
257
|
+
} else if (inner.type === "title") {
|
|
258
|
+
span.title = text.slice(inner.start, innerEnd);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
spans.push(span);
|
|
262
|
+
}
|
|
263
|
+
return spans;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* The bounds of every maths span, whether or not the caller means to render one.
|
|
268
|
+
*
|
|
269
|
+
* A display with nothing to draw maths with keeps `$x^2$` exactly as it was
|
|
270
|
+
* written: cutting only the dollars would leave `x^2`, which is neither the
|
|
271
|
+
* markdown nor the maths, and TeX read as prose is worse than TeX read as TeX.
|
|
272
|
+
* So the delimiters inside these bounds are spared the syntax cut.
|
|
273
|
+
*/
|
|
274
|
+
function mathBounds(ranges) {
|
|
275
|
+
const bounds = [];
|
|
276
|
+
for (const range of ranges) {
|
|
277
|
+
if (range.type === "math" || range.type === "math-block") {
|
|
278
|
+
bounds.push({
|
|
279
|
+
start: range.start,
|
|
280
|
+
end: range.start + range.length
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
return bounds;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/** A maths span as the strip sees it, before the offsets move. */
|
|
288
|
+
|
|
289
|
+
/** Shared for the same reason `NO_EMBEDS` is. */
|
|
290
|
+
const NO_MATH_SPANS = [];
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* The maths spans in `text`, with the TeX each one carries.
|
|
294
|
+
*
|
|
295
|
+
* Nothing has to be walked for the content: the parser makes a maths span
|
|
296
|
+
* opaque -- one range over the lot and `syntax` over the delimiters, and
|
|
297
|
+
* nothing at all for what is between them -- so the TeX is simply the
|
|
298
|
+
* characters the strip is not already removing. `cut` is what says which those
|
|
299
|
+
* are, which is why this runs at the same moment `imageSpans` does: after the
|
|
300
|
+
* syntax has been marked and before the spans themselves are.
|
|
301
|
+
*
|
|
302
|
+
* A `$$` block is trimmed because its delimiters sit on lines of their own, so
|
|
303
|
+
* what survives between them opens and closes with a line break.
|
|
304
|
+
*/
|
|
305
|
+
function mathSpans(text, ranges, cut) {
|
|
306
|
+
const spans = [];
|
|
307
|
+
for (const range of ranges) {
|
|
308
|
+
if (range.type !== "math" && range.type !== "math-block") {
|
|
309
|
+
continue;
|
|
310
|
+
}
|
|
311
|
+
const start = range.start;
|
|
312
|
+
const end = Math.min(start + range.length, text.length);
|
|
313
|
+
const tex = flatten(text, cut, start, end).trim();
|
|
314
|
+
|
|
315
|
+
// `$$` with nothing in it is punctuation, not maths. Left as it was
|
|
316
|
+
// written rather than turned into a placeholder standing for nothing.
|
|
317
|
+
if (tex === "") {
|
|
318
|
+
continue;
|
|
319
|
+
}
|
|
320
|
+
spans.push({
|
|
321
|
+
start,
|
|
322
|
+
end,
|
|
323
|
+
tex,
|
|
324
|
+
display: range.type === "math-block"
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
return spans;
|
|
328
|
+
}
|
|
329
|
+
/** Shared for the same reason `NO_EMBEDS` is. */
|
|
330
|
+
const NO_LINK_SPANS = [];
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* The links in `text`, as the text that will be left of each and where it
|
|
334
|
+
* points.
|
|
335
|
+
*
|
|
336
|
+
* A written link is a label followed immediately by a resource, so the label is
|
|
337
|
+
* the one that opens at `](`. A label with no resource after it is a reference
|
|
338
|
+
* or a shortcut, and nothing here can resolve one: it is still styled as a link
|
|
339
|
+
* -- that much the ranges say -- but there is no destination to press it to.
|
|
340
|
+
*
|
|
341
|
+
* An autolink has no label at all and is its own text, so any `link` left over
|
|
342
|
+
* is one. Left over means outside every resource: the destinations are `link`
|
|
343
|
+
* ranges too, and each has already been taken by the label in front of it or
|
|
344
|
+
* belongs to an image, which has no label to press. The exception is a
|
|
345
|
+
* definition's destination -- `[ref]: https://example.com` -- which is written
|
|
346
|
+
* plainly, is shown as written, and is treated as what it looks like.
|
|
347
|
+
*/
|
|
348
|
+
function linkSpans(text, ranges, resources) {
|
|
349
|
+
const spans = [];
|
|
350
|
+
for (const range of ranges) {
|
|
351
|
+
const end = range.start + range.length;
|
|
352
|
+
let span = null;
|
|
353
|
+
if (range.type === "label") {
|
|
354
|
+
const resource = resources.find(candidate => candidate.open === end + 1);
|
|
355
|
+
if (resource !== undefined) {
|
|
356
|
+
span = {
|
|
357
|
+
start: range.start,
|
|
358
|
+
end,
|
|
359
|
+
uri: resource.uri,
|
|
360
|
+
title: resource.title
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
} else if (range.type === "link" && !resources.some(resource => range.start > resource.open && range.start < resource.close)) {
|
|
364
|
+
span = {
|
|
365
|
+
start: range.start,
|
|
366
|
+
end,
|
|
367
|
+
uri: text.slice(range.start, end),
|
|
368
|
+
title: ""
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
if (span === null) {
|
|
372
|
+
continue;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// A link cannot hold another one, but micromark still reports the construct
|
|
376
|
+
// it finds inside a label: `[see <https://x.com>](y)` arrives as a label
|
|
377
|
+
// with an autolink in it. A label is emitted before its own content, so the
|
|
378
|
+
// one that encloses the other is the one already here -- and it is the one
|
|
379
|
+
// to keep, being the whole of what the reader is shown. Two of them would
|
|
380
|
+
// be worse than a wrong choice: the caller splices the text at these, and
|
|
381
|
+
// spans that overlap would splice the run they share in twice.
|
|
382
|
+
if (spans.length > 0 && span.start < spans[spans.length - 1].end) {
|
|
383
|
+
continue;
|
|
384
|
+
}
|
|
385
|
+
spans.push(span);
|
|
386
|
+
}
|
|
387
|
+
return spans;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* The spans as offsets into the stripped text, carrying the label they now
|
|
392
|
+
* cover. `offsets` is null when nothing was cut and the two texts are the same.
|
|
393
|
+
*/
|
|
394
|
+
function toLinks(text, spans, offsets) {
|
|
395
|
+
if (spans.length === 0) {
|
|
396
|
+
return NO_LINKS;
|
|
397
|
+
}
|
|
398
|
+
const links = [];
|
|
399
|
+
for (const span of spans) {
|
|
400
|
+
const start = offsets === null ? span.start : offsets[span.start];
|
|
401
|
+
const end = offsets === null ? span.end : offsets[span.end];
|
|
402
|
+
|
|
403
|
+
// A label that was nothing but markup -- `[**](x)` -- has nothing left to
|
|
404
|
+
// press.
|
|
405
|
+
if (end <= start) {
|
|
406
|
+
continue;
|
|
407
|
+
}
|
|
408
|
+
links.push({
|
|
409
|
+
start,
|
|
410
|
+
length: end - start,
|
|
411
|
+
uri: span.uri,
|
|
412
|
+
label: text.slice(start, end),
|
|
413
|
+
title: span.title
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
return links;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
/**
|
|
420
|
+
* A span that collapses to a single placeholder character, of either kind.
|
|
421
|
+
*
|
|
422
|
+
* Images and maths are the same problem -- a run of markdown that the display
|
|
423
|
+
* does not read but draws, and that costs the platform exactly one character --
|
|
424
|
+
* so they go through one set of machinery. Sorting by offset is enough to put
|
|
425
|
+
* them back in emission order: both are emitted from the parser as they are
|
|
426
|
+
* met, and neither can contain the other.
|
|
427
|
+
*/
|
|
428
|
+
|
|
429
|
+
/** Shared for the same reason `NO_EMBEDS` is. */
|
|
430
|
+
const NO_ATOMS = [];
|
|
431
|
+
function atomsOf(images, maths) {
|
|
432
|
+
if (images.length === 0) {
|
|
433
|
+
return maths.length === 0 ? NO_ATOMS : maths;
|
|
434
|
+
}
|
|
435
|
+
if (maths.length === 0) {
|
|
436
|
+
return images;
|
|
437
|
+
}
|
|
438
|
+
return [...images, ...maths].sort((a, b) => a.start - b.start);
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
/** Whether a range is one that stands for an atom rather than describing text. */
|
|
442
|
+
function isAtomType(type) {
|
|
443
|
+
return type === "image" || type === "math" || type === "math-block";
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* Widens the cuts already marked on a line to cover the whitespace that only
|
|
448
|
+
* existed to separate a marker from what it marked.
|
|
449
|
+
*
|
|
450
|
+
* A line opens with a run of block markers and the blanks between them. Walking
|
|
451
|
+
* that run, a blank goes only if the marker in front of it went: `# Title` and
|
|
452
|
+
* `> - item` lose their spacing, `- item` keeps the one its bullet needs.
|
|
453
|
+
*
|
|
454
|
+
* A line that turns out to be nothing but removed markers takes its own line
|
|
455
|
+
* break with it, so a setext underline or a thematic break does not leave a
|
|
456
|
+
* blank line behind.
|
|
457
|
+
*/
|
|
458
|
+
function absorbMarkerSpacing(text, cut, marker) {
|
|
459
|
+
let lineStart = 0;
|
|
460
|
+
while (lineStart <= text.length) {
|
|
461
|
+
let lineEnd = lineStart;
|
|
462
|
+
while (lineEnd < text.length) {
|
|
463
|
+
const code = text.charCodeAt(lineEnd);
|
|
464
|
+
if (code === LINE_FEED || code === CARRIAGE_RETURN) {
|
|
465
|
+
break;
|
|
466
|
+
}
|
|
467
|
+
lineEnd++;
|
|
468
|
+
}
|
|
469
|
+
let cursor = lineStart;
|
|
470
|
+
let cutSomething = false;
|
|
471
|
+
let keptMarker = false;
|
|
472
|
+
let afterCut = false;
|
|
473
|
+
while (cursor < lineEnd) {
|
|
474
|
+
const blank = isBlank(text.charCodeAt(cursor));
|
|
475
|
+
if (cut[cursor] === 1) {
|
|
476
|
+
cutSomething = true;
|
|
477
|
+
afterCut = true;
|
|
478
|
+
} else if (blank) {
|
|
479
|
+
if (afterCut) {
|
|
480
|
+
cut[cursor] = 1;
|
|
481
|
+
}
|
|
482
|
+
} else if (marker[cursor] === 1) {
|
|
483
|
+
keptMarker = true;
|
|
484
|
+
afterCut = false;
|
|
485
|
+
} else {
|
|
486
|
+
break;
|
|
487
|
+
}
|
|
488
|
+
cursor++;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
// Nothing readable left on the line, and no marker worth keeping either.
|
|
492
|
+
if (cursor >= lineEnd && cutSomething && !keptMarker) {
|
|
493
|
+
for (let i = lineStart; i < lineEnd; i++) {
|
|
494
|
+
cut[i] = 1;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
// The break in front, for any line but the first, which has none and
|
|
498
|
+
// takes the one behind instead.
|
|
499
|
+
if (lineStart > 0) {
|
|
500
|
+
let index = lineStart - 1;
|
|
501
|
+
if (text.charCodeAt(index) === LINE_FEED) {
|
|
502
|
+
cut[index] = 1;
|
|
503
|
+
index--;
|
|
504
|
+
}
|
|
505
|
+
if (index >= 0 && text.charCodeAt(index) === CARRIAGE_RETURN) {
|
|
506
|
+
cut[index] = 1;
|
|
507
|
+
}
|
|
508
|
+
} else {
|
|
509
|
+
let index = lineEnd;
|
|
510
|
+
if (text.charCodeAt(index) === CARRIAGE_RETURN) {
|
|
511
|
+
cut[index] = 1;
|
|
512
|
+
index++;
|
|
513
|
+
}
|
|
514
|
+
if (text.charCodeAt(index) === LINE_FEED) {
|
|
515
|
+
cut[index] = 1;
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
if (lineEnd >= text.length) {
|
|
520
|
+
break;
|
|
521
|
+
}
|
|
522
|
+
lineStart = lineEnd;
|
|
523
|
+
if (text.charCodeAt(lineStart) === CARRIAGE_RETURN) {
|
|
524
|
+
lineStart++;
|
|
525
|
+
}
|
|
526
|
+
if (text.charCodeAt(lineStart) === LINE_FEED) {
|
|
527
|
+
lineStart++;
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
/**
|
|
533
|
+
* What a type means once the markup around it is gone.
|
|
534
|
+
*
|
|
535
|
+
* A link's label is the one type that changes. While it is being edited it is
|
|
536
|
+
* text between two brackets and is left alone; once the brackets have been
|
|
537
|
+
* removed it is the only thing left standing for the link, so it takes the
|
|
538
|
+
* link's styling -- the destination it was pointing at having been removed too.
|
|
539
|
+
*/
|
|
540
|
+
function displayType(type) {
|
|
541
|
+
return type === "label" ? "link" : type;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
/**
|
|
545
|
+
* Removes the markdown syntax from `text` and rewrites `ranges` to index what
|
|
546
|
+
* is left.
|
|
547
|
+
*
|
|
548
|
+
* Ranges are only ever dropped or shortened, never reordered, so the emission
|
|
549
|
+
* order the native formatters depend on survives -- a `block-prefix` still
|
|
550
|
+
* arrives immediately before its container, and a container that lost its
|
|
551
|
+
* marker entirely arrives with none, which is exactly the gutter-without-marker
|
|
552
|
+
* case the block layout already handles.
|
|
553
|
+
*/
|
|
554
|
+
function stripSyntax(text, ranges, options = {}) {
|
|
555
|
+
if (text.length === 0 || ranges.length === 0) {
|
|
556
|
+
return {
|
|
557
|
+
text,
|
|
558
|
+
ranges,
|
|
559
|
+
embeds: NO_EMBEDS,
|
|
560
|
+
maths: NO_MATHS,
|
|
561
|
+
links: NO_LINKS
|
|
562
|
+
};
|
|
563
|
+
}
|
|
564
|
+
const markers = listMarkers(ranges);
|
|
565
|
+
// Only when there is nothing to draw maths with: otherwise the spans are cut
|
|
566
|
+
// whole a few lines down and sparing their dollars would be pointless work.
|
|
567
|
+
const spared = options.math ? [] : mathBounds(ranges);
|
|
568
|
+
const cut = new Uint8Array(text.length);
|
|
569
|
+
const kept = new Uint8Array(text.length);
|
|
570
|
+
let cutSomething = false;
|
|
571
|
+
for (const range of ranges) {
|
|
572
|
+
// A fenced block's language is metadata about the block, not part of it, so
|
|
573
|
+
// it goes the same way the fence itself does.
|
|
574
|
+
if (range.type !== "syntax" && range.type !== "language") {
|
|
575
|
+
continue;
|
|
576
|
+
}
|
|
577
|
+
const start = range.start;
|
|
578
|
+
const end = Math.min(start + range.length, text.length);
|
|
579
|
+
if (spared.some(span => start >= span.start && end <= span.end)) {
|
|
580
|
+
continue;
|
|
581
|
+
}
|
|
582
|
+
const inListMarker = range.type === "syntax" && markers.some(marker => start >= marker.start && end <= marker.end) && !isQuoteMarker(text, start, end);
|
|
583
|
+
for (let i = start; i < end; i++) {
|
|
584
|
+
if (inListMarker) {
|
|
585
|
+
kept[i] = 1;
|
|
586
|
+
} else {
|
|
587
|
+
cut[i] = 1;
|
|
588
|
+
cutSomething = true;
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
const resources = resourceSpans(text, ranges);
|
|
593
|
+
const links = options.links ? linkSpans(text, ranges, resources) : NO_LINK_SPANS;
|
|
594
|
+
cutSomething = cutResources(resources, cut) || cutSomething;
|
|
595
|
+
|
|
596
|
+
// An image goes whole -- markup, alt text and destination alike -- and leaves
|
|
597
|
+
// one character behind. Keeping one of its own characters rather than
|
|
598
|
+
// splicing a new one in is what lets the offsets below stay as they are: a
|
|
599
|
+
// range is still only ever shortened, never moved.
|
|
600
|
+
// After the cuts above and before the images are cut themselves, which is the
|
|
601
|
+
// one moment `cut` describes the markup inside a label without describing the
|
|
602
|
+
// label's own removal -- exactly what flattening the alt text needs.
|
|
603
|
+
const images = options.embeds ? imageSpans(text, ranges, cut) : NO_IMAGES;
|
|
604
|
+
const maths = options.math ? mathSpans(text, ranges, cut) : NO_MATH_SPANS;
|
|
605
|
+
const atoms = atomsOf(images, maths);
|
|
606
|
+
const placeholder = atoms.length > 0 ? new Uint8Array(text.length) : null;
|
|
607
|
+
for (const atom of atoms) {
|
|
608
|
+
for (let i = atom.start; i < atom.end; i++) {
|
|
609
|
+
cut[i] = 1;
|
|
610
|
+
// 1 for a character the atom swallowed, 2 for the one it left behind.
|
|
611
|
+
placeholder[i] = 1;
|
|
612
|
+
}
|
|
613
|
+
cut[atom.start] = 0;
|
|
614
|
+
placeholder[atom.start] = 2;
|
|
615
|
+
cutSomething = true;
|
|
616
|
+
}
|
|
617
|
+
if (!cutSomething) {
|
|
618
|
+
// Nothing moved, so the spans already index the text as it stands. A bare
|
|
619
|
+
// URL gets here: it is a link written with no syntax at all.
|
|
620
|
+
return {
|
|
621
|
+
text,
|
|
622
|
+
ranges,
|
|
623
|
+
embeds: NO_EMBEDS,
|
|
624
|
+
maths: NO_MATHS,
|
|
625
|
+
links: toLinks(text, links, null)
|
|
626
|
+
};
|
|
627
|
+
}
|
|
628
|
+
absorbMarkerSpacing(text, cut, kept);
|
|
629
|
+
|
|
630
|
+
// Kept characters before each offset, which is where that offset lands once
|
|
631
|
+
// the cuts are gone. One extra entry so a range's end can be mapped the same
|
|
632
|
+
// way as its start.
|
|
633
|
+
const offsets = new Int32Array(text.length + 1);
|
|
634
|
+
let stripped = "";
|
|
635
|
+
let segmentStart = 0;
|
|
636
|
+
let survivors = 0;
|
|
637
|
+
for (let i = 0; i < text.length; i++) {
|
|
638
|
+
offsets[i] = survivors;
|
|
639
|
+
if (placeholder !== null && placeholder[i] === 2) {
|
|
640
|
+
if (segmentStart < i) {
|
|
641
|
+
stripped += text.slice(segmentStart, i);
|
|
642
|
+
}
|
|
643
|
+
stripped += OBJECT_REPLACEMENT;
|
|
644
|
+
segmentStart = i + 1;
|
|
645
|
+
survivors++;
|
|
646
|
+
} else if (cut[i] === 1) {
|
|
647
|
+
if (segmentStart < i) {
|
|
648
|
+
stripped += text.slice(segmentStart, i);
|
|
649
|
+
}
|
|
650
|
+
segmentStart = i + 1;
|
|
651
|
+
} else {
|
|
652
|
+
survivors++;
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
offsets[text.length] = survivors;
|
|
656
|
+
if (segmentStart < text.length) {
|
|
657
|
+
stripped += text.slice(segmentStart);
|
|
658
|
+
}
|
|
659
|
+
const remapped = [];
|
|
660
|
+
// The atom being walked past, if any: everything it swallowed goes with it,
|
|
661
|
+
// save its own range, which shrinks onto the character left behind. Without
|
|
662
|
+
// this the `syntax` over the `!` of an image or the opening `$` of a maths
|
|
663
|
+
// span -- the very character kept as the placeholder -- would survive to
|
|
664
|
+
// style what stands there as markup.
|
|
665
|
+
//
|
|
666
|
+
// Swallowed means emitted after the atom opened and ending inside it, which
|
|
667
|
+
// is what tells the alt text apart from the two kinds of range that reach
|
|
668
|
+
// over an atom and have to survive: the label of a link written around an
|
|
669
|
+
// image, which is emitted before it, and the container of the line it sits
|
|
670
|
+
// on, which is emitted after and runs past its end.
|
|
671
|
+
let atom = 0;
|
|
672
|
+
let insideStart = -1;
|
|
673
|
+
let insideEnd = -1;
|
|
674
|
+
for (const range of ranges) {
|
|
675
|
+
// One span per atom range, in the order they were emitted, so the two walks
|
|
676
|
+
// stay in step. Matched on the offset as well as the type, because a kind
|
|
677
|
+
// of atom the caller did not ask for is not one: an `image` range with no
|
|
678
|
+
// `renderEmbed` behind it is still just a range.
|
|
679
|
+
if (atom < atoms.length && isAtomType(range.type) && range.start === atoms[atom].start) {
|
|
680
|
+
insideStart = atoms[atom].start;
|
|
681
|
+
insideEnd = atoms[atom].end;
|
|
682
|
+
atom++;
|
|
683
|
+
} else if (range.start >= insideStart && range.start + range.length <= insideEnd) {
|
|
684
|
+
continue;
|
|
685
|
+
}
|
|
686
|
+
let start = offsets[Math.min(range.start, text.length)];
|
|
687
|
+
const end = offsets[Math.min(range.start + range.length, text.length)];
|
|
688
|
+
|
|
689
|
+
// A fenced block opens with a line of its own, and cutting that line leaves
|
|
690
|
+
// the break that ended it at the front of the block. What is left then
|
|
691
|
+
// starts on the line above the code, which is a blank first line in
|
|
692
|
+
// whatever draws the block as a box.
|
|
693
|
+
if (range.type === "codeblock") {
|
|
694
|
+
while (start < end && isLineBreak(stripped.charCodeAt(start))) {
|
|
695
|
+
start++;
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
if (end <= start) {
|
|
699
|
+
continue;
|
|
700
|
+
}
|
|
701
|
+
const next = {
|
|
702
|
+
type: displayType(range.type),
|
|
703
|
+
start,
|
|
704
|
+
length: end - start
|
|
705
|
+
};
|
|
706
|
+
if (range.depth !== undefined) {
|
|
707
|
+
next.depth = range.depth;
|
|
708
|
+
}
|
|
709
|
+
remapped.push(next);
|
|
710
|
+
}
|
|
711
|
+
const prefixes = atoms.length > 0 ? remapped.filter(range => range.type === "block-prefix") : [];
|
|
712
|
+
const embeds = images.length > 0 ? images.map(image => {
|
|
713
|
+
const index = offsets[image.start];
|
|
714
|
+
return {
|
|
715
|
+
index,
|
|
716
|
+
uri: image.uri,
|
|
717
|
+
alt: image.alt,
|
|
718
|
+
title: image.title,
|
|
719
|
+
inline: sharesItsLine(stripped, prefixes, index)
|
|
720
|
+
};
|
|
721
|
+
}) : NO_EMBEDS;
|
|
722
|
+
const mathsOut = maths.length > 0 ? maths.map(span => {
|
|
723
|
+
const index = offsets[span.start];
|
|
724
|
+
return {
|
|
725
|
+
index,
|
|
726
|
+
tex: span.tex,
|
|
727
|
+
display: span.display
|
|
728
|
+
};
|
|
729
|
+
}) : NO_MATHS;
|
|
730
|
+
return {
|
|
731
|
+
text: stripped,
|
|
732
|
+
ranges: remapped,
|
|
733
|
+
embeds,
|
|
734
|
+
maths: mathsOut,
|
|
735
|
+
links: toLinks(stripped, links, offsets)
|
|
736
|
+
};
|
|
737
|
+
}
|
|
738
|
+
export { OBJECT_REPLACEMENT, stripSyntax };
|
|
739
|
+
//# sourceMappingURL=stripUtils.js.map
|