Browse Source
This applies a really basic version of the parsing in ndk-svelte-components which was copied from coracle. hopefully they can be fully aligned in the future. I applied extra typing and will intergrate other ParsedParts when needed. applied line breaks to commit messages, pr description and default for event content.master
7 changed files with 148 additions and 5 deletions
@ -0,0 +1,21 @@
@@ -0,0 +1,21 @@
|
||||
<script lang="ts"> |
||||
import type { NDKTag } from "@nostr-dev-kit/ndk"; |
||||
import { isParsedNewLine, isParsedText, parseContent } from "./utils"; |
||||
export let content: string = ""; |
||||
export let tags: NDKTag[] = []; |
||||
|
||||
const fullContent = parseContent({ content, tags }); |
||||
</script> |
||||
|
||||
<div> |
||||
{#each fullContent as part, i} |
||||
{#if isParsedNewLine(part)} |
||||
{#if part.value.length > 1} |
||||
<br /> |
||||
{/if} |
||||
<br /> |
||||
{:else if isParsedText(part)} |
||||
{part.value} |
||||
{/if} |
||||
{/each} |
||||
</div> |
||||
@ -0,0 +1,96 @@
@@ -0,0 +1,96 @@
|
||||
import type { NDKTag } from "@nostr-dev-kit/ndk"; |
||||
import { nip19 } from "nostr-tools"; |
||||
import { identity, last, pluck } from "ramda"; |
||||
|
||||
export const TOPIC = "topic"; |
||||
export const LINK = "link"; |
||||
export const LINKCOLLECTION = "link[]"; |
||||
export const HTML = "html"; |
||||
export const INVOICE = "invoice"; |
||||
export const NOSTR_NOTE = "nostr:note"; |
||||
export const NOSTR_NEVENT = "nostr:nevent"; |
||||
export const NOSTR_NPUB = "nostr:npub"; |
||||
export const NOSTR_NPROFILE = "nostr:nprofile"; |
||||
export const NOSTR_NADDR = "nostr:naddr"; |
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const first = (list: any) => (list ? list[0] : undefined); |
||||
|
||||
export const fromNostrURI = (s: string) => s.replace(/^[\w+]+:\/?\/?/, ""); |
||||
|
||||
export const urlIsMedia = (url: string) => |
||||
!url.match(/\.(apk|docx|xlsx|csv|dmg)/) && last(url.split("://"))?.includes("/"); |
||||
|
||||
export type ContentArgs = { |
||||
content: string; |
||||
tags?: Array<NDKTag>; |
||||
}; |
||||
|
||||
export type ParsedPart = ParsedNewLine | ParsedText; |
||||
|
||||
export const NEWLINE = "newline"; |
||||
|
||||
export type ParsedNewLine = { |
||||
type: "newline", |
||||
value: string, |
||||
}; |
||||
|
||||
export const isParsedNewLine = (part: ParsedPart): part is ParsedNewLine => { |
||||
return part.type == "newline" |
||||
}; |
||||
|
||||
export const TEXT = "text"; |
||||
|
||||
export type ParsedText = { |
||||
type: "text", |
||||
value: string, |
||||
}; |
||||
|
||||
export const isParsedText = (part: ParsedPart): part is ParsedText => { |
||||
return part.type == "text" |
||||
}; |
||||
|
||||
export const parseContent = ({ content, tags = [] }: ContentArgs): ParsedPart[] => { |
||||
const result: ParsedPart[] = []; |
||||
let text = content.trim(); |
||||
let buffer = ""; |
||||
|
||||
const parseNewline = () => { |
||||
const newline = first(text.match(/^\n+/)); |
||||
|
||||
if (newline) { |
||||
return [NEWLINE, newline, newline]; |
||||
} |
||||
}; |
||||
|
||||
while (text) { |
||||
// The order that this runs matters
|
||||
const part = |
||||
parseNewline(); |
||||
|
||||
if (part) { |
||||
if (buffer) { |
||||
result.push({ type: "text", value: buffer }); |
||||
buffer = ""; |
||||
} |
||||
|
||||
const [type, raw, value] = part; |
||||
|
||||
result.push({ type, value }); |
||||
text = text.slice(raw.length); |
||||
} else { |
||||
// Instead of going character by character and re-running all the above regular expressions
|
||||
// a million times, try to match the next word and add it to the buffer
|
||||
const match = first(text.match(/^[\w\d]+ ?/i)) || text[0]; |
||||
|
||||
buffer += match; |
||||
text = text.slice(match.length); |
||||
} |
||||
} |
||||
|
||||
if (buffer) { |
||||
result.push({ type: TEXT, value: buffer }); |
||||
} |
||||
|
||||
return result; |
||||
}; |
||||
Loading…
Reference in new issue