|
|
6 hours ago | |
|---|---|---|
| integration-fixtures | 6 hours ago | |
| src | 6 hours ago | |
| .gitignore | 6 hours ago | |
| README.md | 6 hours ago | |
| asciidoc_testdoc.adoc | 6 hours ago | |
| package-lock.json | 6 hours ago | |
| package.json | 6 hours ago | |
| tsconfig.json | 6 hours ago | |
| vitest.config.ts | 6 hours ago | |
README.md
gc-parser-asciidoc
Lightweight AsciiDoc parser (no asciidoctor dependency) and publication helpers for Nostr. Accepts Nostr events as JSON and returns HTML.
- Single events (30818, 30041): pass one event JSON → get HTML.
- Publications (30040): pass one 30040 index event + section event JSONs → get one HTML page.
Size: ~100 KB built output, zero runtime dependencies — about 80× smaller than @asciidoctor/core (~8.5 MB).
Features
- Headings
=…======with optional TOC - Nostr links — full bech32 (
naddr1,npub1,nevent1,nprofile1,note1) andnostr:...in text become links - #hashtags — rendered as
<span class="hashtag">#tag</span>. Style with a different color and no underline in your CSS, e.g..hashtag { color: var(--tag-color); text-decoration: none; } - Wikilinks
[[id]],[[id|label]] - URLs — bare
https://...andlink:url[text]; backticked URLs stay plaintext - Inline — bold, italic,
code,strikethrough, ~sub~, ^sup^ - Lists — nested
*/**, ordered./.., mixed
Usage
All APIs accept Nostr events as JSON: { kind, content, tags, pubkey?, id? }.
Single events (30818, 30041)
Pass one event (e.g. from a relay) and get HTML:
import { renderEvent } from 'gc-parser-asciidoc';
const event = { kind: 30041, content: '= Section\n\nBody.', tags: [['title', 'Section']], pubkey: '...' };
const html = renderEvent(event, {
wikilinkUrl: '/events?d={dtag}',
nostrBaseUrl: 'https://app.example.com/',
hashtagClass: 'hashtag',
});
For raw content (no event object), use renderEventContent(content, options) or parseAsciiDoc(content, options).
Publications (kind 30040)
Pass the 30040 index event and an array of section events (30041, 30818); get one HTML page:
import { renderPublicationFromEvents } from 'gc-parser-asciidoc';
const indexEvent = { kind: 30040, content: '', tags: [['title', 'My Book'], ['d', 'my-book'], ['a', '30041:...:ch1'], ['a', '30041:...:ch2']], pubkey: '...' };
const sectionEvents = [
{ kind: 30041, content: '...', tags: [['title', 'Chapter 1'], ['d', 'ch1']], pubkey: '...' },
{ kind: 30041, content: '...', tags: [['title', 'Chapter 2'], ['d', 'ch2']], pubkey: '...' },
];
const { html, tableOfContents, asciidoc } = renderPublicationFromEvents(indexEvent, sectionEvents, { toc: true });
If you already have structured data (not raw events), use renderPublication({ index, sections }, options). Helpers: toPublicationIndexLike(event) to get PublicationIndexLike from a 30040 event; buildPublicationAsciiDoc(input) for the combined AsciiDoc string.
Integration tests
Integration tests render events from fixture files in integration-fixtures/ (no relay required). They are skipped unless RUN_INTEGRATION=1:
RUN_INTEGRATION=1 npm run test:integration
Rendered HTML is written to integration-output/single-event.html and integration-output/publication.html for inspection in a browser.
To download events and save/refresh the fixtures (fetch from wss://thecitadel.nostr1.com and overwrite integration-fixtures/*.json):
npm run test:integration:record
Commit the updated integration-fixtures/*.json so others can run the integration test without a relay. Requires nostr-tools (devDependency) only when recording.