mirror of
https://github.com/BlowaterNostr/blowater.git
synced 2024-10-18 07:33:22 +00:00
refactor parseContent (#458)
Co-authored-by: BlowaterNostr <blowater.nostr@proton.me>
This commit is contained in:
parent
8169955d38
commit
2237b7bbb1
@ -666,9 +666,9 @@ export function generateTags(
|
|||||||
const parsedTextItems = parseContent(args.content);
|
const parsedTextItems = parseContent(args.content);
|
||||||
for (const item of parsedTextItems) {
|
for (const item of parsedTextItems) {
|
||||||
if (item.type === "nevent") {
|
if (item.type === "nevent") {
|
||||||
eTags.set(item.event.pointer.id, [item.event.pointer.relays?.[0] || "", "mention"]);
|
eTags.set(item.nevent.pointer.id, [item.nevent.pointer.relays?.[0] || "", "mention"]);
|
||||||
if (item.event.pointer.pubkey) {
|
if (item.nevent.pointer.pubkey) {
|
||||||
pTags.add(item.event.pointer.pubkey.hex);
|
pTags.add(item.nevent.pointer.pubkey.hex);
|
||||||
}
|
}
|
||||||
} else if (item.type === "npub") {
|
} else if (item.type === "npub") {
|
||||||
pTags.add(item.pubkey.hex);
|
pTags.add(item.pubkey.hex);
|
||||||
|
@ -204,36 +204,36 @@ export function ParseMessageContent(
|
|||||||
const parsedContentItems = parseContent(message.content);
|
const parsedContentItems = parseContent(message.content);
|
||||||
|
|
||||||
const vnode = [];
|
const vnode = [];
|
||||||
let start = 0;
|
|
||||||
for (const item of parsedContentItems) {
|
for (const item of parsedContentItems) {
|
||||||
vnode.push(message.content.slice(start, item.start));
|
if (item.type === "raw" || item.type === "tag") {
|
||||||
const itemStr = message.content.slice(item.start, item.end + 1);
|
vnode.push(item.text);
|
||||||
if (item.type == "url") {
|
} else if (item.type === "url") {
|
||||||
if (urlIsImage(itemStr)) {
|
if (urlIsImage(item.text)) {
|
||||||
vnode.push(
|
vnode.push(
|
||||||
<img
|
<img
|
||||||
class={`w-96 p-1 rounded-lg border-2 border-[${DividerBackgroundColor}]`}
|
class={`w-96 p-1 rounded-lg border-2 border-[${DividerBackgroundColor}]`}
|
||||||
src={itemStr}
|
src={item.text}
|
||||||
/>,
|
/>,
|
||||||
);
|
);
|
||||||
} else if (urlIsVideo(itemStr)) {
|
} else if (urlIsVideo(item.text)) {
|
||||||
vnode.push(
|
vnode.push(
|
||||||
<video
|
<video
|
||||||
class={`w-96 p-1 rounded-lg border-2 border-[${DividerBackgroundColor}]`}
|
class={`w-96 p-1 rounded-lg border-2 border-[${DividerBackgroundColor}]`}
|
||||||
controls
|
controls
|
||||||
src={itemStr}
|
src={item.text}
|
||||||
>
|
>
|
||||||
</video>,
|
</video>,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
vnode.push(
|
vnode.push(
|
||||||
<a target="_blank" class={`hover:underline text-[${LinkColor}]`} href={itemStr}>
|
<a target="_blank" class={`hover:underline text-[${LinkColor}]`} href={item.text}>
|
||||||
{itemStr}
|
{item.text}
|
||||||
</a>,
|
</a>,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else if (item.type == "npub") {
|
} else if (item.type === "npub" || item.type === "nprofile") {
|
||||||
const profile = getters.profileGetter.getProfileByPublicKey(item.pubkey);
|
const pubkey = item.type == "npub" ? item.pubkey : item.nprofile.pubkey;
|
||||||
|
const profile = getters.profileGetter.getProfileByPublicKey(pubkey);
|
||||||
const name = profile?.profile.name || profile?.profile.display_name;
|
const name = profile?.profile.name || profile?.profile.display_name;
|
||||||
vnode.push(
|
vnode.push(
|
||||||
<span
|
<span
|
||||||
@ -241,16 +241,16 @@ export function ParseMessageContent(
|
|||||||
onClick={() =>
|
onClick={() =>
|
||||||
emit({
|
emit({
|
||||||
type: "ViewUserDetail",
|
type: "ViewUserDetail",
|
||||||
pubkey: item.pubkey,
|
pubkey: pubkey,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{name ? `@${name}` : item.pubkey.bech32()}
|
{name ? `@${name}` : pubkey.bech32()}
|
||||||
</span>,
|
</span>,
|
||||||
);
|
);
|
||||||
} else if (item.type == "note") {
|
} else if (item.type === "note") {
|
||||||
const event = getters.getEventByID(item.noteID);
|
const event = getters.getEventByID(item.noteID);
|
||||||
if (event == undefined || event.kind == NostrKind.DIRECT_MESSAGE) {
|
if (event == undefined || event.kind == NostrKind.DIRECT_MESSAGE) {
|
||||||
vnode.push(itemStr);
|
vnode.push(item.text);
|
||||||
emit({
|
emit({
|
||||||
type: "SyncEvent",
|
type: "SyncEvent",
|
||||||
eventID: item.noteID.hex,
|
eventID: item.noteID.hex,
|
||||||
@ -259,26 +259,22 @@ export function ParseMessageContent(
|
|||||||
const profile = getters.profileGetter.getProfileByPublicKey(event.publicKey);
|
const profile = getters.profileGetter.getProfileByPublicKey(event.publicKey);
|
||||||
vnode.push(Card(event, profile?.profile, emit, event.publicKey));
|
vnode.push(Card(event, profile?.profile, emit, event.publicKey));
|
||||||
}
|
}
|
||||||
} else if (item.type == "nevent") {
|
} else if (item.type === "nevent") {
|
||||||
const event = getters.getEventByID(NoteID.FromString(item.event.pointer.id));
|
const event = getters.getEventByID(NoteID.FromString(item.nevent.pointer.id));
|
||||||
if (
|
if (
|
||||||
event == undefined || event.kind == NostrKind.DIRECT_MESSAGE
|
event == undefined || event.kind == NostrKind.DIRECT_MESSAGE
|
||||||
) {
|
) {
|
||||||
vnode.push(itemStr);
|
vnode.push(item.text);
|
||||||
emit({
|
emit({
|
||||||
type: "SyncEvent",
|
type: "SyncEvent",
|
||||||
eventID: item.event.pointer.id,
|
eventID: item.nevent.pointer.id,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
const profile = getters.profileGetter.getProfileByPublicKey(event.publicKey);
|
const profile = getters.profileGetter.getProfileByPublicKey(event.publicKey);
|
||||||
vnode.push(Card(event, profile ? profile.profile : undefined, emit, event.publicKey));
|
vnode.push(Card(event, profile ? profile.profile : undefined, emit, event.publicKey));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
start = item.end + 1;
|
|
||||||
}
|
}
|
||||||
vnode.push(message.content.slice(start));
|
|
||||||
|
|
||||||
return vnode;
|
return vnode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,175 +1,195 @@
|
|||||||
import { assertEquals } from "https://deno.land/std@0.202.0/testing/asserts.ts";
|
import { assertEquals } from "https://deno.land/std@0.202.0/assert/assert_equals.ts";
|
||||||
import { ChatMessage, findUrlInString, groupContinuousMessages, parseContent } from "./message.ts";
|
import {
|
||||||
|
ChatMessage,
|
||||||
|
ContentItem,
|
||||||
|
findUrlInString,
|
||||||
|
groupContinuousMessages,
|
||||||
|
parseContent,
|
||||||
|
} from "./message.ts";
|
||||||
import { PrivateKey, PublicKey } from "../../libs/nostr.ts/key.ts";
|
import { PrivateKey, PublicKey } from "../../libs/nostr.ts/key.ts";
|
||||||
|
|
||||||
import { NostrKind } from "../../libs/nostr.ts/nostr.ts";
|
import { NostrKind } from "../../libs/nostr.ts/nostr.ts";
|
||||||
import { Nevent, NostrAddress } from "../../libs/nostr.ts/nip19.ts";
|
import { Nevent, NostrAddress, NostrProfile } from "../../libs/nostr.ts/nip19.ts";
|
||||||
|
|
||||||
Deno.test("inline parse", async (t) => {
|
Deno.test("inline parse", async (t) => {
|
||||||
const data = [
|
const data: {
|
||||||
|
input: string;
|
||||||
|
output: ContentItem[];
|
||||||
|
}[] = [
|
||||||
|
{
|
||||||
|
input: "",
|
||||||
|
output: [],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
input: `nothing`,
|
input: `nothing`,
|
||||||
output: [],
|
output: [{
|
||||||
|
text: "nothing",
|
||||||
|
type: "raw",
|
||||||
|
}],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input:
|
input:
|
||||||
`https://nostr.build/i/f91187675750791b652f7e129b374c2b682d7cc0e9dbc28def58ffdf66508867.jpg`,
|
`https://nostr.build/i/f91187675750791b652f7e129b374c2b682d7cc0e9dbc28def58ffdf66508867.jpg`,
|
||||||
output: [{
|
output: [{
|
||||||
|
text:
|
||||||
|
"https://nostr.build/i/f91187675750791b652f7e129b374c2b682d7cc0e9dbc28def58ffdf66508867.jpg",
|
||||||
type: "url",
|
type: "url",
|
||||||
start: 0,
|
|
||||||
end: 89,
|
|
||||||
}],
|
}],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input:
|
input:
|
||||||
` https://nostr.build/i/f91187675750791b652f7e129b374c2b682d7cc0e9dbc28def58ffdf66508867.jpg`,
|
` https://nostr.build/i/f91187675750791b652f7e129b374c2b682d7cc0e9dbc28def58ffdf66508867.jpg`,
|
||||||
output: [{
|
output: [
|
||||||
type: "url",
|
{
|
||||||
start: 1,
|
text: " ",
|
||||||
end: 90,
|
type: "raw",
|
||||||
}],
|
},
|
||||||
|
{
|
||||||
|
text:
|
||||||
|
"https://nostr.build/i/f91187675750791b652f7e129b374c2b682d7cc0e9dbc28def58ffdf66508867.jpg",
|
||||||
|
type: "url",
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input:
|
input:
|
||||||
`https://nostr.build/i/f91187675750791b652f7e129b374c2b682d7cc0e9dbc28def58ffdf66508867.jpg `,
|
`https://nostr.build/i/f91187675750791b652f7e129b374c2b682d7cc0e9dbc28def58ffdf66508867.jpg `,
|
||||||
output: [{
|
output: [
|
||||||
type: "url",
|
{
|
||||||
start: 0,
|
text:
|
||||||
end: 89,
|
"https://nostr.build/i/f91187675750791b652f7e129b374c2b682d7cc0e9dbc28def58ffdf66508867.jpg",
|
||||||
}],
|
type: "url",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: " ",
|
||||||
|
type: "raw",
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input:
|
input:
|
||||||
` https://nostr.build/i/f91187675750791b652f7e129b374c2b682d7cc0e9dbc28def58ffdf66508867.jpg `,
|
` https://nostr.build/i/f91187675750791b652f7e129b374c2b682d7cc0e9dbc28def58ffdf66508867.jpg `,
|
||||||
output: [{
|
output: [{
|
||||||
|
text: " ",
|
||||||
|
type: "raw",
|
||||||
|
}, {
|
||||||
|
text:
|
||||||
|
"https://nostr.build/i/f91187675750791b652f7e129b374c2b682d7cc0e9dbc28def58ffdf66508867.jpg",
|
||||||
type: "url",
|
type: "url",
|
||||||
start: 1,
|
}, {
|
||||||
end: 90,
|
text: " ",
|
||||||
|
type: "raw",
|
||||||
}],
|
}],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: `Hi https://some.jpg`,
|
input: `Hi https://some.jpg`,
|
||||||
output: [{
|
output: [
|
||||||
type: "url",
|
{
|
||||||
start: 3,
|
text: "Hi ",
|
||||||
end: 18,
|
type: "raw",
|
||||||
}],
|
},
|
||||||
|
{
|
||||||
|
text: "https://some.jpg",
|
||||||
|
type: "url",
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: `Hi https://some.jpg http://some.jpg`,
|
input: `Hi https://some.jpg http://some.jpg`,
|
||||||
output: [{
|
output: [{
|
||||||
type: "url",
|
text: "Hi ",
|
||||||
start: 3,
|
type: "raw",
|
||||||
end: 18,
|
|
||||||
}, {
|
}, {
|
||||||
|
text: "https://some.jpg",
|
||||||
|
type: "url",
|
||||||
|
}, {
|
||||||
|
text: " ",
|
||||||
|
type: "raw",
|
||||||
|
}, {
|
||||||
|
text: "http://some.jpg",
|
||||||
type: "url",
|
type: "url",
|
||||||
start: 20,
|
|
||||||
end: 34,
|
|
||||||
}],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: `nostr:npub17dxnfw2vrhgtk4fgqdmpuqxv05u9raau3w0shay7msmr0dzs4m7s6ng4ylログボ`,
|
|
||||||
output: [{
|
|
||||||
type: "npub",
|
|
||||||
pubkey: PublicKey.FromHex("f34d34b94c1dd0bb552803761e00cc7d3851f7bc8b9f0bf49edc3637b450aefd"),
|
|
||||||
start: 0,
|
|
||||||
end: 68,
|
|
||||||
}],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input: `sherryiscutenpub17dxnfw2vrhgtk4fgqdmpuqxv05u9raau3w0shay7msmr0dzs4m7s6ng4ylログボ`,
|
|
||||||
output: [{
|
|
||||||
type: "npub",
|
|
||||||
pubkey: PublicKey.FromHex("f34d34b94c1dd0bb552803761e00cc7d3851f7bc8b9f0bf49edc3637b450aefd"),
|
|
||||||
start: 12,
|
|
||||||
end: 74,
|
|
||||||
}],
|
}],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: `npub17dxnfw2vrhgtk4fgqdmpuqxv05u9raau3w0shay7msmr0dzs4m7s6ng4yl`,
|
input: `npub17dxnfw2vrhgtk4fgqdmpuqxv05u9raau3w0shay7msmr0dzs4m7s6ng4yl`,
|
||||||
output: [{
|
output: [{
|
||||||
|
text: "npub17dxnfw2vrhgtk4fgqdmpuqxv05u9raau3w0shay7msmr0dzs4m7s6ng4yl",
|
||||||
type: "npub",
|
type: "npub",
|
||||||
pubkey: PublicKey.FromHex("f34d34b94c1dd0bb552803761e00cc7d3851f7bc8b9f0bf49edc3637b450aefd"),
|
pubkey: PublicKey.FromBech32(
|
||||||
start: 0,
|
"npub17dxnfw2vrhgtk4fgqdmpuqxv05u9raau3w0shay7msmr0dzs4m7s6ng4yl",
|
||||||
end: 62,
|
) as PublicKey,
|
||||||
}],
|
}],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
input: `nostr:npub17dxnfw2vrhgtk4fgqdmpuqxv05u9raau3w0shay7msmr0dzs4m7s6ng4ylログボ`,
|
||||||
|
output: [{
|
||||||
|
text: "nostr:npub17dxnfw2vrhgtk4fgqdmpuqxv05u9raau3w0shay7msmr0dzs4m7s6ng4yl",
|
||||||
|
type: "npub",
|
||||||
|
pubkey: PublicKey.FromBech32(
|
||||||
|
"npub17dxnfw2vrhgtk4fgqdmpuqxv05u9raau3w0shay7msmr0dzs4m7s6ng4yl",
|
||||||
|
) as PublicKey,
|
||||||
|
}, {
|
||||||
|
text: "ログボ",
|
||||||
|
type: "raw",
|
||||||
|
}],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: `sherryiscutenpub17dxnfw2vrhgtk4fgqdmpuqxv05u9raau3w0shay7msmr0dzs4m7s6ng4ylログボ`,
|
||||||
|
output: [{
|
||||||
|
text: "sherryiscute",
|
||||||
|
type: "raw",
|
||||||
|
}, {
|
||||||
|
text: "npub17dxnfw2vrhgtk4fgqdmpuqxv05u9raau3w0shay7msmr0dzs4m7s6ng4yl",
|
||||||
|
type: "npub",
|
||||||
|
pubkey: PublicKey.FromBech32(
|
||||||
|
"npub17dxnfw2vrhgtk4fgqdmpuqxv05u9raau3w0shay7msmr0dzs4m7s6ng4yl",
|
||||||
|
) as PublicKey,
|
||||||
|
}, {
|
||||||
|
text: "ログボ",
|
||||||
|
type: "raw",
|
||||||
|
}],
|
||||||
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
input:
|
input:
|
||||||
`nostr:nprofile1qqsf37u9q4up37etd4w4fgdfkxvurxk74gcmsf9ea0g7vgyasfdjeycpp4mhxue69uhkummn9ekx7mqpz3mhxue69uhhyetvv9ujuerpd46hxtnfduqscamnwvaz7tmzwf3zu6t0qyd8wumn8ghj7mn0wd68ytn0wfskuem9wp5kcmpwv3jhvqghwaehxw309aex2mrp0yhxxatjwfjkuapwveukjqgswaehxw309ahx7um5wgh8w6twv5q3samnwvaz7tmjv4kxz7fwwdhx7un59eek7cmfv9kqz9thwden5te0v4jx2m3wdehhxarj9ekxzmnyqyd8wumn8ghj7un9d3shjtnwdaehgun8wfshq6pwdejhgqgewaehxw309ac82unpwe5kgcfwdehhxarj9ekxzmnyqyvhwumn8ghj7mn0wd68ytn6v43x2er9v5hxxmr0w4jqzynhwden5te0wp6hyurvv4cxzeewv4esz9nhwden5te0v96xcctn9ehx7um5wghxcctwvsq3camnwvaz7tmwdaehgu3wd46hg6tw09mkzmrvv46zucm0d5lxp0l4`,
|
`nostr:nprofile1qqsf37u9q4up37etd4w4fgdfkxvurxk74gcmsf9ea0g7vgyasfdjeycpp4mhxue69uhkummn9ekx7mqpz3mhxue69uhhyetvv9ujuerpd46hxtnfduqscamnwvaz7tmzwf3zu6t0qyd8wumn8ghj7mn0wd68ytn0wfskuem9wp5kcmpwv3jhvqghwaehxw309aex2mrp0yhxxatjwfjkuapwveukjqgswaehxw309ahx7um5wgh8w6twv5q3samnwvaz7tmjv4kxz7fwwdhx7un59eek7cmfv9kqz9thwden5te0v4jx2m3wdehhxarj9ekxzmnyqyd8wumn8ghj7un9d3shjtnwdaehgun8wfshq6pwdejhgqgewaehxw309ac82unpwe5kgcfwdehhxarj9ekxzmnyqyvhwumn8ghj7mn0wd68ytn6v43x2er9v5hxxmr0w4jqzynhwden5te0wp6hyurvv4cxzeewv4esz9nhwden5te0v96xcctn9ehx7um5wghxcctwvsq3camnwvaz7tmwdaehgu3wd46hg6tw09mkzmrvv46zucm0d5lxp0l4`,
|
||||||
output: [{
|
output: [{
|
||||||
type: "npub",
|
type: "nprofile",
|
||||||
pubkey: PublicKey.FromHex("98fb85057818fb2b6d5d54a1a9b199c19adeaa31b824b9ebd1e6209d825b2c93"),
|
text:
|
||||||
start: 0,
|
"nostr:nprofile1qqsf37u9q4up37etd4w4fgdfkxvurxk74gcmsf9ea0g7vgyasfdjeycpp4mhxue69uhkummn9ekx7mqpz3mhxue69uhhyetvv9ujuerpd46hxtnfduqscamnwvaz7tmzwf3zu6t0qyd8wumn8ghj7mn0wd68ytn0wfskuem9wp5kcmpwv3jhvqghwaehxw309aex2mrp0yhxxatjwfjkuapwveukjqgswaehxw309ahx7um5wgh8w6twv5q3samnwvaz7tmjv4kxz7fwwdhx7un59eek7cmfv9kqz9thwden5te0v4jx2m3wdehhxarj9ekxzmnyqyd8wumn8ghj7un9d3shjtnwdaehgun8wfshq6pwdejhgqgewaehxw309ac82unpwe5kgcfwdehhxarj9ekxzmnyqyvhwumn8ghj7mn0wd68ytn6v43x2er9v5hxxmr0w4jqzynhwden5te0wp6hyurvv4cxzeewv4esz9nhwden5te0v96xcctn9ehx7um5wghxcctwvsq3camnwvaz7tmwdaehgu3wd46hg6tw09mkzmrvv46zucm0d5lxp0l4",
|
||||||
end: 598,
|
nprofile: NostrProfile.decode(
|
||||||
relays: [
|
"nprofile1qqsf37u9q4up37etd4w4fgdfkxvurxk74gcmsf9ea0g7vgyasfdjeycpp4mhxue69uhkummn9ekx7mqpz3mhxue69uhhyetvv9ujuerpd46hxtnfduqscamnwvaz7tmzwf3zu6t0qyd8wumn8ghj7mn0wd68ytn0wfskuem9wp5kcmpwv3jhvqghwaehxw309aex2mrp0yhxxatjwfjkuapwveukjqgswaehxw309ahx7um5wgh8w6twv5q3samnwvaz7tmjv4kxz7fwwdhx7un59eek7cmfv9kqz9thwden5te0v4jx2m3wdehhxarj9ekxzmnyqyd8wumn8ghj7un9d3shjtnwdaehgun8wfshq6pwdejhgqgewaehxw309ac82unpwe5kgcfwdehhxarj9ekxzmnyqyvhwumn8ghj7mn0wd68ytn6v43x2er9v5hxxmr0w4jqzynhwden5te0wp6hyurvv4cxzeewv4esz9nhwden5te0v96xcctn9ehx7um5wghxcctwvsq3camnwvaz7tmwdaehgu3wd46hg6tw09mkzmrvv46zucm0d5lxp0l4",
|
||||||
"wss://nos.lol",
|
) as NostrProfile,
|
||||||
"wss://relay.damus.io",
|
|
||||||
"wss://brb.io",
|
|
||||||
"wss://nostr.orangepill.dev",
|
|
||||||
"wss://relay.current.fyi",
|
|
||||||
"wss://nostr.wine",
|
|
||||||
"wss://relay.snort.social",
|
|
||||||
"wss://eden.nostr.land",
|
|
||||||
"wss://relay.nostrgraph.net",
|
|
||||||
"wss://puravida.nostr.land",
|
|
||||||
"wss://nostr.zebedee.cloud",
|
|
||||||
"wss://purplepag.es",
|
|
||||||
"wss://atlas.nostr.land",
|
|
||||||
"wss://nostr.mutinywallet.com",
|
|
||||||
],
|
|
||||||
}],
|
}],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input:
|
input:
|
||||||
`sherryiscutenprofile1qqsf37u9q4up37etd4w4fgdfkxvurxk74gcmsf9ea0g7vgyasfdjeycpp4mhxue69uhkummn9ekx7mqpz3mhxue69uhhyetvv9ujuerpd46hxtnfduqscamnwvaz7tmzwf3zu6t0qyd8wumn8ghj7mn0wd68ytn0wfskuem9wp5kcmpwv3jhvqghwaehxw309aex2mrp0yhxxatjwfjkuapwveukjqgswaehxw309ahx7um5wgh8w6twv5q3samnwvaz7tmjv4kxz7fwwdhx7un59eek7cmfv9kqz9thwden5te0v4jx2m3wdehhxarj9ekxzmnyqyd8wumn8ghj7un9d3shjtnwdaehgun8wfshq6pwdejhgqgewaehxw309ac82unpwe5kgcfwdehhxarj9ekxzmnyqyvhwumn8ghj7mn0wd68ytn6v43x2er9v5hxxmr0w4jqzynhwden5te0wp6hyurvv4cxzeewv4esz9nhwden5te0v96xcctn9ehx7um5wghxcctwvsq3camnwvaz7tmwdaehgu3wd46hg6tw09mkzmrvv46zucm0d5lxp0l4 123`,
|
`sherryiscutenprofile1qqsf37u9q4up37etd4w4fgdfkxvurxk74gcmsf9ea0g7vgyasfdjeycpp4mhxue69uhkummn9ekx7mqpz3mhxue69uhhyetvv9ujuerpd46hxtnfduqscamnwvaz7tmzwf3zu6t0qyd8wumn8ghj7mn0wd68ytn0wfskuem9wp5kcmpwv3jhvqghwaehxw309aex2mrp0yhxxatjwfjkuapwveukjqgswaehxw309ahx7um5wgh8w6twv5q3samnwvaz7tmjv4kxz7fwwdhx7un59eek7cmfv9kqz9thwden5te0v4jx2m3wdehhxarj9ekxzmnyqyd8wumn8ghj7un9d3shjtnwdaehgun8wfshq6pwdejhgqgewaehxw309ac82unpwe5kgcfwdehhxarj9ekxzmnyqyvhwumn8ghj7mn0wd68ytn6v43x2er9v5hxxmr0w4jqzynhwden5te0wp6hyurvv4cxzeewv4esz9nhwden5te0v96xcctn9ehx7um5wghxcctwvsq3camnwvaz7tmwdaehgu3wd46hg6tw09mkzmrvv46zucm0d5lxp0l4 123`,
|
||||||
output: [{
|
output: [{
|
||||||
type: "npub",
|
text: "sherryiscute",
|
||||||
pubkey: PublicKey.FromHex("98fb85057818fb2b6d5d54a1a9b199c19adeaa31b824b9ebd1e6209d825b2c93"),
|
type: "raw",
|
||||||
start: 12,
|
}, {
|
||||||
end: 604,
|
type: "nprofile",
|
||||||
relays: [
|
text:
|
||||||
"wss://nos.lol",
|
"nprofile1qqsf37u9q4up37etd4w4fgdfkxvurxk74gcmsf9ea0g7vgyasfdjeycpp4mhxue69uhkummn9ekx7mqpz3mhxue69uhhyetvv9ujuerpd46hxtnfduqscamnwvaz7tmzwf3zu6t0qyd8wumn8ghj7mn0wd68ytn0wfskuem9wp5kcmpwv3jhvqghwaehxw309aex2mrp0yhxxatjwfjkuapwveukjqgswaehxw309ahx7um5wgh8w6twv5q3samnwvaz7tmjv4kxz7fwwdhx7un59eek7cmfv9kqz9thwden5te0v4jx2m3wdehhxarj9ekxzmnyqyd8wumn8ghj7un9d3shjtnwdaehgun8wfshq6pwdejhgqgewaehxw309ac82unpwe5kgcfwdehhxarj9ekxzmnyqyvhwumn8ghj7mn0wd68ytn6v43x2er9v5hxxmr0w4jqzynhwden5te0wp6hyurvv4cxzeewv4esz9nhwden5te0v96xcctn9ehx7um5wghxcctwvsq3camnwvaz7tmwdaehgu3wd46hg6tw09mkzmrvv46zucm0d5lxp0l4",
|
||||||
"wss://relay.damus.io",
|
nprofile: NostrProfile.decode(
|
||||||
"wss://brb.io",
|
"nprofile1qqsf37u9q4up37etd4w4fgdfkxvurxk74gcmsf9ea0g7vgyasfdjeycpp4mhxue69uhkummn9ekx7mqpz3mhxue69uhhyetvv9ujuerpd46hxtnfduqscamnwvaz7tmzwf3zu6t0qyd8wumn8ghj7mn0wd68ytn0wfskuem9wp5kcmpwv3jhvqghwaehxw309aex2mrp0yhxxatjwfjkuapwveukjqgswaehxw309ahx7um5wgh8w6twv5q3samnwvaz7tmjv4kxz7fwwdhx7un59eek7cmfv9kqz9thwden5te0v4jx2m3wdehhxarj9ekxzmnyqyd8wumn8ghj7un9d3shjtnwdaehgun8wfshq6pwdejhgqgewaehxw309ac82unpwe5kgcfwdehhxarj9ekxzmnyqyvhwumn8ghj7mn0wd68ytn6v43x2er9v5hxxmr0w4jqzynhwden5te0wp6hyurvv4cxzeewv4esz9nhwden5te0v96xcctn9ehx7um5wghxcctwvsq3camnwvaz7tmwdaehgu3wd46hg6tw09mkzmrvv46zucm0d5lxp0l4",
|
||||||
"wss://nostr.orangepill.dev",
|
) as NostrProfile,
|
||||||
"wss://relay.current.fyi",
|
}, {
|
||||||
"wss://nostr.wine",
|
text: " 123",
|
||||||
"wss://relay.snort.social",
|
type: "raw",
|
||||||
"wss://eden.nostr.land",
|
|
||||||
"wss://relay.nostrgraph.net",
|
|
||||||
"wss://puravida.nostr.land",
|
|
||||||
"wss://nostr.zebedee.cloud",
|
|
||||||
"wss://purplepag.es",
|
|
||||||
"wss://atlas.nostr.land",
|
|
||||||
"wss://nostr.mutinywallet.com",
|
|
||||||
],
|
|
||||||
}],
|
}],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input:
|
input:
|
||||||
`nprofile1qqsf37u9q4up37etd4w4fgdfkxvurxk74gcmsf9ea0g7vgyasfdjeycpp4mhxue69uhkummn9ekx7mqpz3mhxue69uhhyetvv9ujuerpd46hxtnfduqscamnwvaz7tmzwf3zu6t0qyd8wumn8ghj7mn0wd68ytn0wfskuem9wp5kcmpwv3jhvqghwaehxw309aex2mrp0yhxxatjwfjkuapwveukjqgswaehxw309ahx7um5wgh8w6twv5q3samnwvaz7tmjv4kxz7fwwdhx7un59eek7cmfv9kqz9thwden5te0v4jx2m3wdehhxarj9ekxzmnyqyd8wumn8ghj7un9d3shjtnwdaehgun8wfshq6pwdejhgqgewaehxw309ac82unpwe5kgcfwdehhxarj9ekxzmnyqyvhwumn8ghj7mn0wd68ytn6v43x2er9v5hxxmr0w4jqzynhwden5te0wp6hyurvv4cxzeewv4esz9nhwden5te0v96xcctn9ehx7um5wghxcctwvsq3camnwvaz7tmwdaehgu3wd46hg6tw09mkzmrvv46zucm0d5lxp0l4`,
|
`nprofile1qqsf37u9q4up37etd4w4fgdfkxvurxk74gcmsf9ea0g7vgyasfdjeycpp4mhxue69uhkummn9ekx7mqpz3mhxue69uhhyetvv9ujuerpd46hxtnfduqscamnwvaz7tmzwf3zu6t0qyd8wumn8ghj7mn0wd68ytn0wfskuem9wp5kcmpwv3jhvqghwaehxw309aex2mrp0yhxxatjwfjkuapwveukjqgswaehxw309ahx7um5wgh8w6twv5q3samnwvaz7tmjv4kxz7fwwdhx7un59eek7cmfv9kqz9thwden5te0v4jx2m3wdehhxarj9ekxzmnyqyd8wumn8ghj7un9d3shjtnwdaehgun8wfshq6pwdejhgqgewaehxw309ac82unpwe5kgcfwdehhxarj9ekxzmnyqyvhwumn8ghj7mn0wd68ytn6v43x2er9v5hxxmr0w4jqzynhwden5te0wp6hyurvv4cxzeewv4esz9nhwden5te0v96xcctn9ehx7um5wghxcctwvsq3camnwvaz7tmwdaehgu3wd46hg6tw09mkzmrvv46zucm0d5lxp0l4`,
|
||||||
output: [{
|
output: [{
|
||||||
type: "npub",
|
type: "nprofile",
|
||||||
pubkey: PublicKey.FromHex("98fb85057818fb2b6d5d54a1a9b199c19adeaa31b824b9ebd1e6209d825b2c93"),
|
text:
|
||||||
start: 0,
|
"nprofile1qqsf37u9q4up37etd4w4fgdfkxvurxk74gcmsf9ea0g7vgyasfdjeycpp4mhxue69uhkummn9ekx7mqpz3mhxue69uhhyetvv9ujuerpd46hxtnfduqscamnwvaz7tmzwf3zu6t0qyd8wumn8ghj7mn0wd68ytn0wfskuem9wp5kcmpwv3jhvqghwaehxw309aex2mrp0yhxxatjwfjkuapwveukjqgswaehxw309ahx7um5wgh8w6twv5q3samnwvaz7tmjv4kxz7fwwdhx7un59eek7cmfv9kqz9thwden5te0v4jx2m3wdehhxarj9ekxzmnyqyd8wumn8ghj7un9d3shjtnwdaehgun8wfshq6pwdejhgqgewaehxw309ac82unpwe5kgcfwdehhxarj9ekxzmnyqyvhwumn8ghj7mn0wd68ytn6v43x2er9v5hxxmr0w4jqzynhwden5te0wp6hyurvv4cxzeewv4esz9nhwden5te0v96xcctn9ehx7um5wghxcctwvsq3camnwvaz7tmwdaehgu3wd46hg6tw09mkzmrvv46zucm0d5lxp0l4",
|
||||||
end: 592,
|
nprofile: NostrProfile.decode(
|
||||||
relays: [
|
"nprofile1qqsf37u9q4up37etd4w4fgdfkxvurxk74gcmsf9ea0g7vgyasfdjeycpp4mhxue69uhkummn9ekx7mqpz3mhxue69uhhyetvv9ujuerpd46hxtnfduqscamnwvaz7tmzwf3zu6t0qyd8wumn8ghj7mn0wd68ytn0wfskuem9wp5kcmpwv3jhvqghwaehxw309aex2mrp0yhxxatjwfjkuapwveukjqgswaehxw309ahx7um5wgh8w6twv5q3samnwvaz7tmjv4kxz7fwwdhx7un59eek7cmfv9kqz9thwden5te0v4jx2m3wdehhxarj9ekxzmnyqyd8wumn8ghj7un9d3shjtnwdaehgun8wfshq6pwdejhgqgewaehxw309ac82unpwe5kgcfwdehhxarj9ekxzmnyqyvhwumn8ghj7mn0wd68ytn6v43x2er9v5hxxmr0w4jqzynhwden5te0wp6hyurvv4cxzeewv4esz9nhwden5te0v96xcctn9ehx7um5wghxcctwvsq3camnwvaz7tmwdaehgu3wd46hg6tw09mkzmrvv46zucm0d5lxp0l4",
|
||||||
"wss://nos.lol",
|
) as NostrProfile,
|
||||||
"wss://relay.damus.io",
|
|
||||||
"wss://brb.io",
|
|
||||||
"wss://nostr.orangepill.dev",
|
|
||||||
"wss://relay.current.fyi",
|
|
||||||
"wss://nostr.wine",
|
|
||||||
"wss://relay.snort.social",
|
|
||||||
"wss://eden.nostr.land",
|
|
||||||
"wss://relay.nostrgraph.net",
|
|
||||||
"wss://puravida.nostr.land",
|
|
||||||
"wss://nostr.zebedee.cloud",
|
|
||||||
"wss://purplepag.es",
|
|
||||||
"wss://atlas.nostr.land",
|
|
||||||
"wss://nostr.mutinywallet.com",
|
|
||||||
],
|
|
||||||
}],
|
}],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -177,8 +197,8 @@ Deno.test("inline parse", async (t) => {
|
|||||||
`naddr1qqxnzd3exsmnjvphxqunqv33qgsp7hwmlh5zccs55shzpfued50pznvypj0wwzn00dtyjzlqkr04w4grqsqqqa28vct2px`,
|
`naddr1qqxnzd3exsmnjvphxqunqv33qgsp7hwmlh5zccs55shzpfued50pznvypj0wwzn00dtyjzlqkr04w4grqsqqqa28vct2px`,
|
||||||
output: [{
|
output: [{
|
||||||
type: "naddr",
|
type: "naddr",
|
||||||
start: 0,
|
text:
|
||||||
end: 99,
|
"naddr1qqxnzd3exsmnjvphxqunqv33qgsp7hwmlh5zccs55shzpfued50pznvypj0wwzn00dtyjzlqkr04w4grqsqqqa28vct2px",
|
||||||
addr: new NostrAddress({
|
addr: new NostrAddress({
|
||||||
pubkey: PublicKey.FromHex(
|
pubkey: PublicKey.FromHex(
|
||||||
"1f5ddbfde82c6214a42e20a7996d1e114d840c9ee70a6f7b56490be0b0df5755",
|
"1f5ddbfde82c6214a42e20a7996d1e114d840c9ee70a6f7b56490be0b0df5755",
|
||||||
@ -193,8 +213,10 @@ Deno.test("inline parse", async (t) => {
|
|||||||
input:
|
input:
|
||||||
`nostr:nevent1qqsz25j8nrppstgmyry8hgsg4fggtfa6xnym2n4c2xth7usxtydtgpcpp4mhxue69uhhjctzw5hx6egzyze7g05vclndlu36x0vjzw37jykcjkcu8ep9qfqwpjvahmlrq6947qcyqqqqqqgj5mjek`,
|
`nostr:nevent1qqsz25j8nrppstgmyry8hgsg4fggtfa6xnym2n4c2xth7usxtydtgpcpp4mhxue69uhhjctzw5hx6egzyze7g05vclndlu36x0vjzw37jykcjkcu8ep9qfqwpjvahmlrq6947qcyqqqqqqgj5mjek`,
|
||||||
output: [{
|
output: [{
|
||||||
end: 161,
|
text:
|
||||||
event: new Nevent(
|
"nostr:nevent1qqsz25j8nrppstgmyry8hgsg4fggtfa6xnym2n4c2xth7usxtydtgpcpp4mhxue69uhhjctzw5hx6egzyze7g05vclndlu36x0vjzw37jykcjkcu8ep9qfqwpjvahmlrq6947qcyqqqqqqgj5mjek",
|
||||||
|
type: "nevent",
|
||||||
|
nevent: new Nevent(
|
||||||
{
|
{
|
||||||
id: "25524798c2182d1b20c87ba208aa5085a7ba34c9b54eb851977f7206591ab407",
|
id: "25524798c2182d1b20c87ba208aa5085a7ba34c9b54eb851977f7206591ab407",
|
||||||
kind: 1,
|
kind: 1,
|
||||||
@ -206,42 +228,90 @@ Deno.test("inline parse", async (t) => {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
start: 0,
|
|
||||||
type: "nevent",
|
|
||||||
}],
|
}],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: `Thank you #[0] #[2]#[3]`,
|
input: `Thank you #[0] #[2]#[3]`,
|
||||||
output: [{
|
output: [
|
||||||
type: "tag",
|
{
|
||||||
start: 10,
|
type: "raw",
|
||||||
end: 13,
|
text: "Thank you ",
|
||||||
}, {
|
},
|
||||||
type: "tag",
|
{
|
||||||
start: 16,
|
type: "tag",
|
||||||
end: 19,
|
text: "#[0]",
|
||||||
}, {
|
},
|
||||||
type: "tag",
|
{
|
||||||
start: 20,
|
type: "raw",
|
||||||
end: 23,
|
text: " ",
|
||||||
}],
|
},
|
||||||
|
{
|
||||||
|
type: "tag",
|
||||||
|
text: "#[2]",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "tag",
|
||||||
|
text: "#[3]",
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input:
|
input:
|
||||||
"You have been invited to group npub1k9p03z0gqsz2dqvjrkp6337lq5tl9nzj4wx0sfrpjmje2ze8nyls424ds3",
|
`nostr:npub17dxnfw2vrhgtk4fgqdmpuqxv05u9raau3w0shay7msmr0dzs4m7s6ng4yl https://example.com`,
|
||||||
|
output: [
|
||||||
|
{
|
||||||
|
type: "npub",
|
||||||
|
text: "nostr:npub17dxnfw2vrhgtk4fgqdmpuqxv05u9raau3w0shay7msmr0dzs4m7s6ng4yl",
|
||||||
|
pubkey: PublicKey.FromBech32(
|
||||||
|
"npub17dxnfw2vrhgtk4fgqdmpuqxv05u9raau3w0shay7msmr0dzs4m7s6ng4yl",
|
||||||
|
) as PublicKey,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "raw",
|
||||||
|
text: " ",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "url",
|
||||||
|
text: "https://example.com",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input:
|
||||||
|
`hi https://example.com nostr:npub17dxnfw2vrhgtk4fgqdmpuqxv05u9raau3w0shay7msmr0dzs4m7s6ng4yl`,
|
||||||
|
output: [
|
||||||
|
{
|
||||||
|
type: "raw",
|
||||||
|
text: "hi ",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "url",
|
||||||
|
text: "https://example.com",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "raw",
|
||||||
|
text: " ",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "npub",
|
||||||
|
text: "nostr:npub17dxnfw2vrhgtk4fgqdmpuqxv05u9raau3w0shay7msmr0dzs4m7s6ng4yl",
|
||||||
|
pubkey: PublicKey.FromBech32(
|
||||||
|
"npub17dxnfw2vrhgtk4fgqdmpuqxv05u9raau3w0shay7msmr0dzs4m7s6ng4yl",
|
||||||
|
) as PublicKey,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: `pubkey error: nostr:npub1xxxxxxxxrhgtk4fgqdmpuqxv05u9raau3w0shay7msmr0dzs4m7sxxxxxx`,
|
||||||
output: [{
|
output: [{
|
||||||
type: "npub",
|
type: "raw",
|
||||||
pubkey: PublicKey.FromBech32(
|
text: "pubkey error: nostr:npub1xxxxxxxxrhgtk4fgqdmpuqxv05u9raau3w0shay7msmr0dzs4m7sxxxxxx",
|
||||||
"npub1k9p03z0gqsz2dqvjrkp6337lq5tl9nzj4wx0sfrpjmje2ze8nyls424ds3",
|
|
||||||
),
|
|
||||||
start: 31,
|
|
||||||
end: 93,
|
|
||||||
}],
|
}],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
for (const [i, test] of data.entries()) {
|
for (const test of data) {
|
||||||
await t.step(test.input, () => {
|
await t.step(`t-${test.input}`, () => {
|
||||||
assertEquals(test.output, Array.from(parseContent(test.input)));
|
assertEquals(Array.from(parseContent(test.input)), test.output);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -258,7 +328,6 @@ Deno.test("message group", () => {
|
|||||||
pubkey: "",
|
pubkey: "",
|
||||||
sig: "",
|
sig: "",
|
||||||
tags: [],
|
tags: [],
|
||||||
parsedContentItems: [],
|
|
||||||
parsedTags: {
|
parsedTags: {
|
||||||
e: [],
|
e: [],
|
||||||
p: [],
|
p: [],
|
||||||
|
@ -1,168 +1,187 @@
|
|||||||
import { PublicKey } from "../../libs/nostr.ts/key.ts";
|
import { PublicKey } from "../../libs/nostr.ts/key.ts";
|
||||||
import { DirectedMessage_Event, Parsed_Event } from "../nostr.ts";
|
import { DirectedMessage_Event, Parsed_Event } from "../nostr.ts";
|
||||||
import { Nevent, NostrAddress, NostrProfile, NoteID } from "../../libs/nostr.ts/nip19.ts";
|
|
||||||
import { NostrKind } from "../../libs/nostr.ts/nostr.ts";
|
import { NostrKind } from "../../libs/nostr.ts/nostr.ts";
|
||||||
|
import { Nevent, NostrAddress, NostrProfile, NoteID } from "../../libs/nostr.ts/nip19.ts";
|
||||||
|
|
||||||
export function* parseContent(content: string) {
|
type ItemType = "url" | "tag" | "note" | "npub" | "nprofile" | "naddr" | "nevent";
|
||||||
// URLs
|
|
||||||
yield* match(/https?:\/\/[^\s]+/g, content, "url");
|
|
||||||
|
|
||||||
// npubs
|
|
||||||
yield* match(/(nostr:)?npub[0-9a-z]{59}/g, content, "npub");
|
|
||||||
|
|
||||||
//nprofile
|
|
||||||
yield* match(/(nostr:)?nprofile[0-9a-z]+/g, content, "nprofile");
|
|
||||||
|
|
||||||
//naddr
|
|
||||||
yield* match(/(nostr:)?naddr[0-9a-z]+/g, content, "naddr");
|
|
||||||
|
|
||||||
// notes
|
|
||||||
yield* match(/note[0-9a-z]{59}/g, content, "note");
|
|
||||||
|
|
||||||
// nevent
|
|
||||||
yield* match(/(nostr:)?nevent[0-9a-z]+/g, content, "nevent");
|
|
||||||
|
|
||||||
// tags
|
|
||||||
yield* match(/#\[[0-9]+\]/g, content, "tag");
|
|
||||||
}
|
|
||||||
|
|
||||||
function* match(regex: RegExp, content: string, type: ItemType): Generator<ContentItem, void, unknown> {
|
|
||||||
let match;
|
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/exec#return_value
|
|
||||||
// If the match succeeds, the exec() method returns an array and
|
|
||||||
// updates the lastIndex property of the regular expression object.
|
|
||||||
while ((match = regex.exec(content)) !== null) {
|
|
||||||
const urlStartPosition = match.index;
|
|
||||||
if (urlStartPosition == undefined) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const urlEndPosition = urlStartPosition + match[0].length - 1;
|
|
||||||
if (type == "note") {
|
|
||||||
const noteID = NoteID.FromBech32(content.slice(urlStartPosition, urlEndPosition + 1));
|
|
||||||
if (noteID instanceof Error) {
|
|
||||||
// ignore
|
|
||||||
} else {
|
|
||||||
yield {
|
|
||||||
type: type,
|
|
||||||
noteID: noteID,
|
|
||||||
start: urlStartPosition,
|
|
||||||
end: urlEndPosition,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
} else if (type == "npub") {
|
|
||||||
let bech32: string;
|
|
||||||
if (match[0].startsWith("nostr:")) {
|
|
||||||
bech32 = content.slice(urlStartPosition + 6, urlEndPosition + 1);
|
|
||||||
} else {
|
|
||||||
bech32 = content.slice(urlStartPosition, urlEndPosition + 1);
|
|
||||||
}
|
|
||||||
const pubkey = PublicKey.FromBech32(bech32);
|
|
||||||
if (pubkey instanceof Error) {
|
|
||||||
// ignore
|
|
||||||
} else {
|
|
||||||
yield {
|
|
||||||
type: type,
|
|
||||||
pubkey: pubkey,
|
|
||||||
start: urlStartPosition,
|
|
||||||
end: urlEndPosition,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
} else if (type == "nprofile") {
|
|
||||||
let bech32: string;
|
|
||||||
if (match[0].startsWith("nostr:")) {
|
|
||||||
bech32 = content.slice(urlStartPosition + 6, urlEndPosition + 1);
|
|
||||||
} else {
|
|
||||||
bech32 = content.slice(urlStartPosition, urlEndPosition + 1);
|
|
||||||
}
|
|
||||||
const decoded_nProfile = NostrProfile.decode(bech32);
|
|
||||||
if (decoded_nProfile instanceof Error) {
|
|
||||||
// ignore
|
|
||||||
} else {
|
|
||||||
const pubkey = decoded_nProfile.pubkey;
|
|
||||||
|
|
||||||
yield {
|
|
||||||
type: "npub",
|
|
||||||
pubkey: pubkey,
|
|
||||||
start: urlStartPosition,
|
|
||||||
end: urlEndPosition,
|
|
||||||
relays: decoded_nProfile.relays,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
} else if (type == "naddr") {
|
|
||||||
let bech32: string;
|
|
||||||
if (match[0].startsWith("nostr:")) {
|
|
||||||
bech32 = content.slice(urlStartPosition + 6, urlEndPosition + 1);
|
|
||||||
} else {
|
|
||||||
bech32 = content.slice(urlStartPosition, urlEndPosition + 1);
|
|
||||||
}
|
|
||||||
const decoded_nAddr = NostrAddress.decode(bech32);
|
|
||||||
if (decoded_nAddr instanceof Error) {
|
|
||||||
// ignore
|
|
||||||
} else {
|
|
||||||
yield {
|
|
||||||
type: "naddr",
|
|
||||||
start: urlStartPosition,
|
|
||||||
end: urlEndPosition,
|
|
||||||
addr: decoded_nAddr,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
} else if (type == "nevent") {
|
|
||||||
let bech32: string;
|
|
||||||
if (match[0].startsWith("nostr:")) {
|
|
||||||
bech32 = content.slice(urlStartPosition + 6, urlEndPosition + 1);
|
|
||||||
} else {
|
|
||||||
bech32 = content.slice(urlStartPosition, urlEndPosition + 1);
|
|
||||||
}
|
|
||||||
const decoded_nEvent = Nevent.decode(bech32);
|
|
||||||
if (decoded_nEvent instanceof Error) {
|
|
||||||
// ignore
|
|
||||||
} else {
|
|
||||||
yield {
|
|
||||||
type: "nevent",
|
|
||||||
start: urlStartPosition,
|
|
||||||
end: urlEndPosition,
|
|
||||||
event: decoded_nEvent,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
yield {
|
|
||||||
type: type,
|
|
||||||
start: urlStartPosition,
|
|
||||||
end: urlEndPosition,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type otherItemType = "url" | "tag";
|
|
||||||
type ItemType = otherItemType | "note" | "npub" | "nprofile" | "naddr" | "nevent";
|
|
||||||
export type ContentItem = {
|
export type ContentItem = {
|
||||||
type: otherItemType;
|
type: "raw" | "url" | "tag";
|
||||||
start: number;
|
text: string;
|
||||||
end: number;
|
|
||||||
} | {
|
} | {
|
||||||
type: "npub";
|
type: "npub";
|
||||||
|
text: string;
|
||||||
pubkey: PublicKey;
|
pubkey: PublicKey;
|
||||||
start: number;
|
} | {
|
||||||
end: number;
|
type: "nprofile";
|
||||||
relays?: string[];
|
text: string;
|
||||||
|
nprofile: NostrProfile;
|
||||||
} | {
|
} | {
|
||||||
type: "note";
|
type: "note";
|
||||||
|
text: string;
|
||||||
noteID: NoteID;
|
noteID: NoteID;
|
||||||
start: number;
|
|
||||||
end: number;
|
|
||||||
} | {
|
} | {
|
||||||
type: "naddr";
|
type: "naddr";
|
||||||
start: number;
|
text: string;
|
||||||
end: number;
|
|
||||||
addr: NostrAddress;
|
addr: NostrAddress;
|
||||||
} | {
|
} | {
|
||||||
type: "nevent";
|
type: "nevent";
|
||||||
start: number;
|
text: string;
|
||||||
end: number;
|
nevent: Nevent;
|
||||||
event: Nevent;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export function* parseContent(content: string): Iterable<ContentItem> {
|
||||||
|
if (content.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const first_match = match_first(content);
|
||||||
|
if (!first_match) {
|
||||||
|
yield { text: content, type: "raw" };
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const text = content.substring(first_match.start, first_match.end);
|
||||||
|
const bech32 = text.startsWith("nostr:") ? text.slice(6) : text;
|
||||||
|
const raw_string_before = content.substring(0, first_match.start);
|
||||||
|
|
||||||
|
if (first_match.name === "npub") {
|
||||||
|
const pubkey = PublicKey.FromBech32(bech32);
|
||||||
|
if (pubkey instanceof Error) {
|
||||||
|
yield {
|
||||||
|
type: "raw",
|
||||||
|
text: content.slice(0, first_match.end),
|
||||||
|
};
|
||||||
|
yield* parseContent(content.slice(first_match.end));
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
if (raw_string_before) {
|
||||||
|
yield { text: raw_string_before, type: "raw" };
|
||||||
|
}
|
||||||
|
yield { text, type: first_match.name, pubkey };
|
||||||
|
yield* parseContent(content.slice(first_match.end));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if (first_match.name === "nprofile") {
|
||||||
|
const decoded_nProfile = NostrProfile.decode(bech32);
|
||||||
|
if (decoded_nProfile instanceof Error) {
|
||||||
|
yield {
|
||||||
|
type: "raw",
|
||||||
|
text: content.slice(0, first_match.end),
|
||||||
|
};
|
||||||
|
yield* parseContent(content.slice(first_match.end));
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
if (raw_string_before) {
|
||||||
|
yield { text: raw_string_before, type: "raw" };
|
||||||
|
}
|
||||||
|
yield { text, type: first_match.name, nprofile: decoded_nProfile };
|
||||||
|
yield* parseContent(content.slice(first_match.end));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if (first_match.name === "note") {
|
||||||
|
const noteID = NoteID.FromBech32(bech32);
|
||||||
|
if (noteID instanceof Error) {
|
||||||
|
yield {
|
||||||
|
type: "raw",
|
||||||
|
text: content.slice(0, first_match.end),
|
||||||
|
};
|
||||||
|
yield* parseContent(content.slice(first_match.end));
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
if (raw_string_before) {
|
||||||
|
yield { text: raw_string_before, type: "raw" };
|
||||||
|
}
|
||||||
|
yield { text, type: first_match.name, noteID };
|
||||||
|
yield* parseContent(content.slice(first_match.end));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if (first_match.name === "naddr") {
|
||||||
|
const addr = NostrAddress.decode(bech32);
|
||||||
|
if (addr instanceof Error) {
|
||||||
|
yield {
|
||||||
|
type: "raw",
|
||||||
|
text: content.slice(0, first_match.end),
|
||||||
|
};
|
||||||
|
yield* parseContent(content.slice(first_match.end));
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
if (raw_string_before) {
|
||||||
|
yield { text: raw_string_before, type: "raw" };
|
||||||
|
}
|
||||||
|
yield { text, type: first_match.name, addr };
|
||||||
|
yield* parseContent(content.slice(first_match.end));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if (first_match.name === "nevent") {
|
||||||
|
const nevent = Nevent.decode(bech32);
|
||||||
|
if (nevent instanceof Error) {
|
||||||
|
yield {
|
||||||
|
type: "raw",
|
||||||
|
text: content.slice(0, first_match.end),
|
||||||
|
};
|
||||||
|
yield* parseContent(content.slice(first_match.end));
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
if (raw_string_before) {
|
||||||
|
yield { text: raw_string_before, type: "raw" };
|
||||||
|
}
|
||||||
|
yield { text, type: first_match.name, nevent };
|
||||||
|
yield* parseContent(content.slice(first_match.end));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (raw_string_before) {
|
||||||
|
yield { text: raw_string_before, type: "raw" };
|
||||||
|
}
|
||||||
|
yield { text, type: first_match.name };
|
||||||
|
yield* parseContent(content.slice(first_match.end));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function match_first(content: string) {
|
||||||
|
if (content.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const regexs: { name: ItemType; regex: RegExp }[] = [
|
||||||
|
{ name: "url", regex: /https?:\/\/[^\s]+/ },
|
||||||
|
{ name: "npub", regex: /(nostr:)?npub[0-9a-z]{59}/ },
|
||||||
|
{ name: "nprofile", regex: /(nostr:)?nprofile[0-9a-z]+/ },
|
||||||
|
{ name: "naddr", regex: /(nostr:)?naddr[0-9a-z]+/ },
|
||||||
|
{ name: "note", regex: /(nostr:)?note[0-9a-z]{59}/ },
|
||||||
|
{ name: "nevent", regex: /(nostr:)?nevent[0-9a-z]+/ },
|
||||||
|
{ name: "tag", regex: /#\[[0-9]+\]/ },
|
||||||
|
];
|
||||||
|
|
||||||
|
let first_match: {
|
||||||
|
name: ItemType;
|
||||||
|
start: number;
|
||||||
|
end: number;
|
||||||
|
} | undefined;
|
||||||
|
for (const r of regexs) {
|
||||||
|
const matched = r.regex.exec(content);
|
||||||
|
if (matched == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const start = matched.index;
|
||||||
|
const end = matched.index + matched[0].length;
|
||||||
|
|
||||||
|
// Return the matching string with the maximum length
|
||||||
|
if (first_match == undefined) {
|
||||||
|
first_match = { name: r.name, start, end };
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (start < first_match.start) {
|
||||||
|
first_match = { name: r.name, start, end };
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (first_match.start == start && end > first_match.end) {
|
||||||
|
first_match = { name: r.name, start, end };
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return first_match;
|
||||||
|
}
|
||||||
|
|
||||||
// Think of ChatMessage as an materialized view of NostrEvent
|
// Think of ChatMessage as an materialized view of NostrEvent
|
||||||
export type ChatMessage = {
|
export type ChatMessage = {
|
||||||
readonly type: "image" | "text";
|
readonly type: "image" | "text";
|
||||||
|
@ -3,7 +3,7 @@ import { InvalidKey, PublicKey } from "../../libs/nostr.ts/key.ts";
|
|||||||
import { NostrAccountContext, NostrEvent, NostrKind } from "../../libs/nostr.ts/nostr.ts";
|
import { NostrAccountContext, NostrEvent, NostrKind } from "../../libs/nostr.ts/nostr.ts";
|
||||||
import { ConnectionPool } from "../../libs/nostr.ts/relay-pool.ts";
|
import { ConnectionPool } from "../../libs/nostr.ts/relay-pool.ts";
|
||||||
import { DirectMessageGetter } from "../UI/app_update.tsx";
|
import { DirectMessageGetter } from "../UI/app_update.tsx";
|
||||||
import { ChatMessage, parseContent } from "../UI/message.ts";
|
import { ChatMessage } from "../UI/message.ts";
|
||||||
import {
|
import {
|
||||||
compare,
|
compare,
|
||||||
DirectedMessage_Event,
|
DirectedMessage_Event,
|
||||||
@ -297,7 +297,6 @@ async function parseDM(
|
|||||||
parsedTags,
|
parsedTags,
|
||||||
publicKey,
|
publicKey,
|
||||||
decryptedContent: decrypted,
|
decryptedContent: decrypted,
|
||||||
parsedContentItems: Array.from(parseContent(decrypted)),
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,6 @@ import { PublicKey } from "../libs/nostr.ts/key.ts";
|
|||||||
import * as nostr from "../libs/nostr.ts/nostr.ts";
|
import * as nostr from "../libs/nostr.ts/nostr.ts";
|
||||||
import { NostrKind, TagPubKey } from "../libs/nostr.ts/nostr.ts";
|
import { NostrKind, TagPubKey } from "../libs/nostr.ts/nostr.ts";
|
||||||
import { ProfileData } from "./features/profile.ts";
|
import { ProfileData } from "./features/profile.ts";
|
||||||
import { ContentItem } from "./UI/message.ts";
|
|
||||||
import { prepareEncryptedNostrEvent, prepareNormalNostrEvent } from "../libs/nostr.ts/event.ts";
|
import { prepareEncryptedNostrEvent, prepareNormalNostrEvent } from "../libs/nostr.ts/event.ts";
|
||||||
|
|
||||||
type TotolChunks = string;
|
type TotolChunks = string;
|
||||||
@ -47,7 +46,6 @@ export type Profile_Nostr_Event = Parsed_Event<NostrKind.META_DATA> & {
|
|||||||
|
|
||||||
export type DirectedMessage_Event = Parsed_Event<NostrKind.DIRECT_MESSAGE> & {
|
export type DirectedMessage_Event = Parsed_Event<NostrKind.DIRECT_MESSAGE> & {
|
||||||
decryptedContent: string;
|
decryptedContent: string;
|
||||||
parsedContentItems: ContentItem[];
|
|
||||||
};
|
};
|
||||||
export type Encrypted_Event = DirectedMessage_Event;
|
export type Encrypted_Event = DirectedMessage_Event;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user