Bring back typedoc

This commit is contained in:
Jon Staab
2025-04-08 15:08:00 -07:00
parent 02202d298e
commit 3301616e7d
19 changed files with 261 additions and 135 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
# @welshman/store [![version](https://badgen.net/npm/v/@welshman/store)](https://npmjs.com/package/@welshman/store)
# @welshman/app [![version](https://badgen.net/npm/v/@welshman/app)](https://npmjs.com/package/@welshman/app)
Utilities for dealing with svelte stores when using welshman.
+1 -1
View File
@@ -179,7 +179,7 @@ describe("collection", () => {
getKey: item => item.id,
})
const derived = col.deriveItem(null)
const derived = col.deriveItem(undefined)
expect(get(derived)).toBeUndefined()
})
+2 -2
View File
@@ -1,5 +1,5 @@
import {now} from "@welshman/lib"
import {publish, PublishStatus, MockAdapter} from "@welshman/net"
import {PublishStatus, MockAdapter} from "@welshman/net"
import {NOTE, makeEvent} from "@welshman/util"
import {Nip01Signer} from "@welshman/signer"
import {LOCAL_RELAY_URL} from "@welshman/relay"
@@ -112,7 +112,7 @@ describe("thunk", () => {
const send = vi.fn()
const track = vi.spyOn(tracker, 'track')
const thunk = makeThunk(mockRequest)
let status = {}
let status: Record<string, any> = {}
// Subscribe to status updates
thunk.status.subscribe(_status => {
+42 -38
View File
@@ -1,5 +1,5 @@
import {describe, it, expect} from "vitest"
import * as Content from "../src"
import {ParsedLink, ParsedType, parse, reduceLinks, renderAsHtml, renderAsText} from "../src"
import {npubEncode, noteEncode} from "nostr-tools/nip19"
describe("Content Parsing", () => {
@@ -7,51 +7,55 @@ describe("Content Parsing", () => {
const nevent = noteEncode("ff".repeat(32))
describe("Basic Parsing", () => {
it("should parse plain text", () => {
const result = Content.parse({content: "Hello world"})
const result = parse({content: "Hello world"})
expect(result).toEqual([
{type: Content.ParsedType.Text, value: "Hello world", raw: "Hello world"},
{type: ParsedType.Text, value: "Hello world", raw: "Hello world"},
])
})
it("should parse newlines", () => {
const result = Content.parse({content: "Hello\nworld"})
const result = parse({content: "Hello\nworld"})
expect(result).toEqual([
{type: Content.ParsedType.Text, value: "Hello", raw: "Hello"},
{type: Content.ParsedType.Newline, value: "\n", raw: "\n"},
{type: Content.ParsedType.Text, value: "world", raw: "world"},
{type: ParsedType.Text, value: "Hello", raw: "Hello"},
{type: ParsedType.Newline, value: "\n", raw: "\n"},
{type: ParsedType.Text, value: "world", raw: "world"},
])
})
})
describe("Link Parsing", () => {
it("should parse basic URLs", () => {
const result = Content.parse({content: "Check https://example.com"})
expect(result[1]).toMatchObject({
type: Content.ParsedType.Link,
const result = parse({content: "Check https://example.com"})
const parsed = result[1] as ParsedLink
expect(parsed).toMatchObject({
type: ParsedType.Link,
value: {
url: expect.any(URL),
// isMedia: false,
},
})
expect(result[1].value.url.toString()).toBe("https://example.com/")
expect(parsed.value.url.toString()).toBe("https://example.com/")
})
it("should parse URLs without protocol", () => {
const result = Content.parse({content: "Visit example.com"})
expect(result[1]).toMatchObject({
type: Content.ParsedType.Link,
const result = parse({content: "Visit example.com"})
const parsed = result[1] as ParsedLink
expect(parsed).toMatchObject({
type: ParsedType.Link,
value: {
url: expect.any(URL),
// isMedia: false,
},
})
expect(result[1].value.url.toString()).toBe("https://example.com/")
expect(parsed.value.url.toString()).toBe("https://example.com/")
})
it("should identify media links", () => {
const result = Content.parse({content: "https://example.com/image.jpg"})
const result = parse({content: "https://example.com/image.jpg"})
expect(result[0]).toMatchObject({
type: Content.ParsedType.Link,
type: ParsedType.Link,
value: {
url: expect.any(URL),
meta: {},
@@ -62,46 +66,46 @@ describe("Content Parsing", () => {
describe("Nostr Entity Parsing", () => {
it("should parse nostr profiles", () => {
const result = Content.parse({
const result = parse({
content: `nostr:${npub}`,
})
expect(result[0]).toMatchObject({
type: Content.ParsedType.Profile,
type: ParsedType.Profile,
})
})
it("should parse nostr events", () => {
const result = Content.parse({
const result = parse({
content: `nostr:${nevent}`,
})
expect(result[0]).toMatchObject({
type: Content.ParsedType.Event,
type: ParsedType.Event,
})
})
})
describe("Special Content Parsing", () => {
it("should parse code blocks", () => {
const result = Content.parse({content: "```const x = 1```"})
const result = parse({content: "```const x = 1```"})
expect(result[0]).toMatchObject({
type: Content.ParsedType.Code,
type: ParsedType.Code,
value: "const x = 1",
})
})
it("should parse inline code", () => {
const result = Content.parse({content: "Use `npm install`"})
const result = parse({content: "Use `npm install`"})
expect(result[1]).toMatchObject({
type: Content.ParsedType.Code,
type: ParsedType.Code,
value: "npm install",
})
})
it("should parse topics", () => {
const result = Content.parse({content: "#nostr is cool"})
const result = parse({content: "#nostr is cool"})
expect(result[0]).toMatchObject({
type: Content.ParsedType.Topic,
type: ParsedType.Topic,
value: "nostr",
})
})
@@ -109,27 +113,27 @@ describe("Content Parsing", () => {
describe("Rendering", () => {
it("should render as text", () => {
const parsed = Content.parse({content: "Hello https://example.com"})
const rendered = Content.renderAsText(parsed).toString()
const parsed = parse({content: "Hello https://example.com"})
const rendered = renderAsText(parsed).toString()
expect(rendered).toContain("Hello")
expect(rendered).toContain("https://example.com")
})
it("should render as HTML", () => {
const parsed = Content.parse({content: "Hello https://example.com"})
const rendered = Content.renderAsHtml(parsed).toString()
const parsed = parse({content: "Hello https://example.com"})
const rendered = renderAsHtml(parsed).toString()
expect(rendered).toContain('<a href="https://example.com/"')
})
})
describe("Link Grid", () => {
it("should reduce consecutive image links into a grid", () => {
const content = Content.parse({
const content = parse({
content: "https://example.com/1.jpg\nhttps://example.com/2.jpg https://example.com/2.jpg",
})
const reduced = Content.reduceLinks(content)
const reduced = reduceLinks(content)
expect(reduced[0]).toMatchObject({
type: Content.ParsedType.LinkGrid,
type: ParsedType.LinkGrid,
value: {
links: expect.any(Array),
},
@@ -139,12 +143,12 @@ describe("Content Parsing", () => {
describe("Legacy Mention Parsing", () => {
it("should parse legacy mentions", () => {
const result = Content.parse({
const result = parse({
content: "#[0]",
tags: [["p", "1234567890"]],
})
expect(result[0]).toMatchObject({
type: Content.ParsedType.Profile,
type: ParsedType.Profile,
})
})
})
+2 -4
View File
@@ -36,7 +36,6 @@ describe("Content Truncation", () => {
value: {
url: new URL("https://example.com/image.jpg"),
meta: {},
isMedia: true,
},
raw: "https://example.com/image.jpg",
},
@@ -83,7 +82,6 @@ describe("Content Truncation", () => {
value: {
url: new URL("https://example.com/image.jpg"),
meta: {},
isMedia: true,
},
raw: "https://example.com/image.jpg",
},
@@ -141,8 +139,8 @@ describe("Content Truncation", () => {
type: ParsedType.LinkGrid,
value: {
links: [
{url: new URL("https://example.com/1.jpg"), meta: {}, isMedia: true},
{url: new URL("https://example.com/2.jpg"), meta: {}, isMedia: true},
{url: new URL("https://example.com/1.jpg"), meta: {}},
{url: new URL("https://example.com/2.jpg"), meta: {}},
],
},
raw: "",
+5 -5
View File
@@ -1,6 +1,6 @@
import {defaultTagFeedMappings} from "@welshman/feeds"
import {now} from "@welshman/lib"
import {getAddress, type TrustedEvent} from "@welshman/util"
import {getAddress, TrustedEvent} from "@welshman/util"
import {beforeEach, describe, expect, it, vi} from "vitest"
import {FeedCompiler} from "../src/compiler"
import {Feed, FeedType, Scope} from "../src/core"
@@ -269,7 +269,7 @@ describe("FeedCompiler", () => {
sig: "sig1",
}
mockOptions.requestDVM.mockImplementation(async ({onEvent}) => {
mockOptions.requestDVM.mockImplementation(async ({onEvent}: any) => {
await onEvent(mockEvent)
})
@@ -307,7 +307,7 @@ describe("FeedCompiler", () => {
sig: "sig1",
}
mockOptions.request.mockImplementation(({onEvent}) => {
mockOptions.request.mockImplementation(({onEvent}: any) => {
onEvent(mockEvent)
})
@@ -345,7 +345,7 @@ describe("FeedCompiler", () => {
sig: "sig1",
}
mockOptions.request.mockImplementation(({onEvent}) => {
mockOptions.request.mockImplementation(({onEvent}: any) => {
onEvent(labelEvent)
})
@@ -381,7 +381,7 @@ describe("FeedCompiler", () => {
sig: "sig1",
}
mockOptions.requestDVM.mockImplementation(async ({onEvent}) => {
mockOptions.requestDVM.mockImplementation(async ({onEvent}: any) => {
await onEvent(mockEvent)
})
+1 -1
View File
@@ -1,5 +1,5 @@
import {Tracker} from "../src/Tracker"
import {vi, describe, it, expect, beforeEach} from "vitest"
import {Tracker} from "../src/tracker"
describe("Tracker", () => {
let tracker: Tracker
+10 -8
View File
@@ -1,20 +1,20 @@
import EventEmitter from "events"
import { describe, expect, it, vi, beforeEach, afterEach } from "vitest"
import { isRelayUrl } from "@welshman/util"
import { LocalRelay, LOCAL_RELAY_URL } from "@welshman/relay"
import { LocalRelay, Repository, LOCAL_RELAY_URL } from "@welshman/relay"
import { AdapterEvent, SocketAdapter, LocalAdapter, getAdapter } from "../src/adapter"
import { ClientMessage, RelayMessage } from "../src/message"
import { Socket, SocketEvent } from "../src/socket"
import { Pool } from "../src/pool"
vi.mock('isomorphic-ws', () => {
const WebSocket = vi.fn(function () {
const WebSocket = vi.fn(function (this: any) {
setTimeout(() => this.onopen())
})
WebSocket.prototype.send = vi.fn()
WebSocket.prototype.close = vi.fn(function () {
WebSocket.prototype.close = vi.fn(function (this: any) {
this.onclose()
})
@@ -120,12 +120,14 @@ describe("LocalAdapter", () => {
describe("getAdapter", () => {
let pool: Pool
let relay: LocalRelay
let repository: Repository
beforeEach(() => {
pool = new Pool()
relay = new LocalRelay()
pool.get = vi.fn().mockReturnValue(new Socket("wss://test.relay"))
pool = new Pool({
makeSocket: () => new Socket("wss://test.relay"),
})
repository = new Repository()
})
afterEach(() => {
@@ -134,7 +136,7 @@ describe("getAdapter", () => {
it("should return LocalAdapter for local relay URL", () => {
const url = LOCAL_RELAY_URL
const adapter = getAdapter(url, { relay })
const adapter = getAdapter(url, { repository })
expect(adapter).toBeInstanceOf(LocalAdapter)
})
+3 -3
View File
@@ -1,6 +1,6 @@
import { describe, expect, it, vi, beforeEach, afterEach } from "vitest"
import { Socket, SocketStatus, SocketEvent } from "../src/socket"
import { makeEvent, CLIENT_AUTH } from "@welshman/util"
import { makeEvent, StampedEvent, CLIENT_AUTH } from "@welshman/util"
import { Nip01Signer } from "@welshman/signer"
import { AuthState, AuthStatus, AuthStateEvent, makeAuthEvent } from "../src/auth"
import EventEmitter from "events"
@@ -146,7 +146,7 @@ describe('auth', () => {
socket.auth.challenge = "challenge123"
socket.auth.status = AuthStatus.Requested
const sign = async e => {
const sign = async (e: StampedEvent) => {
event = await Nip01Signer.ephemeral().sign(e)
return event
@@ -154,7 +154,7 @@ describe('auth', () => {
await socket.auth.authenticate(sign)
expect(socket.auth.request).toStrictEqual(event.id)
expect(socket.auth.request).toStrictEqual(event!.id)
expect(sendSpy).toHaveBeenCalledWith(["AUTH", event])
})
})
+4 -4
View File
@@ -4,13 +4,13 @@ import { Pool, makeSocket } from "../src/pool"
import { normalizeRelayUrl } from "@welshman/util"
vi.mock('isomorphic-ws', () => {
const WebSocket = vi.fn(function () {
const WebSocket = vi.fn(function (this: any) {
setTimeout(() => this.onopen())
})
WebSocket.prototype.send = vi.fn()
WebSocket.prototype.close = vi.fn(function () {
WebSocket.prototype.close = vi.fn(function (this: any) {
this.onclose()
})
@@ -97,7 +97,7 @@ describe("Pool", () => {
it("should remove and cleanup existing socket", () => {
const mockSocket = { url: "wss://test.relay", cleanup: vi.fn() }
pool._data.set(mockSocket.url, mockSocket)
pool._data.set(mockSocket.url, mockSocket as unknown as Socket)
pool.remove(mockSocket.url)
expect(mockSocket.cleanup).toHaveBeenCalled()
@@ -116,7 +116,7 @@ describe("Pool", () => {
const mockSockets = urls.map(url => ({ url, cleanup: vi.fn() }))
for (const mockSocket of mockSockets) {
pool._data.set(mockSocket.url, mockSocket)
pool._data.set(mockSocket.url, mockSocket as unknown as Socket)
}
pool.clear()
+4 -4
View File
@@ -103,14 +103,14 @@ describe("SinglePublish", () => {
pub.on(PublishEvent.Complete, completeSpy)
pub.on(PublishEvent.Timeout, timeoutSpy)
await vi.runAllTimers(200)
await vi.runAllTimers()
expect(sendSpy).toHaveBeenCalledWith([ClientMessageType.Event, event])
await vi.runAllTimers()
expect(successSpy).not.toHaveBeenCalled()
expect(failureSpy).not.toHaveBeenCalled(event.id, "hi")
expect(failureSpy).not.toHaveBeenCalled()
expect(completeSpy).toHaveBeenCalled()
expect(timeoutSpy).toHaveBeenCalled()
})
@@ -137,7 +137,7 @@ describe("SinglePublish", () => {
pub.on(PublishEvent.Complete, completeSpy)
pub.on(PublishEvent.Timeout, abortSpy)
await vi.runAllTimers(200)
await vi.runAllTimers()
expect(sendSpy).toHaveBeenCalledWith([ClientMessageType.Event, event])
@@ -146,7 +146,7 @@ describe("SinglePublish", () => {
await vi.runAllTimers()
expect(successSpy).not.toHaveBeenCalled()
expect(failureSpy).not.toHaveBeenCalled(event.id, "hi")
expect(failureSpy).not.toHaveBeenCalled()
expect(completeSpy).toHaveBeenCalled()
expect(abortSpy).toHaveBeenCalled()
})
+10 -13
View File
@@ -5,13 +5,13 @@ import { Socket, SocketStatus, SocketEvent } from "../src/socket"
import { ClientMessage, RelayMessage } from "../src/message"
vi.mock('isomorphic-ws', () => {
const WebSocket = vi.fn(function () {
const WebSocket = vi.fn(function (this: any) {
setTimeout(() => this.onopen())
})
WebSocket.prototype.send = vi.fn()
WebSocket.prototype.close = vi.fn(function () {
WebSocket.prototype.close = vi.fn(function (this: any) {
this.onclose()
})
@@ -77,11 +77,9 @@ describe("Socket", () => {
socket.open()
const ws = socket._ws
socket.close()
expect(ws.close).toHaveBeenCalled()
expect(socket._ws!.close).toHaveBeenCalled()
expect(statusSpy).toHaveBeenCalledWith(SocketStatus.Closed, "wss://test.relay")
})
})
@@ -102,14 +100,14 @@ describe("Socket", () => {
socket.on(SocketEvent.Send, sendSpy)
socket.open()
socket._ws.onopen()
socket._ws?.onopen?.(undefined as unknown as any)
const message: ClientMessage = ["EVENT", { id: "123", kind: 1 }]
socket.send(message)
await vi.runAllTimers()
expect(socket._ws.send).toHaveBeenCalledWith(JSON.stringify(message))
expect(socket._ws!.send).toHaveBeenCalledWith(JSON.stringify(message))
expect(sendSpy).toHaveBeenCalledWith(message, "wss://test.relay")
})
})
@@ -121,9 +119,8 @@ describe("Socket", () => {
socket.open()
const message: RelayMessage = ["EVENT", "123", { id: "123", kind: 1 }]
socket._ws.onmessage({ data: JSON.stringify(message) })
socket._ws?.onmessage?.({data: JSON.stringify(message)} as unknown as any)
// Allow task queue to process
await vi.runAllTimers()
expect(receiveSpy).toHaveBeenCalledWith(message, "wss://test.relay")
@@ -134,7 +131,7 @@ describe("Socket", () => {
socket.on(SocketEvent.Error, errorSpy)
socket.open()
socket._ws.onmessage({ data: "invalid json" })
socket._ws?.onmessage?.({data: "invalid json"} as unknown as any)
expect(errorSpy).toHaveBeenCalledWith("Invalid message received", "wss://test.relay")
})
@@ -144,7 +141,7 @@ describe("Socket", () => {
socket.on(SocketEvent.Error, errorSpy)
socket.open()
socket._ws.onmessage({ data: JSON.stringify({ not: "an array" }) })
socket._ws?.onmessage?.({data: JSON.stringify({not: "an array"})} as unknown as any)
expect(errorSpy).toHaveBeenCalledWith("Invalid message received", "wss://test.relay")
})
@@ -158,7 +155,7 @@ describe("Socket", () => {
socket.cleanup()
expect(ws.close).toHaveBeenCalled()
expect(ws!.close).toHaveBeenCalled()
expect(socket.listenerCount(SocketEvent.Send)).toBe(0)
})
})
@@ -169,7 +166,7 @@ describe("Socket", () => {
socket.on(SocketEvent.Status, statusSpy)
socket.open()
socket._ws.onerror()
socket._ws?.onerror?.(undefined as unknown as any)
expect(statusSpy).toHaveBeenCalledWith(SocketStatus.Error, "wss://test.relay")
})
+1 -1
View File
@@ -1,7 +1,7 @@
import {describe, it, vi, expect, beforeEach} from "vitest"
import {now} from "@welshman/lib"
import {getAddress, TrustedEvent, DELETE, MUTES} from "@welshman/util"
import {Repository} from "../src/Repository"
import {Repository} from "../src/repository"
describe("Repository", () => {
beforeEach(() => {
+2 -1
View File
@@ -1,4 +1,5 @@
import type {Repository, TrustedEvent} from "@welshman/util"
import {TrustedEvent} from "@welshman/util"
import {Repository} from "@welshman/relay"
import {get} from "svelte/store"
import {afterEach, beforeEach, describe, expect, it, vi} from "vitest"
import {
+48 -35
View File
@@ -1,8 +1,21 @@
import {describe, it, vi, expect, beforeEach} from "vitest"
import * as Filters from "../src/Filters"
import type {TrustedEvent} from "../src/Events"
import {GENERIC_REPOST, LONG_FORM, MUTES, REPOST} from "@welshman/util"
import {
addRepostFilters,
getFilterGenerality,
getFilterId,
getFilterResultCardinality,
getIdFilters,
getReplyFilters,
guessFilterDelta,
intersectFilters,
matchFilter,
matchFilters,
trimFilter,
unionFilters,
Filter,
} from "../src/Filters"
import type {TrustedEvent} from "../src/Events"
describe("Filters", () => {
beforeEach(() => {
@@ -27,23 +40,23 @@ describe("Filters", () => {
it("should match basic filter criteria", () => {
const event = createEvent()
const filter = {kinds: [1], authors: [pubkey]}
expect(Filters.matchFilter(filter, event)).toBe(true)
expect(matchFilter(filter, event)).toBe(true)
})
it("should handle search terms", () => {
const event = createEvent({content: "Hello Nostr World!"})
expect(Filters.matchFilter({search: "nostr"}, event)).toBe(true)
expect(Filters.matchFilter({search: "bitcoin"}, event)).toBe(false)
expect(matchFilter({search: "nostr"}, event)).toBe(true)
expect(matchFilter({search: "bitcoin"}, event)).toBe(false)
})
it("should handle multiple search terms", () => {
const event = createEvent({content: "Hello Nostr World!"})
expect(Filters.matchFilter({search: "hello world"}, event)).toBe(true)
expect(matchFilter({search: "hello world"}, event)).toBe(true)
})
it("should handle case-insensitive search", () => {
const event = createEvent({content: "Hello NOSTR World!"})
expect(Filters.matchFilter({search: "nostr"}, event)).toBe(true)
expect(matchFilter({search: "nostr"}, event)).toBe(true)
})
})
@@ -51,13 +64,13 @@ describe("Filters", () => {
it("should match if any filter matches", () => {
const event = createEvent()
const filters = [{kinds: [2]}, {kinds: [1], authors: [pubkey]}]
expect(Filters.matchFilters(filters, event)).toBe(true)
expect(matchFilters(filters, event)).toBe(true)
})
it("should not match if no filters match", () => {
const event = createEvent()
const filters = [{kinds: [2]}, {kinds: [3]}]
expect(Filters.matchFilters(filters, event)).toBe(false)
expect(matchFilters(filters, event)).toBe(false)
})
})
@@ -65,13 +78,13 @@ describe("Filters", () => {
it("should generate consistent IDs for equivalent filters", () => {
const filter1 = {kinds: [1], authors: [pubkey]}
const filter2 = {authors: [pubkey], kinds: [1]}
expect(Filters.getFilterId(filter1)).toBe(Filters.getFilterId(filter2))
expect(getFilterId(filter1)).toBe(getFilterId(filter2))
})
it("should generate different IDs for different filters", () => {
const filter1 = {kinds: [1], authors: [pubkey]}
const filter2 = {kinds: [2], authors: [pubkey]}
expect(Filters.getFilterId(filter1)).not.toBe(Filters.getFilterId(filter2))
expect(getFilterId(filter1)).not.toBe(getFilterId(filter2))
})
})
@@ -81,14 +94,14 @@ describe("Filters", () => {
{kinds: [1], authors: [pubkey]},
{kinds: [1], authors: [pubkey + "1"]},
]
const result = Filters.unionFilters(filters)
const result = unionFilters(filters)
expect(result).toHaveLength(1)
expect(result[0].authors).toHaveLength(2)
})
it("should handle different filter groups", () => {
const filters = [{kinds: [1]}, {"#e": [id]}]
const result = Filters.unionFilters(filters)
const filters: Filter[] = [{kinds: [1]}, {"#e": [id]}]
const result = unionFilters(filters)
expect(result).toHaveLength(2)
})
@@ -97,7 +110,7 @@ describe("Filters", () => {
{kinds: [1], limit: 10, since: 1000, until: 2000, search: "test"},
{kinds: [1], limit: 10, since: 1000, until: 2000, search: "test"},
]
const result = Filters.unionFilters(filters)
const result = unionFilters(filters)
expect(result).toHaveLength(1)
expect(result[0]).toMatchObject({limit: 10, since: 1000, until: 2000, search: "test"})
})
@@ -106,7 +119,7 @@ describe("Filters", () => {
describe("intersectFilters", () => {
it("should combine filter groups", () => {
const groups = [[{kinds: [1]}], [{authors: [pubkey]}]]
const result = Filters.intersectFilters(groups)
const result = intersectFilters(groups)
expect(result).toHaveLength(1)
expect(result[0]).toMatchObject({
kinds: [1],
@@ -119,7 +132,7 @@ describe("Filters", () => {
[{since: 1000, until: 2000, limit: 10}],
[{since: 1500, until: 1800, limit: 20}],
]
const result = Filters.intersectFilters(groups)
const result = intersectFilters(groups)
expect(result[0]).toMatchObject({
since: 1500, // Max of since
until: 1800, // Min of until
@@ -129,20 +142,20 @@ describe("Filters", () => {
it("should combine search terms", () => {
const groups = [[{search: "hello"}], [{search: "world"}]]
const result = Filters.intersectFilters(groups)
const result = intersectFilters(groups)
expect(result[0].search).toBe("hello world")
})
})
describe("getIdFilters", () => {
it("should handle plain IDs", () => {
const result = Filters.getIdFilters([id])
const result = getIdFilters([id])
expect(result[0].ids).toContain(id)
})
it("should handle addresses", () => {
const addr = `1:${pubkey}:test`
const result = Filters.getIdFilters([addr])
const result = getIdFilters([addr])
expect(result[0]).toMatchObject({
kinds: [1],
authors: [pubkey],
@@ -152,7 +165,7 @@ describe("Filters", () => {
it("should handle mixed IDs and addresses", () => {
const addr = `1:${pubkey}:test`
const result = Filters.getIdFilters([id, addr])
const result = getIdFilters([id, addr])
expect(result).toHaveLength(2)
})
})
@@ -160,13 +173,13 @@ describe("Filters", () => {
describe("getReplyFilters", () => {
it("should create filters for regular events", () => {
const event = createEvent()
const result = Filters.getReplyFilters([event])
const result = getReplyFilters([event])
expect((result[0] as any)["#e"]).toContain(event.id)
})
it("should handle replaceable events", () => {
const event = createEvent({kind: MUTES})
const result = Filters.getReplyFilters([event])
const result = getReplyFilters([event])
expect((result[0] as any)["#a"]).toBeDefined()
})
@@ -174,20 +187,20 @@ describe("Filters", () => {
const event = createEvent({
wrap: createEvent(),
})
const result = Filters.getReplyFilters([event])
const result = getReplyFilters([event])
expect((result[0] as any)["#e"]).toHaveLength(2)
})
})
describe("addRepostFilters", () => {
it("should add repost kinds for kind 1", () => {
const result = Filters.addRepostFilters([{kinds: [1]}])
const result = addRepostFilters([{kinds: [1]}])
expect(result).toHaveLength(2)
expect(result[1].kinds).toContain(REPOST)
})
it("should handle other kinds", () => {
const result = Filters.addRepostFilters([{kinds: [LONG_FORM]}])
const result = addRepostFilters([{kinds: [LONG_FORM]}])
expect(result[1].kinds).toContain(GENERIC_REPOST)
expect(result[1].kinds).not.toContain(REPOST)
expect(result[1]["#k"]).toContain(LONG_FORM.toString())
@@ -196,27 +209,27 @@ describe("Filters", () => {
describe("filter utilities", () => {
it("should calculate filter generality", () => {
expect(Filters.getFilterGenerality({ids: [id]})).toBe(0)
expect(Filters.getFilterGenerality({authors: [pubkey], "#p": [pubkey]})).toBe(0.2)
expect(Filters.getFilterGenerality({authors: [pubkey, pubkey, pubkey], kinds: [1]})).toBe(
expect(getFilterGenerality({ids: [id]})).toBe(0)
expect(getFilterGenerality({authors: [pubkey], "#p": [pubkey]})).toBe(0.2)
expect(getFilterGenerality({authors: [pubkey, pubkey, pubkey], kinds: [1]})).toBe(
0.01,
)
expect(Filters.getFilterGenerality({kinds: [1]})).toBe(1)
expect(getFilterGenerality({kinds: [1]})).toBe(1)
})
it("should guess filter delta", () => {
const result = Filters.guessFilterDelta([{ids: [id]}])
const result = guessFilterDelta([{ids: [id]}])
expect(result).toBeGreaterThan(0)
})
it("should get filter result cardinality", () => {
expect(Filters.getFilterResultCardinality({ids: [id, id + "1"]})).toBe(2)
expect(Filters.getFilterResultCardinality({kinds: [1]})).toBeUndefined()
expect(getFilterResultCardinality({ids: [id, id + "1"]})).toBe(2)
expect(getFilterResultCardinality({kinds: [1]})).toBeUndefined()
})
it("should trim large filters", () => {
const largeFilter = {authors: Array(2000).fill(pubkey)}
const result = Filters.trimFilter(largeFilter)
const result = trimFilter(largeFilter)
expect(result.authors?.length).toBe(1000)
})
})