You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
96 lines
3.2 KiB
96 lines
3.2 KiB
import { ParserOptions, ProcessResult, ContentFormat } from './types'; |
|
import { detectFormat } from './detector'; |
|
import { convertToAsciidoc } from './converters/to-asciidoc'; |
|
import { processAsciidoc } from './processors/asciidoc'; |
|
import { extractMetadata } from './extractors/metadata'; |
|
|
|
/** |
|
* Default parser options |
|
*/ |
|
export function defaultOptions(): ParserOptions { |
|
return { |
|
linkBaseURL: '', |
|
enableAsciiDoc: true, |
|
enableMarkdown: true, |
|
enableCodeHighlighting: true, |
|
enableLaTeX: true, |
|
enableMusicalNotation: true, |
|
enableNostrAddresses: true, |
|
}; |
|
} |
|
|
|
/** |
|
* Main parser for Nostr event content |
|
* Handles multiple content formats: AsciiDoc, Markdown, code syntax, |
|
* LaTeX, musical notation, and nostr: prefixed addresses |
|
* |
|
* Everything is converted to AsciiDoc first, then processed through AsciiDoctor |
|
*/ |
|
export class Parser { |
|
private options: Required<ParserOptions>; |
|
|
|
constructor(options: ParserOptions = {}) { |
|
const defaults = defaultOptions(); |
|
this.options = { |
|
linkBaseURL: options.linkBaseURL ?? defaults.linkBaseURL ?? '', |
|
enableAsciiDoc: options.enableAsciiDoc ?? defaults.enableAsciiDoc ?? true, |
|
enableMarkdown: options.enableMarkdown ?? defaults.enableMarkdown ?? true, |
|
enableCodeHighlighting: options.enableCodeHighlighting ?? defaults.enableCodeHighlighting ?? true, |
|
enableLaTeX: options.enableLaTeX ?? defaults.enableLaTeX ?? true, |
|
enableMusicalNotation: options.enableMusicalNotation ?? defaults.enableMusicalNotation ?? true, |
|
enableNostrAddresses: options.enableNostrAddresses ?? defaults.enableNostrAddresses ?? true, |
|
}; |
|
} |
|
|
|
/** |
|
* Process Nostr event content and return HTML |
|
* Automatically detects the content format and processes accordingly |
|
* Everything is converted to AsciiDoc first, then processed through AsciiDoctor |
|
*/ |
|
async process(content: string): Promise<ProcessResult> { |
|
// Extract metadata from original content (before conversion) |
|
const metadata = extractMetadata(content, this.options.linkBaseURL); |
|
|
|
// Detect content format |
|
const format = detectFormat(content); |
|
|
|
// Convert everything to AsciiDoc format first |
|
const asciidocContent = convertToAsciidoc( |
|
content, |
|
format, |
|
this.options.linkBaseURL, |
|
{ |
|
enableNostrAddresses: this.options.enableNostrAddresses, |
|
} |
|
); |
|
|
|
// Process through AsciiDoctor |
|
const result = await processAsciidoc( |
|
asciidocContent, |
|
{ |
|
enableCodeHighlighting: this.options.enableCodeHighlighting, |
|
enableLaTeX: this.options.enableLaTeX, |
|
enableMusicalNotation: this.options.enableMusicalNotation, |
|
originalContent: content, // Pass original for LaTeX detection |
|
} |
|
); |
|
|
|
// Combine with extracted metadata |
|
return { |
|
...result, |
|
nostrLinks: metadata.nostrLinks, |
|
wikilinks: metadata.wikilinks, |
|
hashtags: metadata.hashtags, |
|
links: metadata.links, |
|
media: metadata.media, |
|
}; |
|
} |
|
} |
|
|
|
/** |
|
* Convenience function to process content with default options |
|
*/ |
|
export async function process(content: string, options?: ParserOptions): Promise<ProcessResult> { |
|
const parser = new Parser(options); |
|
return parser.process(content); |
|
}
|
|
|