From 0e667995c15da5c4023e98818384df298808d6e0 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Thu, 27 Feb 2025 14:15:02 -0600 Subject: [PATCH] Remove `@/config.ts` import from utils/note.ts --- packages/ditto/storages/DittoRelayStore.ts | 3 +- packages/ditto/utils/note.test.ts | 32 +++++++++++++++++++--- packages/ditto/utils/note.ts | 16 +++++++---- packages/ditto/views/mastodon/accounts.ts | 4 +-- packages/ditto/views/mastodon/statuses.ts | 2 +- 5 files changed, 44 insertions(+), 13 deletions(-) diff --git a/packages/ditto/storages/DittoRelayStore.ts b/packages/ditto/storages/DittoRelayStore.ts index 7b935d96..b3938c9d 100644 --- a/packages/ditto/storages/DittoRelayStore.ts +++ b/packages/ditto/storages/DittoRelayStore.ts @@ -324,7 +324,8 @@ export class DittoRelayStore implements NRelay { } private async prewarmLinkPreview(event: NostrEvent, signal?: AbortSignal): Promise { - const { firstUrl } = parseNoteContent(stripimeta(event.content, event.tags), []); + const { firstUrl } = parseNoteContent(stripimeta(event.content, event.tags), [], this.opts); + if (firstUrl) { await unfurlCardCached(firstUrl, signal); } diff --git a/packages/ditto/utils/note.test.ts b/packages/ditto/utils/note.test.ts index 699c4c5e..cdf29314 100644 --- a/packages/ditto/utils/note.test.ts +++ b/packages/ditto/utils/note.test.ts @@ -1,26 +1,35 @@ +import { DittoConf } from '@ditto/conf'; import { assertEquals } from '@std/assert'; import { eventFixture } from '@/test.ts'; import { getMediaLinks, parseNoteContent, stripimeta } from '@/utils/note.ts'; Deno.test('parseNoteContent', () => { - const { html, links, firstUrl } = parseNoteContent('Hello, world!', []); + const conf = new DittoConf(new Map()); + const { html, links, firstUrl } = parseNoteContent('Hello, world!', [], { conf }); + assertEquals(html, 'Hello, world!'); assertEquals(links, []); assertEquals(firstUrl, undefined); }); Deno.test('parseNoteContent parses URLs', () => { - const { html } = parseNoteContent('check out my website: https://alexgleason.me', []); + const conf = new DittoConf(new Map()); + const { html } = parseNoteContent('check out my website: https://alexgleason.me', [], { conf }); + assertEquals(html, 'check out my website: https://alexgleason.me'); }); Deno.test('parseNoteContent parses bare URLs', () => { - const { html } = parseNoteContent('have you seen ditto.pub?', []); + const conf = new DittoConf(new Map()); + const { html } = parseNoteContent('have you seen ditto.pub?', [], { conf }); + assertEquals(html, 'have you seen ditto.pub?'); }); Deno.test('parseNoteContent parses mentions with apostrophes', () => { + const conf = new DittoConf(new Map()); + const { html } = parseNoteContent( `did you see nostr:nprofile1qqsqgc0uhmxycvm5gwvn944c7yfxnnxm0nyh8tt62zhrvtd3xkj8fhgprdmhxue69uhkwmr9v9ek7mnpw3hhytnyv4mz7un9d3shjqgcwaehxw309ahx7umywf5hvefwv9c8qtmjv4kxz7gpzemhxue69uhhyetvv9ujumt0wd68ytnsw43z7s3al0v's speech?`, [{ @@ -29,7 +38,9 @@ Deno.test('parseNoteContent parses mentions with apostrophes', () => { acct: 'alex@gleasonator.dev', url: 'https://gleasonator.dev/@alex', }], + { conf }, ); + assertEquals( html, 'did you see @alex@gleasonator.dev's speech?', @@ -37,6 +48,8 @@ Deno.test('parseNoteContent parses mentions with apostrophes', () => { }); Deno.test('parseNoteContent parses mentions with commas', () => { + const conf = new DittoConf(new Map()); + const { html } = parseNoteContent( `Sim. Hi nostr:npub1q3sle0kvfsehgsuexttt3ugjd8xdklxfwwkh559wxckmzddywnws6cd26p and nostr:npub1gujeqakgt7fyp6zjggxhyy7ft623qtcaay5lkc8n8gkry4cvnrzqd3f67z, any chance to have Cobrafuma as PWA?`, [{ @@ -50,7 +63,9 @@ Deno.test('parseNoteContent parses mentions with commas', () => { acct: 'patrick@patrickdosreis.com', url: 'https://gleasonator.dev/@patrick@patrickdosreis.com', }], + { conf }, ); + assertEquals( html, 'Sim. Hi @alex@gleasonator.dev and @patrick@patrickdosreis.com, any chance to have Cobrafuma as PWA?', @@ -58,19 +73,26 @@ Deno.test('parseNoteContent parses mentions with commas', () => { }); Deno.test("parseNoteContent doesn't parse invalid nostr URIs", () => { - const { html } = parseNoteContent('nip19 has URIs like nostr:npub and nostr:nevent, etc.', []); + const conf = new DittoConf(new Map()); + const { html } = parseNoteContent('nip19 has URIs like nostr:npub and nostr:nevent, etc.', [], { conf }); assertEquals(html, 'nip19 has URIs like nostr:npub and nostr:nevent, etc.'); }); Deno.test('parseNoteContent renders empty for non-profile nostr URIs', () => { + const conf = new DittoConf(new Map()); + const { html } = parseNoteContent( 'nostr:nevent1qgsr9cvzwc652r4m83d86ykplrnm9dg5gwdvzzn8ameanlvut35wy3gpz3mhxue69uhhztnnwashymtnw3ezucm0d5qzqru8mkz2q4gzsxg99q7pdneyx7n8p5u0afe3ntapj4sryxxmg4gpcdvgce', [], + { conf }, ); + assertEquals(html, ''); }); Deno.test("parseNoteContent doesn't fuck up links to my own post", () => { + const conf = new DittoConf(new Map()); + const { html } = parseNoteContent( 'Check this post: https://gleasonator.dev/@alex@gleasonator.dev/posts/a8badb480d88f9e7b6a090342279ef47ed0e0a3989ed85f898dfedc6be94225f', [{ @@ -79,7 +101,9 @@ Deno.test("parseNoteContent doesn't fuck up links to my own post", () => { acct: 'alex@gleasonator.dev', url: 'https://gleasonator.dev/@alex', }], + { conf }, ); + assertEquals( html, 'Check this post: https://gleasonator.dev/@alex@gleasonator.dev/posts/a8badb480d88f9e7b6a090342279ef47ed0e0a3989ed85f898dfedc6be94225f', diff --git a/packages/ditto/utils/note.ts b/packages/ditto/utils/note.ts index a17a0f15..c51595f1 100644 --- a/packages/ditto/utils/note.ts +++ b/packages/ditto/utils/note.ts @@ -3,11 +3,11 @@ import linkifyStr from 'linkify-string'; import linkify from 'linkifyjs'; import { nip19, nip27 } from 'nostr-tools'; -import { Conf } from '@/config.ts'; import { html } from '@/utils/html.ts'; import { getUrlMediaType, isPermittedMediaType } from '@/utils/media.ts'; -import { MastodonMention } from '@ditto/mastoapi/types'; +import type { DittoConf } from '@ditto/conf'; +import type { MastodonMention } from '@ditto/mastoapi/types'; linkify.registerCustomProtocol('nostr', true); linkify.registerCustomProtocol('wss'); @@ -21,8 +21,14 @@ interface ParsedNoteContent { firstUrl: string | undefined; } +interface ParseNoteContentOpts { + conf: DittoConf; +} + /** Convert Nostr content to Mastodon API HTML. Also return parsed data. */ -function parseNoteContent(content: string, mentions: MastodonMention[]): ParsedNoteContent { +function parseNoteContent(content: string, mentions: MastodonMention[], opts: ParseNoteContentOpts): ParsedNoteContent { + const { conf } = opts; + const links = linkify.find(content).filter(({ type }) => type === 'url'); const firstUrl = links.find(isNonMediaLink)?.href; @@ -30,7 +36,7 @@ function parseNoteContent(content: string, mentions: MastodonMention[]): ParsedN render: { hashtag: ({ content }) => { const tag = content.replace(/^#/, ''); - const href = Conf.local(`/tags/${tag}`); + const href = conf.local(`/tags/${tag}`); return html``; }, url: ({ attributes, content }) => { @@ -49,7 +55,7 @@ function parseNoteContent(content: string, mentions: MastodonMention[]): ParsedN const npub = nip19.npubEncode(pubkey); const acct = mention?.acct ?? npub; const name = mention?.acct ?? npub.substring(0, 8); - const href = mention?.url ?? Conf.local(`/@${acct}`); + const href = mention?.url ?? conf.local(`/@${acct}`); return html`@${name}${extra}`; } else { return ''; diff --git a/packages/ditto/views/mastodon/accounts.ts b/packages/ditto/views/mastodon/accounts.ts index 827b7921..4639ade3 100644 --- a/packages/ditto/views/mastodon/accounts.ts +++ b/packages/ditto/views/mastodon/accounts.ts @@ -48,7 +48,7 @@ function renderAccount(event: Omit, opts: ToAccountOpt const parsed05 = stats?.nip05 ? parseNip05(stats.nip05) : undefined; const acct = parsed05?.handle || npub; - const { html } = parseNoteContent(about || '', []); + const { html } = parseNoteContent(about || '', [], { conf: Conf }); const fields = _fields ?.slice(0, Conf.profileFields.maxFields) @@ -84,7 +84,7 @@ function renderAccount(event: Omit, opts: ToAccountOpt discoverable: true, display_name: name ?? '', emojis: renderEmojis(event), - fields: fields.map((field) => ({ ...field, value: parseNoteContent(field.value, []).html })), + fields: fields.map((field) => ({ ...field, value: parseNoteContent(field.value, [], { conf: Conf }).html })), follow_requests_count: 0, followers_count: stats?.followers_count ?? 0, following_count: stats?.following_count ?? 0, diff --git a/packages/ditto/views/mastodon/statuses.ts b/packages/ditto/views/mastodon/statuses.ts index 55aa0808..065ac798 100644 --- a/packages/ditto/views/mastodon/statuses.ts +++ b/packages/ditto/views/mastodon/statuses.ts @@ -42,7 +42,7 @@ async function renderStatus( const mentions = event.mentions?.map((event) => renderMention(event)) ?? []; - const { html, links, firstUrl } = parseNoteContent(stripimeta(event.content, event.tags), mentions); + const { html, links, firstUrl } = parseNoteContent(stripimeta(event.content, event.tags), mentions, { conf: Conf }); const [card, relatedEvents] = await Promise .all([