Content Parser
The content parser system in @welshman/content
provides a powerful way to parse Nostr content into structured elements. It handles various types of content including Nostr entities, links, code blocks, and special formats.
Content Types
Basic Types
typescript
enum ParsedType {
Text = "text", // Plain text
Newline = "newline", // Line breaks
Topic = "topic", // Hashtags (#nostr)
Code = "code", // Code blocks (inline and multi-line)
Link = "link", // URLs
LinkGrid = "link-grid" // Grid of media links
}
Nostr-specific Types
typescript
enum ParsedType {
Event = "event", // Nostr events (note1/nevent1)
Profile = "profile", // Profiles (npub1/nprofile1)
Address = "address", // Addresses (naddr1)
}
Special Format Types
typescript
enum ParsedType {
Cashu = "cashu", // Cashu tokens
Invoice = "invoice", // Lightning invoices
Ellipsis = "ellipsis" // Truncation marker
}
Parsing Content
Main Parser
typescript
const parse = ({
content = "",
tags = []
}: {
content?: string
tags?: string[][]
}) => Parsed[]
// Example
const parsed = parse({
content: "Hello #nostr, check nostr:npub1...",
tags: [["p", "pubkey123"]]
})
Available Parsers
The system includes specialized parsers for each content type:
typescript
// Nostr Entities
parseAddress(text: string, context: ParseContext): ParsedAddress | void
parseEvent(text: string, context: ParseContext): ParsedEvent | void
parseProfile(text: string, context: ParseContext): ParsedProfile | void
// Code Blocks
parseCodeBlock(text: string, context: ParseContext): ParsedCode | void
parseCodeInline(text: string, context: ParseContext): ParsedCode | void
// Special Formats
parseCashu(text: string, context: ParseContext): ParsedCashu | void
parseInvoice(text: string, context: ParseContext): ParsedInvoice | void
// Basic Content
parseLink(text: string, context: ParseContext): ParsedLink | void
parseNewline(text: string, context: ParseContext): ParsedNewline | void
parseTopic(text: string, context: ParseContext): ParsedTopic | void
Content Processing
Truncation
typescript
type TruncateOpts = {
minLength?: number // Minimum content length (default: 500)
maxLength?: number // Maximum content length (default: 700)
mediaLength?: number // Length value for media items (default: 200)
entityLength?: number // Length value for entities (default: 30)
}
const truncate = (
content: Parsed[],
options?: TruncateOpts
) => Parsed[]
// Example
const truncated = truncate(parsed, {
maxLength: 1000,
mediaLength: 150
})
Link Processing
typescript
// Consolidate consecutive image links into grids
const reduceLinks = (content: Parsed[]) => Parsed[]
// Example
const processed = reduceLinks(parsed)
Type Guards
typescript
// Basic content
isText(parsed: Parsed): parsed is ParsedText
isNewline(parsed: Parsed): parsed is ParsedNewline
isCode(parsed: Parsed): parsed is ParsedCode
isTopic(parsed: Parsed): parsed is ParsedTopic
// Links and media
isLink(parsed: Parsed): parsed is ParsedLink
isImage(parsed: Parsed): parsed is ParsedLink
isLinkGrid(parsed: Parsed): parsed is ParsedLinkGrid
// Nostr entities
isEvent(parsed: Parsed): parsed is ParsedEvent
isProfile(parsed: Parsed): parsed is ParsedProfile
isAddress(parsed: Parsed): parsed is ParsedAddress
// Special formats
isCashu(parsed: Parsed): parsed is ParsedCashu
isInvoice(parsed: Parsed): parsed is ParsedInvoice
isEllipsis(parsed: Parsed): parsed is ParsedEllipsis
Complete Example
typescript
// Parse content with tags
const parsed = parse({
content: `
Hello #nostr!
Check out this note: nostr:note1...
And this profile: nostr:npub1...
Some code: \`console.log("hello")\`
https://example.com/image.jpg
https://example.com/image2.jpg
`,
tags: [
["p", "pubkey123"],
["e", "event456"]
]
})
// Process the content
const processed = reduceLinks(parsed)
// Truncate if needed
const final = truncate(processed, {
maxLength: 500,
mediaLength: 150
})
// Check types and handle accordingly
final.forEach(item => {
if (isImage(item)) {
// Handle image
} else if (isProfile(item)) {
// Handle profile reference
} else if (isCode(item)) {
// Handle code block
}
})
This parser system provides a robust foundation for handling Nostr content, with support for various content types and processing needs. The type-safe approach ensures reliable content handling while maintaining flexibility for different use cases.