react-native-nitro-markdown 0.7.2 → 0.8.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 +66 -4
- package/ios/HybridMarkdownSession.swift +11 -4
- package/lib/commonjs/MarkdownContext.js +1 -3
- package/lib/commonjs/MarkdownContext.js.map +1 -1
- package/lib/commonjs/index.js +6 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/markdown-stream.js +80 -29
- package/lib/commonjs/markdown-stream.js.map +1 -1
- package/lib/commonjs/markdown.js +94 -37
- package/lib/commonjs/markdown.js.map +1 -1
- package/lib/commonjs/renderers/image.js +2 -2
- package/lib/commonjs/renderers/image.js.map +1 -1
- package/lib/commonjs/renderers/math.js +6 -2
- package/lib/commonjs/renderers/math.js.map +1 -1
- package/lib/commonjs/renderers/table/index.js +4 -4
- package/lib/commonjs/renderers/table/index.js.map +1 -1
- package/lib/commonjs/renderers/table/table-utils.js +1 -1
- package/lib/commonjs/renderers/table/table-utils.js.map +1 -1
- package/lib/commonjs/utils/code-highlight.js +1 -1
- package/lib/commonjs/utils/code-highlight.js.map +1 -1
- package/lib/commonjs/utils/incremental-ast.js +24 -11
- package/lib/commonjs/utils/incremental-ast.js.map +1 -1
- package/lib/commonjs/utils/link-security.js +2 -2
- package/lib/commonjs/utils/link-security.js.map +1 -1
- package/lib/commonjs/utils/stream-timeline.js +13 -7
- package/lib/commonjs/utils/stream-timeline.js.map +1 -1
- package/lib/module/MarkdownContext.js +1 -3
- package/lib/module/MarkdownContext.js.map +1 -1
- package/lib/module/index.js +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/markdown-stream.js +79 -29
- package/lib/module/markdown-stream.js.map +1 -1
- package/lib/module/markdown.js +94 -37
- package/lib/module/markdown.js.map +1 -1
- package/lib/module/renderers/image.js +2 -2
- package/lib/module/renderers/image.js.map +1 -1
- package/lib/module/renderers/math.js +6 -2
- package/lib/module/renderers/math.js.map +1 -1
- package/lib/module/renderers/table/index.js +4 -4
- package/lib/module/renderers/table/index.js.map +1 -1
- package/lib/module/renderers/table/table-utils.js +1 -1
- package/lib/module/renderers/table/table-utils.js.map +1 -1
- package/lib/module/utils/code-highlight.js +1 -1
- package/lib/module/utils/code-highlight.js.map +1 -1
- package/lib/module/utils/incremental-ast.js +24 -11
- package/lib/module/utils/incremental-ast.js.map +1 -1
- package/lib/module/utils/link-security.js +2 -2
- package/lib/module/utils/link-security.js.map +1 -1
- package/lib/module/utils/stream-timeline.js +13 -7
- package/lib/module/utils/stream-timeline.js.map +1 -1
- package/lib/typescript/commonjs/MarkdownContext.d.ts.map +1 -1
- package/lib/typescript/commonjs/index.d.ts +2 -2
- package/lib/typescript/commonjs/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/markdown-stream.d.ts +28 -7
- package/lib/typescript/commonjs/markdown-stream.d.ts.map +1 -1
- package/lib/typescript/commonjs/markdown.d.ts.map +1 -1
- package/lib/typescript/commonjs/utils/incremental-ast.d.ts.map +1 -1
- package/lib/typescript/commonjs/utils/stream-timeline.d.ts.map +1 -1
- package/lib/typescript/module/MarkdownContext.d.ts.map +1 -1
- package/lib/typescript/module/index.d.ts +2 -2
- package/lib/typescript/module/index.d.ts.map +1 -1
- package/lib/typescript/module/markdown-stream.d.ts +28 -7
- package/lib/typescript/module/markdown-stream.d.ts.map +1 -1
- package/lib/typescript/module/markdown.d.ts.map +1 -1
- package/lib/typescript/module/utils/incremental-ast.d.ts.map +1 -1
- package/lib/typescript/module/utils/stream-timeline.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/MarkdownContext.ts +0 -2
- package/src/index.ts +9 -2
- package/src/markdown-stream.tsx +107 -31
- package/src/markdown.tsx +75 -41
- package/src/renderers/image.tsx +2 -2
- package/src/renderers/math.tsx +2 -2
- package/src/renderers/table/index.tsx +4 -4
- package/src/renderers/table/table-utils.ts +1 -1
- package/src/utils/code-highlight.ts +1 -1
- package/src/utils/incremental-ast.ts +25 -9
- package/src/utils/link-security.ts +3 -3
- package/src/utils/stream-timeline.ts +10 -7
package/src/markdown.tsx
CHANGED
|
@@ -34,6 +34,7 @@ import {
|
|
|
34
34
|
type CustomRenderer,
|
|
35
35
|
type CustomRenderers,
|
|
36
36
|
type LinkPressHandler,
|
|
37
|
+
type MarkdownContextValue,
|
|
37
38
|
type NodeRendererProps,
|
|
38
39
|
type TableOptions,
|
|
39
40
|
} from "./MarkdownContext";
|
|
@@ -174,10 +175,8 @@ const warnInDev = (message: string, error?: unknown): void => {
|
|
|
174
175
|
};
|
|
175
176
|
|
|
176
177
|
const cloneMarkdownNode = (node: MarkdownNode): MarkdownNode => {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
children: node.children?.map(cloneMarkdownNode),
|
|
180
|
-
};
|
|
178
|
+
const children = node.children?.map(cloneMarkdownNode);
|
|
179
|
+
return children ? { ...node, children } : { ...node };
|
|
181
180
|
};
|
|
182
181
|
|
|
183
182
|
const getParserOptionsKey = (options?: ParserOptions): string => {
|
|
@@ -204,11 +203,11 @@ const normalizeParserOptions = (
|
|
|
204
203
|
return undefined;
|
|
205
204
|
}
|
|
206
205
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
206
|
+
const normalized: ParserOptions = {};
|
|
207
|
+
if (gfm !== undefined) normalized.gfm = gfm;
|
|
208
|
+
if (math !== undefined) normalized.math = math;
|
|
209
|
+
if (html !== undefined) normalized.html = html;
|
|
210
|
+
return normalized;
|
|
212
211
|
};
|
|
213
212
|
|
|
214
213
|
const parseWithNativeParser = (
|
|
@@ -478,11 +477,14 @@ export const Markdown: FC<MarkdownProps> = ({
|
|
|
478
477
|
const markdownToParse = sourceAst
|
|
479
478
|
? children
|
|
480
479
|
: applyBeforeParsePlugins(children, sortedPlugins, onErrorRef.current);
|
|
481
|
-
const parserOptions = normalizeParserOptions(
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
480
|
+
const parserOptions = normalizeParserOptions(
|
|
481
|
+
Object.assign(
|
|
482
|
+
{},
|
|
483
|
+
parserOptionGfm === undefined ? null : { gfm: parserOptionGfm },
|
|
484
|
+
parserOptionMath === undefined ? null : { math: parserOptionMath },
|
|
485
|
+
parserOptionHtml === undefined ? null : { html: parserOptionHtml },
|
|
486
|
+
),
|
|
487
|
+
);
|
|
486
488
|
const shouldCloneSourceAst =
|
|
487
489
|
sourceAst &&
|
|
488
490
|
(Boolean(astTransform) ||
|
|
@@ -566,16 +568,16 @@ export const Markdown: FC<MarkdownProps> = ({
|
|
|
566
568
|
}, [userTheme, stylingStrategy]);
|
|
567
569
|
|
|
568
570
|
const baseStyles = getBaseStyles(theme);
|
|
569
|
-
const contextValue = useMemo(
|
|
571
|
+
const contextValue = useMemo<MarkdownContextValue>(
|
|
570
572
|
() => ({
|
|
571
573
|
renderers,
|
|
572
574
|
theme,
|
|
573
|
-
styles: nodeStyles,
|
|
574
575
|
stylingStrategy,
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
576
|
+
...(nodeStyles ? { styles: nodeStyles } : {}),
|
|
577
|
+
...(onLinkPress ? { onLinkPress } : {}),
|
|
578
|
+
...(tableOptions ? { tableOptions } : {}),
|
|
579
|
+
...(imageOptions ? { imageOptions } : {}),
|
|
580
|
+
...(highlightCode === undefined ? {} : { highlightCode }),
|
|
579
581
|
}),
|
|
580
582
|
[
|
|
581
583
|
renderers,
|
|
@@ -779,15 +781,18 @@ const NodeRendererComponent: FC<NodeRendererProps> = ({
|
|
|
779
781
|
...(node.type === "heading" && {
|
|
780
782
|
level: (node.level ?? 1) as 1 | 2 | 3 | 4 | 5 | 6,
|
|
781
783
|
}),
|
|
782
|
-
...(node.type === "link" && {
|
|
784
|
+
...(node.type === "link" && {
|
|
785
|
+
href: node.href ?? "",
|
|
786
|
+
...(node.title ? { title: node.title } : {}),
|
|
787
|
+
}),
|
|
783
788
|
...(node.type === "image" && {
|
|
784
789
|
url: node.href ?? "",
|
|
785
|
-
alt: node.alt,
|
|
786
|
-
title: node.title,
|
|
790
|
+
...(node.alt ? { alt: node.alt } : {}),
|
|
791
|
+
...(node.title ? { title: node.title } : {}),
|
|
787
792
|
}),
|
|
788
793
|
...(node.type === "code_block" && {
|
|
789
794
|
content: getTextContent(node),
|
|
790
|
-
language: node.language,
|
|
795
|
+
...(node.language ? { language: node.language } : {}),
|
|
791
796
|
}),
|
|
792
797
|
...(node.type === "code_inline" && { content: node.content ?? "" }),
|
|
793
798
|
...((node.type === "math_inline" || node.type === "math_block") && {
|
|
@@ -795,7 +800,7 @@ const NodeRendererComponent: FC<NodeRendererProps> = ({
|
|
|
795
800
|
}),
|
|
796
801
|
...(node.type === "list" && {
|
|
797
802
|
ordered: node.ordered ?? false,
|
|
798
|
-
start: node.start,
|
|
803
|
+
...(node.start === undefined ? {} : { start: node.start }),
|
|
799
804
|
}),
|
|
800
805
|
...(node.type === "task_list_item" && { checked: node.checked ?? false }),
|
|
801
806
|
};
|
|
@@ -816,7 +821,10 @@ const NodeRendererComponent: FC<NodeRendererProps> = ({
|
|
|
816
821
|
|
|
817
822
|
case "heading":
|
|
818
823
|
return (
|
|
819
|
-
<Heading
|
|
824
|
+
<Heading
|
|
825
|
+
level={node.level ?? 1}
|
|
826
|
+
{...(nodeStyles?.heading ? { style: nodeStyles.heading } : {})}
|
|
827
|
+
>
|
|
820
828
|
{renderChildren(node.children, inListItem, true)}
|
|
821
829
|
</Heading>
|
|
822
830
|
);
|
|
@@ -859,7 +867,10 @@ const NodeRendererComponent: FC<NodeRendererProps> = ({
|
|
|
859
867
|
|
|
860
868
|
case "link":
|
|
861
869
|
return (
|
|
862
|
-
<Link
|
|
870
|
+
<Link
|
|
871
|
+
href={node.href ?? ""}
|
|
872
|
+
{...(nodeStyles?.link ? { style: nodeStyles.link } : {})}
|
|
873
|
+
>
|
|
863
874
|
{renderChildren(node.children, inListItem, true)}
|
|
864
875
|
</Link>
|
|
865
876
|
);
|
|
@@ -868,36 +879,52 @@ const NodeRendererComponent: FC<NodeRendererProps> = ({
|
|
|
868
879
|
return (
|
|
869
880
|
<Image
|
|
870
881
|
url={node.href ?? ""}
|
|
871
|
-
title={node.title}
|
|
872
|
-
alt={node.alt}
|
|
873
882
|
Renderer={NodeRenderer}
|
|
874
|
-
|
|
883
|
+
{...(node.title ? { title: node.title } : {})}
|
|
884
|
+
{...(node.alt ? { alt: node.alt } : {})}
|
|
885
|
+
{...(nodeStyles?.image ? { style: nodeStyles.image } : {})}
|
|
875
886
|
/>
|
|
876
887
|
);
|
|
877
888
|
|
|
878
889
|
case "code_inline":
|
|
879
890
|
return (
|
|
880
|
-
<InlineCode
|
|
891
|
+
<InlineCode
|
|
892
|
+
{...(nodeStyles?.code_inline
|
|
893
|
+
? { style: nodeStyles.code_inline }
|
|
894
|
+
: {})}
|
|
895
|
+
>
|
|
896
|
+
{node.content}
|
|
897
|
+
</InlineCode>
|
|
881
898
|
);
|
|
882
899
|
|
|
883
900
|
case "code_block":
|
|
884
901
|
return (
|
|
885
902
|
<CodeBlock
|
|
886
|
-
language={node.language}
|
|
887
903
|
content={getTextContent(node)}
|
|
888
|
-
|
|
904
|
+
{...(node.language ? { language: node.language } : {})}
|
|
905
|
+
{...(nodeStyles?.code_block ? { style: nodeStyles.code_block } : {})}
|
|
889
906
|
/>
|
|
890
907
|
);
|
|
891
908
|
|
|
892
909
|
case "blockquote":
|
|
893
910
|
return (
|
|
894
|
-
<Blockquote
|
|
911
|
+
<Blockquote
|
|
912
|
+
{...(nodeStyles?.blockquote
|
|
913
|
+
? { style: nodeStyles.blockquote }
|
|
914
|
+
: {})}
|
|
915
|
+
>
|
|
895
916
|
{renderChildren(node.children, inListItem, false)}
|
|
896
917
|
</Blockquote>
|
|
897
918
|
);
|
|
898
919
|
|
|
899
920
|
case "horizontal_rule":
|
|
900
|
-
return
|
|
921
|
+
return (
|
|
922
|
+
<HorizontalRule
|
|
923
|
+
{...(nodeStyles?.horizontal_rule
|
|
924
|
+
? { style: nodeStyles.horizontal_rule }
|
|
925
|
+
: {})}
|
|
926
|
+
/>
|
|
927
|
+
);
|
|
901
928
|
|
|
902
929
|
case "line_break":
|
|
903
930
|
return <Text>{"\n"}</Text>;
|
|
@@ -910,7 +937,12 @@ const NodeRendererComponent: FC<NodeRendererProps> = ({
|
|
|
910
937
|
if (!mathContent) return null;
|
|
911
938
|
mathContent = mathContent.replace(/^\$+|\$+$/g, "").trim();
|
|
912
939
|
return (
|
|
913
|
-
<MathInline
|
|
940
|
+
<MathInline
|
|
941
|
+
content={mathContent}
|
|
942
|
+
{...(nodeStyles?.math_inline
|
|
943
|
+
? { style: nodeStyles.math_inline }
|
|
944
|
+
: {})}
|
|
945
|
+
/>
|
|
914
946
|
);
|
|
915
947
|
}
|
|
916
948
|
|
|
@@ -918,7 +950,7 @@ const NodeRendererComponent: FC<NodeRendererProps> = ({
|
|
|
918
950
|
return (
|
|
919
951
|
<MathBlock
|
|
920
952
|
content={getTextContent(node)}
|
|
921
|
-
|
|
953
|
+
{...(nodeStyles?.math_block ? { style: nodeStyles.math_block } : {})}
|
|
922
954
|
/>
|
|
923
955
|
);
|
|
924
956
|
|
|
@@ -926,9 +958,9 @@ const NodeRendererComponent: FC<NodeRendererProps> = ({
|
|
|
926
958
|
return (
|
|
927
959
|
<List
|
|
928
960
|
ordered={node.ordered ?? false}
|
|
929
|
-
start={node.start}
|
|
930
961
|
depth={depth}
|
|
931
|
-
|
|
962
|
+
{...(node.start === undefined ? {} : { start: node.start })}
|
|
963
|
+
{...(nodeStyles?.list ? { style: nodeStyles.list } : {})}
|
|
932
964
|
>
|
|
933
965
|
{node.children?.map((child, index) => {
|
|
934
966
|
if (child.type === "task_list_item") {
|
|
@@ -968,7 +1000,9 @@ const NodeRendererComponent: FC<NodeRendererProps> = ({
|
|
|
968
1000
|
return (
|
|
969
1001
|
<TaskListItem
|
|
970
1002
|
checked={node.checked ?? false}
|
|
971
|
-
|
|
1003
|
+
{...(nodeStyles?.task_list_item
|
|
1004
|
+
? { style: nodeStyles.task_list_item }
|
|
1005
|
+
: {})}
|
|
972
1006
|
>
|
|
973
1007
|
{renderChildren(node.children, true, false)}
|
|
974
1008
|
</TaskListItem>
|
|
@@ -979,7 +1013,7 @@ const NodeRendererComponent: FC<NodeRendererProps> = ({
|
|
|
979
1013
|
<TableRenderer
|
|
980
1014
|
node={node}
|
|
981
1015
|
Renderer={NodeRenderer}
|
|
982
|
-
|
|
1016
|
+
{...(nodeStyles?.table ? { style: nodeStyles.table } : {})}
|
|
983
1017
|
/>
|
|
984
1018
|
);
|
|
985
1019
|
|
package/src/renderers/image.tsx
CHANGED
|
@@ -140,8 +140,8 @@ export const Image: FC<ImageProps> = ({ url, title, alt, Renderer, style }) => {
|
|
|
140
140
|
/picsum\.photos\/.*\/(\d+)\/(\d+)/,
|
|
141
141
|
);
|
|
142
142
|
if (picsumMatch) {
|
|
143
|
-
const w = parseInt(picsumMatch[1], 10);
|
|
144
|
-
const h = parseInt(picsumMatch[2], 10);
|
|
143
|
+
const w = parseInt(picsumMatch[1] ?? "", 10);
|
|
144
|
+
const h = parseInt(picsumMatch[2] ?? "", 10);
|
|
145
145
|
if (!isNaN(w) && !isNaN(h) && h !== 0) {
|
|
146
146
|
setAspectRatio(w / h);
|
|
147
147
|
return () => {
|
package/src/renderers/math.tsx
CHANGED
|
@@ -265,8 +265,8 @@ export const MathInline: FC<MathInlineProps> = ({ content, style }) => {
|
|
|
265
265
|
latex={content}
|
|
266
266
|
fontSize={getInlineMathFontSize(content, theme)}
|
|
267
267
|
displayMode={false}
|
|
268
|
-
color={theme.colors.text}
|
|
269
268
|
style={styles.ratexInline}
|
|
269
|
+
{...(theme.colors.text ? { color: theme.colors.text } : {})}
|
|
270
270
|
onError={() => {
|
|
271
271
|
if (!mountedRef.current) return;
|
|
272
272
|
setHasRenderError(true);
|
|
@@ -314,8 +314,8 @@ export const MathBlock: FC<MathBlockProps> = ({ content, style }) => {
|
|
|
314
314
|
latex={content}
|
|
315
315
|
fontSize={theme.fontSizes.xl}
|
|
316
316
|
displayMode
|
|
317
|
-
color={theme.colors.text}
|
|
318
317
|
style={styles.ratexBlock}
|
|
318
|
+
{...(theme.colors.text ? { color: theme.colors.text } : {})}
|
|
319
319
|
onError={() => {
|
|
320
320
|
if (!mountedRef.current) return;
|
|
321
321
|
setHasRenderError(true);
|
|
@@ -181,19 +181,19 @@ export const TableRenderer: FC<TableRendererProps> = ({
|
|
|
181
181
|
for (let col = 0; col < columnCount; col++) {
|
|
182
182
|
const headerWidth = measuredWidths.current.get(`header-${col}`);
|
|
183
183
|
if (headerWidth && headerWidth > 0) {
|
|
184
|
-
maxWidths[col] = Math.max(maxWidths[col], headerWidth);
|
|
184
|
+
maxWidths[col] = Math.max(maxWidths[col] ?? 0, headerWidth);
|
|
185
185
|
}
|
|
186
186
|
|
|
187
187
|
for (let row = 0; row < rows.length; row++) {
|
|
188
|
-
if (col >= rows[row]
|
|
188
|
+
if (col >= (rows[row]?.length ?? 0)) continue;
|
|
189
189
|
const cellWidth = measuredWidths.current.get(`cell-${row}-${col}`);
|
|
190
190
|
if (cellWidth && cellWidth > 0) {
|
|
191
|
-
maxWidths[col] = Math.max(maxWidths[col], cellWidth);
|
|
191
|
+
maxWidths[col] = Math.max(maxWidths[col] ?? 0, cellWidth);
|
|
192
192
|
}
|
|
193
193
|
}
|
|
194
194
|
|
|
195
195
|
maxWidths[col] = Math.max(
|
|
196
|
-
maxWidths[col] + COLUMN_MEASUREMENT_PADDING,
|
|
196
|
+
(maxWidths[col] ?? 0) + COLUMN_MEASUREMENT_PADDING,
|
|
197
197
|
minColumnWidth,
|
|
198
198
|
);
|
|
199
199
|
}
|
|
@@ -59,7 +59,7 @@ export const estimateColumnWidths = (
|
|
|
59
59
|
let maxChars = headerChars;
|
|
60
60
|
|
|
61
61
|
for (let row = 0; row < rows.length; row++) {
|
|
62
|
-
const cell = rows[row][col];
|
|
62
|
+
const cell = rows[row]?.[col];
|
|
63
63
|
if (!cell) continue;
|
|
64
64
|
const cellChars = Math.min(
|
|
65
65
|
getTextContent(cell).trim().length,
|
|
@@ -182,7 +182,7 @@ export function defaultHighlighter(
|
|
|
182
182
|
const lines = code.split("\n");
|
|
183
183
|
const result: HighlightedToken[] = [];
|
|
184
184
|
for (let i = 0; i < lines.length; i++) {
|
|
185
|
-
result.push(...tokenizeLine(lines[i], language));
|
|
185
|
+
result.push(...tokenizeLine(lines[i] ?? "", language));
|
|
186
186
|
if (i < lines.length - 1) {
|
|
187
187
|
result.push({ text: "\n", type: "default" });
|
|
188
188
|
}
|
|
@@ -24,7 +24,7 @@ const isInsideFencedCodeBlock = (text: string): boolean => {
|
|
|
24
24
|
const fenceMatch = line.match(FENCE_LINE_PATTERN);
|
|
25
25
|
if (!fenceMatch) continue;
|
|
26
26
|
|
|
27
|
-
const marker = fenceMatch[1];
|
|
27
|
+
const marker = fenceMatch[1] ?? "";
|
|
28
28
|
const markerChar = marker[0] as "`" | "~";
|
|
29
29
|
const markerLength = marker.length;
|
|
30
30
|
|
|
@@ -94,7 +94,11 @@ const findTrailingLeafPath = (
|
|
|
94
94
|
}
|
|
95
95
|
|
|
96
96
|
const lastIndex = children.length - 1;
|
|
97
|
-
|
|
97
|
+
const lastChild = children[lastIndex];
|
|
98
|
+
if (lastChild === undefined) {
|
|
99
|
+
return path;
|
|
100
|
+
}
|
|
101
|
+
return findTrailingLeafPath(lastChild, [...path, lastIndex]);
|
|
98
102
|
};
|
|
99
103
|
|
|
100
104
|
const getNodeAtPath = (
|
|
@@ -126,11 +130,14 @@ const appendPlainTextToAst = (
|
|
|
126
130
|
const delta = appendedChunk.length;
|
|
127
131
|
const update = (node: MarkdownNode, depth: number): MarkdownNode => {
|
|
128
132
|
if (depth === path.length) {
|
|
129
|
-
|
|
133
|
+
const updatedNode: MarkdownNode = {
|
|
130
134
|
...node,
|
|
131
135
|
content: (node.content ?? "") + appendedChunk,
|
|
132
|
-
end: typeof node.end === "number" ? node.end + delta : node.end,
|
|
133
136
|
};
|
|
137
|
+
if (typeof node.end === "number") {
|
|
138
|
+
updatedNode.end = node.end + delta;
|
|
139
|
+
}
|
|
140
|
+
return updatedNode;
|
|
134
141
|
}
|
|
135
142
|
|
|
136
143
|
const childIndex = path[depth];
|
|
@@ -138,11 +145,16 @@ const appendPlainTextToAst = (
|
|
|
138
145
|
index === childIndex ? update(child, depth + 1) : child,
|
|
139
146
|
);
|
|
140
147
|
|
|
141
|
-
|
|
148
|
+
const updatedNode: MarkdownNode = {
|
|
142
149
|
...node,
|
|
143
|
-
end: typeof node.end === "number" ? node.end + delta : node.end,
|
|
144
|
-
children,
|
|
145
150
|
};
|
|
151
|
+
if (typeof node.end === "number") {
|
|
152
|
+
updatedNode.end = node.end + delta;
|
|
153
|
+
}
|
|
154
|
+
if (children) {
|
|
155
|
+
updatedNode.children = children;
|
|
156
|
+
}
|
|
157
|
+
return updatedNode;
|
|
146
158
|
};
|
|
147
159
|
|
|
148
160
|
return update(ast, 0);
|
|
@@ -206,8 +218,12 @@ export const reuseStableAstNodes = (
|
|
|
206
218
|
|
|
207
219
|
let hasChildChange = false;
|
|
208
220
|
const children = nextChildren.map((nextChild, index) => {
|
|
209
|
-
const
|
|
210
|
-
|
|
221
|
+
const previousChild = previousChildren[index];
|
|
222
|
+
const child =
|
|
223
|
+
previousChild === undefined
|
|
224
|
+
? nextChild
|
|
225
|
+
: reuseStableAstNodes(previousChild, nextChild);
|
|
226
|
+
hasChildChange ||= child !== previousChild;
|
|
211
227
|
return child;
|
|
212
228
|
});
|
|
213
229
|
|
|
@@ -26,14 +26,14 @@ const parseAbsoluteHref = (
|
|
|
26
26
|
const protocolMatch = href.match(/^([a-z][a-z0-9+.-]*):/i);
|
|
27
27
|
if (!protocolMatch) return null;
|
|
28
28
|
|
|
29
|
-
const protocol = normalizeProtocol(protocolMatch[1]);
|
|
29
|
+
const protocol = normalizeProtocol(protocolMatch[1] ?? "");
|
|
30
30
|
const rest = href.slice(protocolMatch[0].length);
|
|
31
31
|
const authorityMatch = rest.match(/^\/\/([^/?#]*)/);
|
|
32
32
|
const rawHost = authorityMatch?.[1] ?? "";
|
|
33
|
-
const hostname = rawHost
|
|
33
|
+
const hostname = (rawHost
|
|
34
34
|
.replace(/^[^@]*@/, "")
|
|
35
35
|
.replace(/^\[|\]$/g, "")
|
|
36
|
-
.split(":")[0]
|
|
36
|
+
.split(":")[0] ?? "")
|
|
37
37
|
.toLowerCase();
|
|
38
38
|
|
|
39
39
|
return { protocol, hostname };
|
|
@@ -19,15 +19,17 @@ export const createTimestampTimeline = (
|
|
|
19
19
|
.map(Number)
|
|
20
20
|
.filter((index) => Number.isFinite(index))
|
|
21
21
|
.sort((a, b) => a - b)
|
|
22
|
-
.
|
|
23
|
-
index
|
|
24
|
-
time:
|
|
25
|
-
})
|
|
22
|
+
.flatMap((index) => {
|
|
23
|
+
const time = timestamps[index];
|
|
24
|
+
return time === undefined ? [] : [{ index, time }];
|
|
25
|
+
})
|
|
26
26
|
.filter((entry) => Number.isFinite(entry.time));
|
|
27
27
|
|
|
28
28
|
let monotonic = true;
|
|
29
29
|
for (let i = 1; i < entries.length; i += 1) {
|
|
30
|
-
|
|
30
|
+
const current = entries[i];
|
|
31
|
+
const previous = entries[i - 1];
|
|
32
|
+
if (current && previous && current.time < previous.time) {
|
|
31
33
|
monotonic = false;
|
|
32
34
|
break;
|
|
33
35
|
}
|
|
@@ -59,7 +61,8 @@ export const resolveHighlightPosition = (
|
|
|
59
61
|
|
|
60
62
|
while (left <= right) {
|
|
61
63
|
const mid = (left + right) >> 1;
|
|
62
|
-
|
|
64
|
+
const entry = entries[mid];
|
|
65
|
+
if (entry !== undefined && entry.time <= currentTimeMs) {
|
|
63
66
|
resolvedIndex = mid;
|
|
64
67
|
left = mid + 1;
|
|
65
68
|
} else {
|
|
@@ -68,5 +71,5 @@ export const resolveHighlightPosition = (
|
|
|
68
71
|
}
|
|
69
72
|
|
|
70
73
|
if (resolvedIndex === -1) return 0;
|
|
71
|
-
return entries[resolvedIndex]
|
|
74
|
+
return (entries[resolvedIndex]?.index ?? 0) + 1;
|
|
72
75
|
};
|