Move the event parser and dedup functions to Rust (#206)

* feat: improve js parser

* feat: move parser and dedup to rust

* fix: parser

* fix: get event function

* feat: improve parser performance (#207)

* feat: improve parser performance

* feat: add test for video parsing

* feat: finish new parser

---------

Co-authored-by: XIAO YU <xyzmhx@gmail.com>
This commit is contained in:
雨宮蓮
2024-06-12 08:27:53 +07:00
committed by GitHub
parent 1c20512ecc
commit 71be59b2e9
21 changed files with 610 additions and 250 deletions

View File

@@ -1,4 +1,4 @@
import { NOSTR_EVENTS, NOSTR_MENTIONS, cn, parser } from "@lume/utils";
import { cn } from "@lume/utils";
import { type ReactNode, useMemo } from "react";
import reactStringReplace from "react-string-replace";
import { Hashtag } from "./mentions/hashtag";
@@ -21,54 +21,42 @@ export function NoteContent({
className?: string;
}) {
const event = useNoteContext();
const data = useMemo(() => {
const { content, images, videos } = parser(event.content);
const words = content.split(/( |\n)/);
const hashtags = words.filter((word) => word.startsWith("#"));
const events = words.filter((word) =>
NOSTR_EVENTS.some((el) => word.startsWith(el)),
);
const mentions = words.filter((word) =>
NOSTR_MENTIONS.some((el) => word.startsWith(el)),
);
let richContent: ReactNode[] | string = content;
const content = useMemo(() => {
try {
if (hashtags.length) {
for (const hashtag of hashtags) {
const regex = new RegExp(`(|^)${hashtag}\\b`, "g");
richContent = reactStringReplace(richContent, regex, (_, index) => {
return <Hashtag key={hashtag + index} tag={hashtag} />;
});
// Get parsed meta
const { content, hashtags, events, mentions } = event.meta;
// Define rich content
let richContent: ReactNode[] | string = content;
for (const hashtag of hashtags) {
const regex = new RegExp(`(|^)${hashtag}\\b`, "g");
richContent = reactStringReplace(richContent, regex, (_, index) => {
return <Hashtag key={hashtag + index} tag={hashtag} />;
});
}
for (const event of events) {
if (quote) {
richContent = reactStringReplace(richContent, event, (_, index) => (
<MentionNote key={event + index} eventId={event} />
));
}
if (!quote && clean) {
richContent = reactStringReplace(richContent, event, () => null);
}
}
if (events.length) {
for (const event of events) {
if (quote) {
richContent = reactStringReplace(richContent, event, (_, index) => (
<MentionNote key={event + index} eventId={event} />
));
}
if (!quote && clean) {
richContent = reactStringReplace(richContent, event, () => null);
}
for (const user of mentions) {
if (mention) {
richContent = reactStringReplace(richContent, user, (_, index) => (
<MentionUser key={user + index} pubkey={user} />
));
}
}
if (mentions.length) {
for (const user of mentions) {
if (mention) {
richContent = reactStringReplace(richContent, user, (_, index) => (
<MentionUser key={user + index} pubkey={user} />
));
}
if (!mention && clean) {
richContent = reactStringReplace(richContent, user, () => null);
}
if (!mention && clean) {
richContent = reactStringReplace(richContent, user, () => null);
}
}
@@ -81,7 +69,7 @@ export function NoteContent({
href={match}
target="_blank"
rel="noreferrer"
className="line-clamp-1 text-blue-500 hover:text-blue-600"
className="text-blue-500 line-clamp-1 hover:text-blue-600"
>
{match}
</a>
@@ -92,25 +80,26 @@ export function NoteContent({
<div key={nanoid()} className="h-3" />
));
return { content: richContent, images, videos };
return richContent;
} catch (e) {
return { content, images, videos };
console.log("[parser]: ", e);
return event.content;
}
}, []);
}, [event.content]);
return (
<div className="flex flex-col gap-2">
<div
className={cn(
"select-text text-[15px] text-pretty content-break overflow-hidden",
event.content.length > 500 ? "max-h-[300px] gradient-mask-b-0" : "",
"select-text text-pretty content-break overflow-hidden",
event.content.length > 420 ? "max-h-[250px] gradient-mask-b-0" : "",
className,
)}
>
{data.content}
{content}
</div>
{data.images.length ? <Images urls={data.images} /> : null}
{data.videos.length ? <Videos urls={data.videos} /> : null}
{event.meta?.images.length ? <Images urls={event.meta.images} /> : null}
{event.meta?.videos.length ? <Videos urls={event.meta.videos} /> : null}
</div>
);
}