Fix content parsing, add default rendering
This commit is contained in:
Generated
+30
@@ -323,6 +323,12 @@
|
|||||||
"version": "3.0.3",
|
"version": "3.0.3",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/insane": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/insane/-/insane-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-9FNbmwdaQezEszc5B/w4kRSpMJMOVj+gX7CKSbBCFO4WPiUqKO3HJlUNXzjtus0w5tF2BOJoKTbyps/Envlg/Q==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/@types/json-schema": {
|
"node_modules/@types/json-schema": {
|
||||||
"version": "7.0.15",
|
"version": "7.0.15",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
@@ -666,6 +672,11 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/assignment": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/assignment/-/assignment-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-naMULXjtgCs9SVUEtyvJNt68aF18em7/W+dhbR59kbz9cXWPEvUkCun2tqlgqRPSqZaKPpqLc5ZnwL8jVmJRvw=="
|
||||||
|
},
|
||||||
"node_modules/balanced-match": {
|
"node_modules/balanced-match": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
@@ -1542,6 +1553,14 @@
|
|||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/he": {
|
||||||
|
"version": "0.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/he/-/he-0.5.0.tgz",
|
||||||
|
"integrity": "sha512-DoufbNNOFzwRPy8uecq+j+VCPQ+JyDelHTmSgygrA5TsR8Cbw4Qcir5sGtWiusB4BdT89nmlaVDhSJOqC/33vw==",
|
||||||
|
"bin": {
|
||||||
|
"he": "bin/he"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/hosted-git-info": {
|
"node_modules/hosted-git-info": {
|
||||||
"version": "4.1.0",
|
"version": "4.1.0",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
@@ -1648,6 +1667,15 @@
|
|||||||
"node": ">=8.0.0"
|
"node": ">=8.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/insane": {
|
||||||
|
"version": "2.6.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/insane/-/insane-2.6.2.tgz",
|
||||||
|
"integrity": "sha512-BqEL1CJsjJi+/C/zKZxv31zs3r6zkLH5Nz1WMFb7UBX2KHY2yXDpbFTSEmNHzomBbGDysIfkTX55A0mQZ2CQiw==",
|
||||||
|
"dependencies": {
|
||||||
|
"assignment": "2.0.0",
|
||||||
|
"he": "0.5.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/is-arrayish": {
|
"node_modules/is-arrayish": {
|
||||||
"version": "0.2.1",
|
"version": "0.2.1",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
@@ -3067,9 +3095,11 @@
|
|||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"insane": "^2.6.2",
|
||||||
"nostr-tools": "^2.7.0"
|
"nostr-tools": "^2.7.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/insane": "^1.0.0",
|
||||||
"gts": "^5.0.1",
|
"gts": "^5.0.1",
|
||||||
"tsc-multi": "^1.1.0",
|
"tsc-multi": "^1.1.0",
|
||||||
"typescript": "~5.1.6"
|
"typescript": "~5.1.6"
|
||||||
|
|||||||
+143
-58
@@ -1,4 +1,5 @@
|
|||||||
import {nip19} from "nostr-tools"
|
import {nip19} from "nostr-tools"
|
||||||
|
import insane from 'insane'
|
||||||
|
|
||||||
const last = <T>(xs: T[], ...args: unknown[]) => xs[xs.length - 1]
|
const last = <T>(xs: T[], ...args: unknown[]) => xs[xs.length - 1]
|
||||||
|
|
||||||
@@ -79,8 +80,7 @@ export type ParsedInvoice = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type ParsedLinkValue = {
|
export type ParsedLinkValue = {
|
||||||
url: string
|
url: URL
|
||||||
hash: string
|
|
||||||
meta: Record<string, string>
|
meta: Record<string, string>
|
||||||
isMedia: boolean
|
isMedia: boolean
|
||||||
}
|
}
|
||||||
@@ -143,46 +143,46 @@ export type Parsed =
|
|||||||
|
|
||||||
// Parsers for known formats
|
// Parsers for known formats
|
||||||
|
|
||||||
export const parseAddress = (raw: string, context: ParseContext): ParsedAddress | void => {
|
export const parseAddress = (text: string, context: ParseContext): ParsedAddress | void => {
|
||||||
const [naddr] = raw.match(/^(web\+)?(nostr:)?\/?\/?naddr1[\d\w]+/i) || []
|
const [naddr] = text.match(/^(web\+)?(nostr:)?\/?\/?naddr1[\d\w]+/i) || []
|
||||||
|
|
||||||
if (naddr) {
|
if (naddr) {
|
||||||
try {
|
try {
|
||||||
const {data} = nip19.decode(fromNostrURI(naddr))
|
const {data} = nip19.decode(fromNostrURI(naddr))
|
||||||
|
|
||||||
return {type: ParsedType.Address, value: data as AddressPointer, raw}
|
return {type: ParsedType.Address, value: data as AddressPointer, raw: naddr}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Pass
|
// Pass
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const parseCashu = (raw: string, context: ParseContext): ParsedCashu | void => {
|
export const parseCashu = (text: string, context: ParseContext): ParsedCashu | void => {
|
||||||
const [value] = raw.match(/^(cashu)[\d\w=]{50,5000}/i) || []
|
const [value] = text.match(/^(cashu)[\d\w=]{50,5000}/i) || []
|
||||||
|
|
||||||
if (value) {
|
if (value) {
|
||||||
return {type: ParsedType.Cashu, value, raw}
|
return {type: ParsedType.Cashu, value, raw: value}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const parseCodeBlock = (raw: string, context: ParseContext): ParsedCodeBlock | void => {
|
export const parseCodeBlock = (text: string, context: ParseContext): ParsedCodeBlock | void => {
|
||||||
const [code, value] = raw.match(/^```([^]*?)```/i) || []
|
const [code, value] = text.match(/^```([^]*?)```/i) || []
|
||||||
|
|
||||||
if (code) {
|
if (code) {
|
||||||
return {type: ParsedType.CodeBlock, value, raw}
|
return {type: ParsedType.CodeBlock, value, raw: code}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const parseCodeInline = (raw: string, context: ParseContext): ParsedCodeInline | void => {
|
export const parseCodeInline = (text: string, context: ParseContext): ParsedCodeInline | void => {
|
||||||
const [code, value] = raw.match(/^`(.*?)`/i) || []
|
const [code, value] = text.match(/^`(.*?)`/i) || []
|
||||||
|
|
||||||
if (code) {
|
if (code) {
|
||||||
return {type: ParsedType.CodeInline, value, raw}
|
return {type: ParsedType.CodeInline, value, raw: code}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const parseEvent = (raw: string, context: ParseContext): ParsedEvent | void => {
|
export const parseEvent = (text: string, context: ParseContext): ParsedEvent | void => {
|
||||||
const [entity] = raw.match(/^(web\+)?(nostr:)?\/?\/?n(event|ote)1[\d\w]+/i) || []
|
const [entity] = text.match(/^(web\+)?(nostr:)?\/?\/?n(event|ote)1[\d\w]+/i) || []
|
||||||
|
|
||||||
if (entity) {
|
if (entity) {
|
||||||
try {
|
try {
|
||||||
@@ -191,23 +191,23 @@ export const parseEvent = (raw: string, context: ParseContext): ParsedEvent | vo
|
|||||||
? {id: data as string, relays: []}
|
? {id: data as string, relays: []}
|
||||||
: data as EventPointer
|
: data as EventPointer
|
||||||
|
|
||||||
return {type: ParsedType.Event, value, raw}
|
return {type: ParsedType.Event, value, raw: entity}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Pass
|
// Pass
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const parseInvoice = (raw: string, context: ParseContext): ParsedInvoice | void => {
|
export const parseInvoice = (text: string, context: ParseContext): ParsedInvoice | void => {
|
||||||
const [value] = raw.match(/^ln(lnbc|lnurl)[\d\w]{50,1000}/i) || []
|
const [value] = text.match(/^ln(lnbc|lnurl)[\d\w]{50,1000}/i) || []
|
||||||
|
|
||||||
if (value) {
|
if (value) {
|
||||||
return {type: ParsedType.Invoice, value, raw}
|
return {type: ParsedType.Invoice, value, raw: value}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const parseLink = (raw: string, context: ParseContext): ParsedLink | void => {
|
export const parseLink = (text: string, context: ParseContext): ParsedLink | void => {
|
||||||
const [link] = raw.match(/^([a-z\+:]{2,30}:\/\/)?[^<>\(\)\s]+\.[a-z]{2,6}[^\s]*[^<>"'\.!?,:\s\)\(]/gi) || []
|
let [link] = text.match(/^([a-z\+:]{2,30}:\/\/)?[^<>\(\)\s]+\.[a-z]{2,6}[^\s]*[^<>"'\.!?,:\s\)\(]/gi) || []
|
||||||
|
|
||||||
if (!link) {
|
if (!link) {
|
||||||
return
|
return
|
||||||
@@ -215,52 +215,51 @@ export const parseLink = (raw: string, context: ParseContext): ParsedLink | void
|
|||||||
|
|
||||||
const prev = last(context.results)
|
const prev = last(context.results)
|
||||||
|
|
||||||
// Skip url if it's just the end of a filepath
|
// Skip url if it's just the end of a filepath or an ellipse
|
||||||
if (prev?.type === ParsedType.Text && prev.value.endsWith("/")) {
|
if (prev?.type === ParsedType.Text && prev.value.endsWith("/") || link.match(/\.\./)) {
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Strip hash component
|
|
||||||
let [url, hash] = link.split("#")
|
|
||||||
|
|
||||||
// Skip ellipses and very short non-urls
|
|
||||||
if (url.match(/\.\./)) {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure there's a protocol
|
// Make sure there's a protocol
|
||||||
if (!url.match("^\w+://")) {
|
if (!link.match(/^\w+:\/\//)) {
|
||||||
url = "https://" + url
|
link = "https://" + link
|
||||||
}
|
}
|
||||||
|
|
||||||
const meta = Object.fromEntries(new URLSearchParams(hash).entries())
|
// Parse using URL
|
||||||
|
let url
|
||||||
|
try {
|
||||||
|
url = new URL(link)
|
||||||
|
} catch (e) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const meta = Object.fromEntries(new URLSearchParams(url.hash.slice(1)).entries())
|
||||||
|
|
||||||
for (const tag of context.tags) {
|
for (const tag of context.tags) {
|
||||||
if (tag[0] === 'imeta' && tag.find(t => t.includes(`url ${raw}`))) {
|
if (tag[0] === 'imeta' && tag.find(t => t.includes(`url ${link}`))) {
|
||||||
Object.assign(meta, Object.fromEntries(tag.slice(1).map((m: string) => m.split(" "))))
|
Object.assign(meta, Object.fromEntries(tag.slice(1).map((m: string) => m.split(" "))))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const isMedia = Boolean(
|
const isMedia = Boolean(
|
||||||
url.match(/\.(jpe?g|png|wav|mp3|mp4|mov|avi|webm|webp|gif|bmp|svg)$/) &&
|
url.pathname.match(/\.(jpe?g|png|wav|mp3|mp4|mov|avi|webm|webp|gif|bmp|svg)$/)
|
||||||
last(url.replace(/\/$/, "").split("://"))?.includes("/")
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const value = {url, hash, meta, isMedia}
|
const value = {url, meta, isMedia}
|
||||||
|
|
||||||
return {type: ParsedType.Link, value, raw}
|
return {type: ParsedType.Link, value, raw: link}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const parseNewline = (raw: string, context: ParseContext): ParsedNewline | void => {
|
export const parseNewline = (text: string, context: ParseContext): ParsedNewline | void => {
|
||||||
const [value] = raw.match(/^\n+/) || []
|
const [value] = text.match(/^\n+/) || []
|
||||||
|
|
||||||
if (value) {
|
if (value) {
|
||||||
return {type: ParsedType.Newline, raw, value}
|
return {type: ParsedType.Newline, value, raw: value}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const parseProfile = (raw: string, context: ParseContext): ParsedProfile | void => {
|
export const parseProfile = (text: string, context: ParseContext): ParsedProfile | void => {
|
||||||
const [entity] = raw.match(/^(web\+)?(nostr:)?\/?\/?n(profile|pub)1[\d\w]+/i) || []
|
const [entity] = text.match(/^(web\+)?(nostr:)?\/?\/?n(profile|pub)1[\d\w]+/i) || []
|
||||||
|
|
||||||
if (entity) {
|
if (entity) {
|
||||||
try {
|
try {
|
||||||
@@ -269,38 +268,38 @@ export const parseProfile = (raw: string, context: ParseContext): ParsedProfile
|
|||||||
? {pubkey: data as string, relays: []}
|
? {pubkey: data as string, relays: []}
|
||||||
: data as ProfilePointer
|
: data as ProfilePointer
|
||||||
|
|
||||||
return {type: ParsedType.Profile, value, raw}
|
return {type: ParsedType.Profile, value, raw: entity}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Pass
|
// Pass
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const parseTopic = (raw: string, context: ParseContext): ParsedTopic | void => {
|
export const parseTopic = (text: string, context: ParseContext): ParsedTopic | void => {
|
||||||
const [value] = raw.match(/^#[^\s!\"#$%&'()*+,-.\/:;<=>?@[\\\]^_`{|}~]+/i) || []
|
const [value] = text.match(/^#[^\s!\"#$%&'()*+,-.\/:;<=>?@[\\\]^_`{|}~]+/i) || []
|
||||||
|
|
||||||
// Skip numeric topics
|
// Skip numeric topics
|
||||||
if (value && !value.match(/^#\d+$/)) {
|
if (value && !value.match(/^#\d+$/)) {
|
||||||
return {type: ParsedType.Topic, raw, value}
|
return {type: ParsedType.Topic, value, raw: value}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Parse other formats to known types
|
// Parse other formats to known types
|
||||||
|
|
||||||
export const parseLegacyMention = (raw: string, context: ParseContext): ParsedProfile | ParsedEvent | void => {
|
export const parseLegacyMention = (text: string, context: ParseContext): ParsedProfile | ParsedEvent | void => {
|
||||||
const mentionMatch = raw.match(/^#\[(\d+)\]/i) || []
|
const mentionMatch = text.match(/^#\[(\d+)\]/i) || []
|
||||||
|
|
||||||
if (mentionMatch) {
|
if (mentionMatch) {
|
||||||
const [tag, value, url] = context.tags[parseInt(mentionMatch[1])] || []
|
const [tag, value, url] = context.tags[parseInt(mentionMatch[1])] || []
|
||||||
const relays = url ? [url] : []
|
const relays = url ? [url] : []
|
||||||
|
|
||||||
if (tag === "p") {
|
if (tag === "p") {
|
||||||
return {type: ParsedType.Profile, value: {pubkey: value, relays}, raw}
|
return {type: ParsedType.Profile, value: {pubkey: value, relays}, raw: mentionMatch[0]!}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tag === "e") {
|
if (tag === "e") {
|
||||||
return {type: ParsedType.Event, value: {id: value, relays}, raw}
|
return {type: ParsedType.Event, value: {id: value, relays}, raw: mentionMatch[0]!}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -366,10 +365,10 @@ export const parse = ({content = "", tags = []}: {content?: string; tags?: strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
type TruncateOpts = {
|
type TruncateOpts = {
|
||||||
minLength: number
|
minLength?: number
|
||||||
maxLength: number
|
maxLength?: number
|
||||||
mediaLength: number
|
mediaLength?: number
|
||||||
entityLength: number
|
entityLength?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export const truncate = (
|
export const truncate = (
|
||||||
@@ -379,7 +378,7 @@ export const truncate = (
|
|||||||
maxLength = 600,
|
maxLength = 600,
|
||||||
mediaLength = 200,
|
mediaLength = 200,
|
||||||
entityLength = 30,
|
entityLength = 30,
|
||||||
}: TruncateOpts,
|
}: TruncateOpts = {},
|
||||||
) => {
|
) => {
|
||||||
// Get a list of content sizes so we know where to truncate
|
// Get a list of content sizes so we know where to truncate
|
||||||
// Non-plaintext things might take up more or less room if rendered
|
// Non-plaintext things might take up more or less room if rendered
|
||||||
@@ -423,3 +422,89 @@ export const truncate = (
|
|||||||
|
|
||||||
return content
|
return content
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Renderers
|
||||||
|
|
||||||
|
export type RenderOptions = {
|
||||||
|
entityBaseUrl?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export const defaultRenderOptions = {
|
||||||
|
entityBaseUrl: 'https://njump.me/'
|
||||||
|
}
|
||||||
|
|
||||||
|
export class HTML {
|
||||||
|
constructor(readonly value: string) {
|
||||||
|
this.value = value
|
||||||
|
}
|
||||||
|
|
||||||
|
toString = () => this.value
|
||||||
|
|
||||||
|
static useSafely = (value: string) => new HTML(insane(value))
|
||||||
|
|
||||||
|
static useDangerously = (value: string) => new HTML(value)
|
||||||
|
|
||||||
|
static buildLink = (href: string, display: string) =>
|
||||||
|
HTML.useSafely(`<a href=${href} target="_blank">${display}</a>`)
|
||||||
|
|
||||||
|
static buildEntityLink = (entity: string, options: RenderOptions) =>
|
||||||
|
HTML.buildLink(options.entityBaseUrl + entity, entity.slice(0, 16))
|
||||||
|
}
|
||||||
|
|
||||||
|
export const renderCashu = (parsed: ParsedCashu, options: RenderOptions) =>
|
||||||
|
HTML.useSafely(parsed.value)
|
||||||
|
|
||||||
|
export const renderCodeBlock = (parsed: ParsedCodeBlock, options: RenderOptions) =>
|
||||||
|
HTML.useSafely(parsed.value)
|
||||||
|
|
||||||
|
export const renderCodeInline = (parsed: ParsedCodeInline, options: RenderOptions) =>
|
||||||
|
HTML.useSafely(parsed.value)
|
||||||
|
|
||||||
|
export const renderEllipsis = (parsed: ParsedEllipsis, options: RenderOptions) => "..."
|
||||||
|
|
||||||
|
export const renderInvoice = (parsed: ParsedInvoice, options: RenderOptions) =>
|
||||||
|
HTML.useSafely(parsed.value)
|
||||||
|
|
||||||
|
export const renderLink = (parsed: ParsedLink, options: RenderOptions) => {
|
||||||
|
const href = parsed.value.url.toString()
|
||||||
|
const display = parsed.value.url.host + parsed.value.url.pathname
|
||||||
|
|
||||||
|
return HTML.buildLink(href, display)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const renderNewline = (parsed: ParsedNewline, options: RenderOptions) =>
|
||||||
|
HTML.useSafely(Array.from(parsed.value).map(() => '<br />').join(''))
|
||||||
|
|
||||||
|
export const renderText = (parsed: ParsedText, options: RenderOptions) =>
|
||||||
|
HTML.useSafely(parsed.value)
|
||||||
|
|
||||||
|
export const renderTopic = (parsed: ParsedTopic, options: RenderOptions) =>
|
||||||
|
HTML.useSafely(parsed.value)
|
||||||
|
|
||||||
|
export const renderEvent = (parsed: ParsedEvent, options: RenderOptions) =>
|
||||||
|
HTML.buildEntityLink(nip19.neventEncode(parsed.value), options)
|
||||||
|
|
||||||
|
export const renderProfile = (parsed: ParsedProfile, options: RenderOptions) =>
|
||||||
|
HTML.buildEntityLink(nip19.nprofileEncode(parsed.value), options)
|
||||||
|
|
||||||
|
export const renderAddress = (parsed: ParsedAddress, options: RenderOptions) =>
|
||||||
|
HTML.buildEntityLink(nip19.naddrEncode(parsed.value), options)
|
||||||
|
|
||||||
|
export const render = (parsed: Parsed, options: RenderOptions = {}) => {
|
||||||
|
options = {...defaultRenderOptions, ...options}
|
||||||
|
|
||||||
|
switch (parsed.type) {
|
||||||
|
case ParsedType.Address: return renderAddress(parsed as ParsedAddress, options)
|
||||||
|
case ParsedType.Cashu: return renderCashu(parsed as ParsedCashu, options)
|
||||||
|
case ParsedType.CodeBlock: return renderCodeBlock(parsed as ParsedCodeBlock, options)
|
||||||
|
case ParsedType.CodeInline: return renderCodeInline(parsed as ParsedCodeInline, options)
|
||||||
|
case ParsedType.Ellipsis: return renderEllipsis(parsed as ParsedEllipsis, options)
|
||||||
|
case ParsedType.Event: return renderEvent(parsed as ParsedEvent, options)
|
||||||
|
case ParsedType.Invoice: return renderInvoice(parsed as ParsedInvoice, options)
|
||||||
|
case ParsedType.Link: return renderLink(parsed as ParsedLink, options)
|
||||||
|
case ParsedType.Newline: return renderNewline(parsed as ParsedNewline, options)
|
||||||
|
case ParsedType.Profile: return renderProfile(parsed as ParsedProfile, options)
|
||||||
|
case ParsedType.Text: return renderText(parsed as ParsedText, options)
|
||||||
|
case ParsedType.Topic: return renderTopic(parsed as ParsedTopic, options)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@welshman/content",
|
"name": "@welshman/content",
|
||||||
"version": "0.0.1",
|
"version": "0.0.2",
|
||||||
"author": "hodlbod",
|
"author": "hodlbod",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"description": "A collection of utilities for parsing nostr note content.",
|
"description": "A collection of utilities for parsing nostr note content.",
|
||||||
@@ -26,11 +26,13 @@
|
|||||||
"fix": "gts fix"
|
"fix": "gts fix"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/insane": "^1.0.0",
|
||||||
"gts": "^5.0.1",
|
"gts": "^5.0.1",
|
||||||
"tsc-multi": "^1.1.0",
|
"tsc-multi": "^1.1.0",
|
||||||
"typescript": "~5.1.6"
|
"typescript": "~5.1.6"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"insane": "^2.6.2",
|
||||||
"nostr-tools": "^2.7.0"
|
"nostr-tools": "^2.7.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user