From 760d6d07cd2ce9fc4124dd653ee65e8b8dbebea9 Mon Sep 17 00:00:00 2001 From: Jon Staab Date: Fri, 13 Dec 2024 15:18:33 -0800 Subject: [PATCH] Remove Fluent, Tags --- packages/feeds/src/compiler.ts | 8 +- packages/feeds/src/utils.ts | 12 +-- packages/lib/src/Fluent.ts | 71 -------------- packages/lib/src/Tools.ts | 7 -- packages/lib/src/index.ts | 1 - packages/util/src/Events.ts | 6 +- packages/util/src/Tags.ts | 167 +-------------------------------- 7 files changed, 14 insertions(+), 258 deletions(-) delete mode 100644 packages/lib/src/Fluent.ts diff --git a/packages/feeds/src/compiler.ts b/packages/feeds/src/compiler.ts index 4898d36..bf6f840 100644 --- a/packages/feeds/src/compiler.ts +++ b/packages/feeds/src/compiler.ts @@ -1,6 +1,6 @@ import {uniq, identity, flatten, pushToMapKey, intersection, tryCatch, now} from '@welshman/lib' import type {TrustedEvent, Filter} from '@welshman/util' -import {Tags, intersectFilters, matchFilter, getAddress, getIdFilters, unionFilters} from '@welshman/util' +import {intersectFilters, matchFilter, getAddress, getIdFilters, unionFilters} from '@welshman/util' import type {CreatedAtItem, RequestItem, ListItem, LabelItem, WOTItem, DVMItem, Scope, Feed, FeedOptions} from './core' import {getFeedArgs, feedsFromTags} from './utils' import {FeedType} from './core' @@ -110,7 +110,7 @@ export class FeedCompiler { this.options.requestDVM({ ...request, onEvent: async (e: TrustedEvent) => { - const tags = Tags.wrap(await tryCatch(() => JSON.parse(e.content)) || []) + const tags = await tryCatch(() => JSON.parse(e.content)) || [] for (const feed of feedsFromTags(tags, mappings)) { feeds.push(feed) @@ -231,7 +231,7 @@ export class FeedCompiler { const event = eventsByAddress.get(address) if (event) { - for (const feed of feedsFromTags(Tags.fromEvent(event), mappings)) { + for (const feed of feedsFromTags(event.tags, mappings)) { feeds.push(feed) } } @@ -271,7 +271,7 @@ export class FeedCompiler { } } - return feedsFromTags(Tags.wrap(tags), mappings) + return feedsFromTags(tags, mappings) }) ) ) diff --git a/packages/feeds/src/utils.ts b/packages/feeds/src/utils.ts index 8e80d2e..9af901e 100644 --- a/packages/feeds/src/utils.ts +++ b/packages/feeds/src/utils.ts @@ -1,6 +1,6 @@ import {ensureNumber} from '@welshman/lib' import type {Filter} from '@welshman/util' -import {Tags} from '@welshman/util' +import {getTagValues} from '@welshman/util' import { FeedType, Feed, @@ -110,15 +110,13 @@ export const defaultTagFeedMappings: TagFeedMapping[] = [ ['t', [FeedType.Tag, '#t']], ] -export const feedsFromTags = (tags: Tags, mappings?: TagFeedMapping[]) => { +export const feedsFromTags = (tags: string[][], mappings?: TagFeedMapping[]) => { const feeds = [] for (const [tagName, templateFeed] of mappings || defaultTagFeedMappings) { - const filterTags = tags.whereKey(tagName) - - if (filterTags.exists()) { - let values: string[] | number[] = filterTags.values().valueOf() + let values: any[] = getTagValues(tagName, tags) + if (values.length > 0) { if (isKindFeed(templateFeed)) { values = values.map(ensureNumber) as number[] } @@ -130,7 +128,7 @@ export const feedsFromTags = (tags: Tags, mappings?: TagFeedMapping[]) => { return feeds } -export const feedFromTags = (tags: Tags, mappings?: TagFeedMapping[]) => +export const feedFromTags = (tags: string[][], mappings?: TagFeedMapping[]) => makeIntersectionFeed(...feedsFromTags(tags, mappings)) export const feedsFromFilter = ({since, until, ...filter}: Filter) => { diff --git a/packages/lib/src/Fluent.ts b/packages/lib/src/Fluent.ts deleted file mode 100644 index 4e49b93..0000000 --- a/packages/lib/src/Fluent.ts +++ /dev/null @@ -1,71 +0,0 @@ -import {last} from './Tools' - -export class Fluent { - constructor(readonly xs: T[]) {} - - static create() { - return this.from([]) - } - - static from(xs: Iterable) { - return new Fluent(Array.from(xs)) - } - - clone>(this: K, xs: T[]): K { - return new (this.constructor as { new (xs: T[]): K })(xs) - } - - valueOf = () => this.xs - - first = () => this.xs[0] - - nth = (i: number) => this.xs[i] - - last = () => last(this.xs) - - count = () => this.xs.length - - exists = () => this.xs.length > 0 - - has = (v: T) => this.xs.includes(v) - - every = (f: (t: T) => boolean) => this.xs.every(f) - - some = (f: (t: T) => boolean) => this.xs.some(f) - - find = (f: (t: T) => boolean) => this.xs.find(f) - - uniq = () => this.clone(Array.from(new Set(this.xs))) - - slice = (a: number, b?: number) => this.clone(this.xs.slice(a, b)) - - take = (n: number) => this.slice(0, n) - - drop = (n: number) => this.slice(n) - - filter = (f: (t: T) => boolean) => this.clone(this.xs.filter(f)) - - reject = (f: (t: T) => boolean) => this.clone(this.xs.filter(t => !f(t))) - - keep = (xs: T[]) => this.filter(x => xs.includes(x)) - - without = (xs: T[]) => this.reject(x => xs.includes(x)) - - map = (f: (t: T) => T) => this.clone(this.xs.map(f)) - - mapTo = (f: (t: T) => U) => Fluent.from(this.xs.map(f)) - - flatMap = (f: (t: T) => U[]) => Fluent.from(this.xs.flatMap(f)) - - forEach = (f: (t: T, i: number) => void) => this.xs.forEach(f) - - join = (s: string) => this.valueOf().join(s) - - set = (i: number, x: T) => this.clone([...this.xs.slice(0, i), x, ...this.xs.slice(i + 1)]) - - concat = (xs: T[]) => this.clone(this.xs.concat(xs)) - - append = (x: T) => this.concat([x]) - - prepend = (x: T) => this.clone([x].concat(this.xs)) -} diff --git a/packages/lib/src/Tools.ts b/packages/lib/src/Tools.ts index c2dd1c3..8f3342b 100644 --- a/packages/lib/src/Tools.ts +++ b/packages/lib/src/Tools.ts @@ -1088,10 +1088,3 @@ export const hexToBech32 = (prefix: string, hex: string) => */ export const bech32ToHex = (b32: string) => utf8.encode(bech32.fromWords(bech32.decode(b32, false).words)) - -/** Extracts non-function property names from type */ -// https://github.com/microsoft/TypeScript/issues/4628#issuecomment-1147905253 -export type OmitStatics = - T extends {new(...args: infer A): infer R} ? - {new(...args: A): R}&Omit : - Omit; diff --git a/packages/lib/src/index.ts b/packages/lib/src/index.ts index 4a55cec..df8dee4 100644 --- a/packages/lib/src/index.ts +++ b/packages/lib/src/index.ts @@ -1,7 +1,6 @@ export * from './Context' export * from './Deferred' export * from './Emitter' -export * from './Fluent' export * from './LRUCache' export * from './Tools' export * from './Worker' diff --git a/packages/util/src/Events.ts b/packages/util/src/Events.ts index 4e01252..bc73d0b 100644 --- a/packages/util/src/Events.ts +++ b/packages/util/src/Events.ts @@ -1,6 +1,6 @@ import {verifiedSymbol, getEventHash, verifyEvent} from 'nostr-tools' import {cached, pick, now} from '@welshman/lib' -import {Tags} from './Tags' +import {getAncestorTagValues} from './Tags' import {getAddress} from './Address' import {isEphemeralKind, isReplaceableKind, isPlainReplaceableKind, isParameterizedReplaceableKind} from './Kinds' @@ -128,8 +128,8 @@ export const isPlainReplaceable = (e: EventTemplate) => isPlainReplaceableKind(e export const isParameterizedReplaceable = (e: EventTemplate) => isParameterizedReplaceableKind(e.kind) export const isChildOf = (child: EventContent, parent: HashedEvent) => { - const {roots, replies} = Tags.fromEvent(child).ancestors() - const parentIds = (replies.exists() ? replies : roots).values().valueOf() + const {roots, replies} = getAncestorTagValues(child.tags) + const parentIds = replies.length > 0 ? replies : roots return getIdAndAddress(parent).some(x => parentIds.includes(x)) } diff --git a/packages/util/src/Tags.ts b/packages/util/src/Tags.ts index 3d6364e..730b119 100644 --- a/packages/util/src/Tags.ts +++ b/packages/util/src/Tags.ts @@ -1,170 +1,7 @@ -import type {OmitStatics} from "@welshman/lib" -import {Fluent, uniq, uniqBy, mapVals, nth, nthEq, ensurePlural} from "@welshman/lib" -import {isRelayUrl, isShareableRelayUrl, normalizeRelayUrl} from "./Relay" +import {uniq, uniqBy, mapVals, nth, nthEq, ensurePlural} from "@welshman/lib" +import {isRelayUrl, isShareableRelayUrl} from "./Relay" import {Address} from "./Address" -export class Tag extends (Fluent as OmitStatics, "from">) { - static from = (xs: Iterable) => new Tag(Array.from(xs)) - - static fromId = (id: string) => new Tag(["e", id]) - - static fromIdentifier = (identifier: string) => new Tag(["d", identifier]) - - static fromTopic = (topic: string) => new Tag(["t", topic]) - - static fromPubkey = (pubkey: string) => new Tag(["p", pubkey]) - - static fromAddress = (address: string, relay = "") => new Tag(["a", address, relay]) - - key = () => this.xs[0] - - value = () => this.xs[1] - - entry = () => this.xs.slice(0, 2) - - setKey = (k: string) => this.set(0, k) - - setValue = (v: string) => this.set(1, v) - - isAddress = (kind?: number) => this.key() === "a" && this.value()?.startsWith(`${kind}:`) -} - -export class Tags extends (Fluent as OmitStatics, "from">) { - static from = (p: Iterable) => new Tags(Array.from(p)) - - static wrap = (p: Iterable) => new Tags(Array.from(p).map(Tag.from)) - - static fromEvent = (event: {tags: string[][]}) => Tags.wrap(event?.tags || []) - - static fromEvents = (events: {tags: string[][]}[]) => Tags.wrap(events.flatMap(e => e.tags || [])) - - static fromIMeta = (imeta: string[]) => Tags.wrap(imeta.map((m: string) => m.split(" "))) - - unwrap = () => this.xs.map(tag => tag.valueOf()) - - whereKey = (key: string) => this.filter(t => t.key() === key) - - whereValue = (value: string) => this.filter(t => t.value() === value) - - filterByKey = (keys: string[]) => this.filter(t => keys.includes(t.key())) - - filterByValue = (values: string[]) => this.filter(t => values.includes(t.value())) - - rejectByKey = (keys: string[]) => this.reject(t => keys.includes(t.key())) - - rejectByValue = (values: string[]) => this.reject(t => values.includes(t.value())) - - get = (key: string) => this.whereKey(key).first() - - keys = () => this.mapTo(t => t.key()) - - values = (key?: string | string[]) => - (key ? this.filterByKey(ensurePlural(key)) : this).mapTo(t => t.value()) - - entries = () => this.mapTo(t => t.entry()) - - relays = () => - this.flatMap((t: Tag) => - t - .valueOf() - .filter(isRelayUrl) - .map(url => normalizeRelayUrl(url)) - ).uniq() - - topics = () => - this.whereKey("t") - .values() - .map((t: string) => t.replace(/^#/, "")) - - ancestors = (x?: boolean) => { - const {roots, replies, mentions} = getAncestorTags(this.unwrap()) - - return { - roots: Tags.wrap(roots), - replies: Tags.wrap(replies), - mentions: Tags.wrap(mentions), - } - } - - roots = () => this.ancestors().roots - - replies = () => this.ancestors().replies - - mentions = () => this.ancestors().mentions - - root = () => { - const roots = this.roots() - - return roots.get("e") || roots.get("a") - } - - reply = () => { - const replies = this.replies() - - return replies.get("e") || replies.get("a") - } - - parents = () => { - const {roots, replies} = this.ancestors() - - return replies.exists() ? replies : roots - } - - parent = () => { - const parents = this.parents() - - return parents.get("e") || parents.get("a") - } - - asObject = () => { - const result: Record = {} - - for (const t of this.xs) { - result[t.key()] = t.value() - } - - return result - } - - imeta = (url: string) => { - for (const tag of this.whereKey("imeta").xs) { - const tags = Tags.fromIMeta(tag.drop(1).valueOf()) - - if (tags.get("url")?.value() === url) { - return tags - } - } - - return null - } - - // Generic setters - - addTag = (...args: string[]) => this.append(Tag.from(args)) - - setTag = (k: string, ...args: string[]) => this.rejectByKey([k]).addTag(k, ...args) - - // Images - - addImages = (imeta: Tags[]) => - this.concat(imeta.map(tags => Tag.from(["image", tags.get("url").value()]))) - - removeImages = () => this.rejectByKey(["image"]) - - setImages = (imeta: Tags[]) => this.removeImages().addImages(imeta) - - // IMeta - - addIMeta = (imeta: Tags[]) => - this.concat(imeta.map(tags => Tag.from(["imeta", ...tags.valueOf().map(xs => xs.join(" "))]))) - - removeIMeta = () => this.rejectByKey(["imeta"]) - - setIMeta = (imeta: Tags[]) => this.removeIMeta().addIMeta(imeta) -} - -// New, simpler version - export const getTags = (types: string | string[], tags: string[][]) => { types = ensurePlural(types)