diff --git a/web/src/components/CreateTagDialog.tsx b/web/src/components/CreateTagDialog.tsx index 8fe9b601..ce788f5e 100644 --- a/web/src/components/CreateTagDialog.tsx +++ b/web/src/components/CreateTagDialog.tsx @@ -3,10 +3,9 @@ import React, { useEffect, useState } from "react"; import { toast } from "react-hot-toast"; import { tagServiceClient } from "@/grpcweb"; import useCurrentUser from "@/hooks/useCurrentUser"; -import { matcher } from "@/labs/marked/matcher"; -import Tag from "@/labs/marked/parser/Tag"; import { useTagStore } from "@/store/module"; import { useTranslate } from "@/utils/i18n"; +import { TAG_REG } from "@/utils/tag"; import { generateDialog } from "./Dialog"; import Icon from "./Icon"; import OverflowTip from "./kit/OverflowTip"; @@ -14,7 +13,7 @@ import OverflowTip from "./kit/OverflowTip"; type Props = DialogProps; const validateTagName = (tagName: string): boolean => { - const matchResult = matcher(`#${tagName}`, Tag.regexp); + const matchResult = `#${tagName}`.match(TAG_REG); if (!matchResult || matchResult[1] !== tagName) { return false; } diff --git a/web/src/components/MemoList.tsx b/web/src/components/MemoList.tsx index 5db2fc02..87de0d2b 100644 --- a/web/src/components/MemoList.tsx +++ b/web/src/components/MemoList.tsx @@ -5,10 +5,10 @@ import MemoFilter from "@/components/MemoFilter"; import { DEFAULT_MEMO_LIMIT } from "@/helpers/consts"; import { getTimeStampByDate } from "@/helpers/datetime"; import useCurrentUser from "@/hooks/useCurrentUser"; -import { TAG_REG } from "@/labs/marked/parser"; import { useFilterStore, useMemoStore } from "@/store/module"; import { extractUsernameFromName } from "@/store/v1"; import { useTranslate } from "@/utils/i18n"; +import { TAG_REG } from "@/utils/tag"; import Empty from "./Empty"; import Memo from "./Memo"; diff --git a/web/src/labs/marked/index.tsx b/web/src/labs/marked/index.tsx deleted file mode 100644 index db80b63b..00000000 --- a/web/src/labs/marked/index.tsx +++ /dev/null @@ -1,146 +0,0 @@ -import { matcher } from "./matcher"; -import { blockElementParserList, inlineElementParserList } from "./parser"; - -type Parser = { - name: string; - regexp: RegExp; - renderer: (rawStr: string) => JSX.Element | string; -}; - -const findMatchingParser = (parsers: Parser[], markdownStr: string): Parser | undefined => { - let matchedParser = undefined; - let matchedIndex = -1; - - for (const parser of parsers) { - const matchResult = matcher(markdownStr, parser.regexp); - if (!matchResult) { - continue; - } - - if (parser.name === "plain text" && matchedParser !== undefined) { - continue; - } - - const startIndex = matchResult.index as number; - if (matchedParser === undefined || matchedIndex > startIndex) { - matchedParser = parser; - matchedIndex = startIndex; - } - } - - return matchedParser; -}; - -export const marked = ( - markdownStr: string, - blockParsers = blockElementParserList, - inlineParsers = inlineElementParserList -): string | JSX.Element => { - const matchedBlockParser = findMatchingParser(blockParsers, markdownStr); - if (matchedBlockParser) { - const matchResult = matcher(markdownStr, matchedBlockParser.regexp); - if (matchResult) { - const matchedStr = matchResult[0]; - const retainContent = markdownStr.slice(matchedStr.length); - - if (matchedBlockParser.name === "br") { - return ( - <> - {matchedBlockParser.renderer(matchedStr)} - {marked(retainContent, blockParsers, inlineParsers)} - > - ); - } else { - if (retainContent === "") { - return matchedBlockParser.renderer(matchedStr); - } else if (retainContent.startsWith("\n")) { - return ( - <> - {matchedBlockParser.renderer(matchedStr)} - {marked(retainContent.slice(1), blockParsers, inlineParsers)} - > - ); - } - } - } - } - - const matchedInlineParser = findMatchingParser(inlineParsers, markdownStr); - if (matchedInlineParser) { - const matchResult = matcher(markdownStr, matchedInlineParser.regexp); - if (matchResult) { - const matchedStr = matchResult[0]; - const matchedLength = matchedStr.length; - const mIndex = matchResult.index || 0; - const prefixStr = markdownStr.slice(0, mIndex); - const suffixStr = markdownStr.slice(mIndex + matchedLength); - return ( - <> - {marked(prefixStr, [], inlineParsers)} - {matchedInlineParser.renderer(matchedStr)} - {marked(suffixStr, [], inlineParsers)} - > - ); - } - } - - return <>{markdownStr}>; -}; - -interface MatchedNode { - parserName: string; - matchedContent: string; -} - -export const getMatchedNodes = (markdownStr: string): MatchedNode[] => { - const matchedNodeList: MatchedNode[] = []; - - const walkthrough = (markdownStr: string, blockParsers = blockElementParserList, inlineParsers = inlineElementParserList): string => { - const matchedBlockParser = findMatchingParser(blockParsers, markdownStr); - if (matchedBlockParser) { - const matchResult = matcher(markdownStr, matchedBlockParser.regexp); - if (matchResult) { - const matchedStr = matchResult[0]; - const retainContent = markdownStr.slice(matchedStr.length); - matchedNodeList.push({ - parserName: matchedBlockParser.name, - matchedContent: matchedStr, - }); - - if (matchedBlockParser.name === "br") { - return walkthrough(retainContent, blockParsers, inlineParsers); - } else { - if (matchedBlockParser.name !== "code block") { - walkthrough(matchedStr, [], inlineParsers); - } - if (retainContent.startsWith("\n")) { - return walkthrough(retainContent.slice(1), blockParsers, inlineParsers); - } - } - return ""; - } - } - - const matchedInlineParser = findMatchingParser(inlineParsers, markdownStr); - if (matchedInlineParser) { - const matchResult = matcher(markdownStr, matchedInlineParser.regexp); - if (matchResult) { - const matchedStr = matchResult[0]; - const matchedLength = matchedStr.length; - const mIndex = matchResult.index || 0; - const suffixStr = markdownStr.slice(mIndex + matchedLength); - matchedNodeList.push({ - parserName: matchedInlineParser.name, - matchedContent: matchedStr, - }); - return walkthrough(suffixStr, [], inlineParsers); - } - } - - return markdownStr; - }; - - walkthrough(markdownStr); - - return matchedNodeList; -}; diff --git a/web/src/labs/marked/matcher.ts b/web/src/labs/marked/matcher.ts deleted file mode 100644 index 475d809e..00000000 --- a/web/src/labs/marked/matcher.ts +++ /dev/null @@ -1,4 +0,0 @@ -export const matcher = (rawStr: string, regexp: RegExp) => { - const matchResult = rawStr.match(regexp); - return matchResult; -}; diff --git a/web/src/labs/marked/parser/BlockLatex.tsx b/web/src/labs/marked/parser/BlockLatex.tsx deleted file mode 100644 index 902508a9..00000000 --- a/web/src/labs/marked/parser/BlockLatex.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import TeX from "@matejmazur/react-katex"; -import "katex/dist/katex.min.css"; -import { matcher } from "../matcher"; - -const BLOCK_LATEX_REG = new RegExp( - "\\$\\$(\\s*[^\\$\\s][^\\$]*?)\\$\\$|\\\\\\[(.+?)\\\\\\]|\\\\begin{equation}([\\s\\S]+?)\\\\end{equation}" -); - -const blockRenderer = (rawStr: string) => { - const matchResult = matcher(rawStr, BLOCK_LATEX_REG); - if (!matchResult) { - return <>{rawStr}>; - } - - let latexCode = ""; - - if (matchResult[1]) { - // $$ - latexCode = matchResult[1]; - } else if (matchResult[2]) { - // \[ and \] - latexCode = matchResult[2]; - } else if (matchResult[3]) { - // \begin{equation} and \end{equation} - latexCode = matchResult[3]; - } - - return ( -
{parsedContent}; -}; - -export default { - name: "blockquote", - regexp: BLOCKQUOTE_REG, - renderer, -}; diff --git a/web/src/labs/marked/parser/Bold.tsx b/web/src/labs/marked/parser/Bold.tsx deleted file mode 100644 index 259eb0f8..00000000 --- a/web/src/labs/marked/parser/Bold.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { marked } from ".."; -import { matcher } from "../matcher"; -import Link from "./Link"; -import PlainText from "./PlainText"; - -export const BOLD_REG = /\*\*(.+?)\*\*/; - -const renderer = (rawStr: string) => { - const matchResult = matcher(rawStr, BOLD_REG); - if (!matchResult) { - return <>{rawStr}>; - } - - const parsedContent = marked(matchResult[1], [], [Link, PlainText]); - return {parsedContent}; -}; - -export default { - name: "bold", - regexp: BOLD_REG, - renderer, -}; diff --git a/web/src/labs/marked/parser/BoldEmphasis.tsx b/web/src/labs/marked/parser/BoldEmphasis.tsx deleted file mode 100644 index a5ccfbed..00000000 --- a/web/src/labs/marked/parser/BoldEmphasis.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import { marked } from ".."; -import { matcher } from "../matcher"; -import Link from "./Link"; -import PlainText from "./PlainText"; - -export const BOLD_EMPHASIS_REG = /\*\*\*(.+?)\*\*\*/; - -const renderer = (rawStr: string) => { - const matchResult = matcher(rawStr, BOLD_EMPHASIS_REG); - if (!matchResult) { - return rawStr; - } - - const parsedContent = marked(matchResult[1], [], [Link, PlainText]); - return ( - - {parsedContent} - - ); -}; - -export default { - name: "bold emphasis", - regexp: BOLD_EMPHASIS_REG, - renderer, -}; diff --git a/web/src/labs/marked/parser/Br.tsx b/web/src/labs/marked/parser/Br.tsx deleted file mode 100644 index b6a1a3a2..00000000 --- a/web/src/labs/marked/parser/Br.tsx +++ /dev/null @@ -1,16 +0,0 @@ -export const BR_REG = /^(\n+)/; - -const renderer = (rawStr: string) => { - const length = rawStr.split("\n").length - 1; - const brList = []; - for (let i = 0; i < length; i++) { - brList.push(
-
-
-
- );
-};
-
-export default {
- name: "code block",
- regexp: CODE_BLOCK_REG,
- renderer,
-};
diff --git a/web/src/labs/marked/parser/DoneList.tsx b/web/src/labs/marked/parser/DoneList.tsx
deleted file mode 100644
index 52f3a0f9..00000000
--- a/web/src/labs/marked/parser/DoneList.tsx
+++ /dev/null
@@ -1,29 +0,0 @@
-import { inlineElementParserList } from ".";
-import { marked } from "..";
-import { matcher } from "../matcher";
-
-export const DONE_LIST_REG = /^( *)- \[[xX]\] ([^\n]+)/;
-
-const renderer = (rawStr: string) => {
- const matchResult = matcher(rawStr, DONE_LIST_REG);
- if (!matchResult) {
- return rawStr;
- }
- const space = matchResult[1];
- const parsedContent = marked(matchResult[2], [], inlineElementParserList);
- return (
- - {space} - - ✓ - - {parsedContent} -
- ); -}; - -export default { - name: "done list", - regexp: DONE_LIST_REG, - renderer, -}; diff --git a/web/src/labs/marked/parser/Emphasis.tsx b/web/src/labs/marked/parser/Emphasis.tsx deleted file mode 100644 index 3a92437e..00000000 --- a/web/src/labs/marked/parser/Emphasis.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import { marked } from ".."; -import { matcher } from "../matcher"; -import Link from "./Link"; -import PlainLink from "./PlainLink"; -import PlainText from "./PlainText"; - -export const EMPHASIS_REG = /\*(.+?)\*/; - -const renderer = (rawStr: string) => { - const matchResult = matcher(rawStr, EMPHASIS_REG); - if (!matchResult) { - return rawStr; - } - - const parsedContent = marked(matchResult[1], [], [Link, PlainLink, PlainText]); - return {parsedContent}; -}; - -export default { - name: "emphasis", - regexp: EMPHASIS_REG, - renderer, -}; diff --git a/web/src/labs/marked/parser/Heading.tsx b/web/src/labs/marked/parser/Heading.tsx deleted file mode 100644 index 8fa8e146..00000000 --- a/web/src/labs/marked/parser/Heading.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { marked } from ".."; -import { matcher } from "../matcher"; -import InlineCode from "./InlineCode"; -import Link from "./Link"; -import PlainLink from "./PlainLink"; -import PlainText from "./PlainText"; - -export const HEADING_REG = /^(#+) ([^\n]+)/; - -const renderer = (rawStr: string) => { - const matchResult = matcher(rawStr, HEADING_REG); - if (!matchResult) { - return rawStr; - } - - const level = matchResult[1].length; - const parsedContent = marked(matchResult[2], [], [InlineCode, Link, PlainLink, PlainText]); - if (level === 1) { - return{matchResult[1]}
;
-};
-
-export default {
- name: "inline code",
- regexp: INLINE_CODE_REG,
- renderer,
-};
diff --git a/web/src/labs/marked/parser/InlineLatex.tsx b/web/src/labs/marked/parser/InlineLatex.tsx
deleted file mode 100644
index b7856f72..00000000
--- a/web/src/labs/marked/parser/InlineLatex.tsx
+++ /dev/null
@@ -1,28 +0,0 @@
-import TeX from "@matejmazur/react-katex";
-import "katex/dist/katex.min.css";
-
-export const LATEX_INLINE_REG = /\$(.+?)\$|\\\((.+?)\\\)/;
-
-const inlineRenderer = (rawStr: string) => {
- const matchResult = LATEX_INLINE_REG.exec(rawStr);
- if (matchResult) {
- let latexCode = "";
- if (matchResult[1]) {
- latexCode = matchResult[1];
- } else if (matchResult[2]) {
- latexCode = matchResult[2];
- }
- return (
-
- - {space} - {matchResult[2]}. - {parsedContent} -
- ); -}; - -export default { - name: "ordered list", - regexp: ORDERED_LIST_REG, - renderer, -}; diff --git a/web/src/labs/marked/parser/Paragraph.tsx b/web/src/labs/marked/parser/Paragraph.tsx deleted file mode 100644 index 60cb69d6..00000000 --- a/web/src/labs/marked/parser/Paragraph.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { inlineElementParserList } from "."; -import { marked } from ".."; - -export const PARAGRAPH_REG = /^([^\n]+)/; - -const renderer = (rawStr: string) => { - const parsedContent = marked(rawStr, [], inlineElementParserList); - return{parsedContent}
; -}; - -export default { - name: "paragraph", - regexp: PARAGRAPH_REG, - renderer, -}; diff --git a/web/src/labs/marked/parser/PlainLink.tsx b/web/src/labs/marked/parser/PlainLink.tsx deleted file mode 100644 index 17a7f788..00000000 --- a/web/src/labs/marked/parser/PlainLink.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { matcher } from "../matcher"; - -export const PLAIN_LINK_REG = /((?:https?|chrome|edge):\/\/[^ ]+)/; - -const renderer = (rawStr: string) => { - const matchResult = matcher(rawStr, PLAIN_LINK_REG); - if (!matchResult) { - return rawStr; - } - - return ( - - {matchResult[1]} - - ); -}; - -export default { - name: "plain link", - regexp: PLAIN_LINK_REG, - renderer, -}; diff --git a/web/src/labs/marked/parser/PlainText.tsx b/web/src/labs/marked/parser/PlainText.tsx deleted file mode 100644 index 41c45de5..00000000 --- a/web/src/labs/marked/parser/PlainText.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import { matcher } from "../matcher"; - -export const PLAIN_TEXT_REG = /(.+)/; - -const renderer = (rawStr: string): string => { - const matchResult = matcher(rawStr, PLAIN_TEXT_REG); - if (!matchResult) { - return rawStr; - } - - return matchResult[1]; -}; - -export default { - name: "plain text", - regexp: PLAIN_TEXT_REG, - renderer, -}; diff --git a/web/src/labs/marked/parser/Strikethrough.tsx b/web/src/labs/marked/parser/Strikethrough.tsx deleted file mode 100644 index 64d8d0b2..00000000 --- a/web/src/labs/marked/parser/Strikethrough.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import { matcher } from "../matcher"; - -export const STRIKETHROUGH_REG = /~~(.+?)~~/; - -const renderer = (rawStr: string) => { - const matchResult = matcher(rawStr, STRIKETHROUGH_REG); - if (!matchResult) { - return rawStr; - } - - return{marked(header, [], inlineElementParserList)} | - ))} -
---|
- {cellIndex < row.length ? marked(row[cellIndex], [], inlineElementParserList) : null} - | - ))} -
- {space} - - {parsedContent} -
- ); -}; - -export default { - name: "todo list", - regexp: TODO_LIST_REG, - renderer, -}; diff --git a/web/src/labs/marked/parser/UnorderedList.tsx b/web/src/labs/marked/parser/UnorderedList.tsx deleted file mode 100644 index ebd41e62..00000000 --- a/web/src/labs/marked/parser/UnorderedList.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { inlineElementParserList } from "."; -import { marked } from ".."; -import { matcher } from "../matcher"; - -export const UNORDERED_LIST_REG = /^( *)[*-] ([^\n]+)/; - -const renderer = (rawStr: string) => { - const matchResult = matcher(rawStr, UNORDERED_LIST_REG); - if (!matchResult) { - return rawStr; - } - const space = matchResult[1]; - const parsedContent = marked(matchResult[2], [], inlineElementParserList); - return ( -- {space} - • - {parsedContent} -
- ); -}; - -export default { - name: "unordered list", - regexp: UNORDERED_LIST_REG, - renderer, -}; diff --git a/web/src/labs/marked/parser/index.ts b/web/src/labs/marked/parser/index.ts deleted file mode 100644 index 3259ee8e..00000000 --- a/web/src/labs/marked/parser/index.ts +++ /dev/null @@ -1,56 +0,0 @@ -import BlockLatex from "./BlockLatex"; -import Blockquote from "./Blockquote"; -import Bold from "./Bold"; -import BoldEmphasis from "./BoldEmphasis"; -import Br from "./Br"; -import CodeBlock from "./CodeBlock"; -import DoneList from "./DoneList"; -import Emphasis from "./Emphasis"; -import Heading from "./Heading"; -import HorizontalRules from "./HorizontalRules"; -import Image from "./Image"; -import InlineCode from "./InlineCode"; -import InlineLatex from "./InlineLatex"; -import Link from "./Link"; -import OrderedList from "./OrderedList"; -import Paragraph from "./Paragraph"; -import PlainLink from "./PlainLink"; -import PlainText from "./PlainText"; -import Strikethrough from "./Strikethrough"; -import Table from "./Table"; -import Tag from "./Tag"; -import TodoList from "./TodoList"; -import UnorderedList from "./UnorderedList"; - -export { TAG_REG } from "./Tag"; -export { LINK_REG } from "./Link"; -export { PLAIN_LINK_REG } from "./PlainLink"; - -// The order determines the order of execution. -export const blockElementParserList = [ - BlockLatex, - Br, - CodeBlock, - Blockquote, - Table, - Heading, - TodoList, - DoneList, - OrderedList, - UnorderedList, - HorizontalRules, - Paragraph, -]; -export const inlineElementParserList = [ - InlineLatex, - Image, - BoldEmphasis, - Bold, - Emphasis, - Link, - InlineCode, - PlainLink, - Strikethrough, - Tag, - PlainText, -]; diff --git a/web/src/pages/Explore.tsx b/web/src/pages/Explore.tsx index 97185b7e..3230b217 100644 --- a/web/src/pages/Explore.tsx +++ b/web/src/pages/Explore.tsx @@ -5,9 +5,9 @@ import Memo from "@/components/Memo"; import MemoFilter from "@/components/MemoFilter"; import MobileHeader from "@/components/MobileHeader"; import { DEFAULT_MEMO_LIMIT } from "@/helpers/consts"; -import { TAG_REG } from "@/labs/marked/parser"; import { useFilterStore, useMemoStore } from "@/store/module"; import { useTranslate } from "@/utils/i18n"; +import { TAG_REG } from "@/utils/tag"; const Explore = () => { const t = useTranslate(); diff --git a/web/src/utils/tag.ts b/web/src/utils/tag.ts new file mode 100644 index 00000000..bfd2ce72 --- /dev/null +++ b/web/src/utils/tag.ts @@ -0,0 +1 @@ +export const TAG_REG = /#([^\s#,]+)/;