Browse Source

Update variable names and parse document metadata

master
buttercat1791 2 years ago
parent
commit
b04e73ca34
  1. 129
      src/lib/parser.ts

129
src/lib/parser.ts

@ -10,6 +10,17 @@ import { @@ -10,6 +10,17 @@ import {
type ProcessorOptions
} from 'asciidoctor';
interface IndexMetadata {
authors?: string[];
version?: string;
edition?: string;
isbn?: string;
publicationDate?: string;
publisher?: string;
summary?: string;
coverImage?: string;
}
/**
* @classdesc Pharos is an extension of the Asciidoctor class that adds Nostr Knowledge Base (NKB)
* features to core Asciidoctor functionality. Asciidoctor is used to parse an AsciiDoc document
@ -49,7 +60,14 @@ export default class Pharos extends Asciidoctor { @@ -49,7 +60,14 @@ export default class Pharos extends Asciidoctor {
/**
* The ID of the root node in the document.
*/
private rootId?: string;
private rootNodeId?: string;
/**
* The ID of the root index event generated for the document.
*/
private rootIndexId?: string;
private rootIndexMetadata: IndexMetadata = {};
/**
* A map of node IDs to the nodes themselves.
@ -64,7 +82,7 @@ export default class Pharos extends Asciidoctor { @@ -64,7 +82,7 @@ export default class Pharos extends Asciidoctor {
/**
* A map of index IDs to the IDs of the nodes they reference.
*/
private indexToChildrenMap: Map<string, Set<string>> = new Map<string, Set<string>>();
private indexToChildEventsMap: Map<string, Set<string>> = new Map<string, Set<string>>();
/**
* A map of node IDs to the Nostr event IDs of the events they generate.
@ -94,7 +112,7 @@ export default class Pharos extends Asciidoctor { @@ -94,7 +112,7 @@ export default class Pharos extends Asciidoctor {
}
getEvents(pubkey: string): NDKEvent[] {
const stack = this.stackEventNodes(this.rootId!);
const stack = this.stackEventNodes();
return this.generateEvents(stack, pubkey);
}
@ -111,23 +129,23 @@ export default class Pharos extends Asciidoctor { @@ -111,23 +129,23 @@ export default class Pharos extends Asciidoctor {
* - Each ID of a node containing children is mapped to the set of IDs of its children.
*/
private treeProcessor(treeProcessor: Extensions.TreeProcessor, document: Document) {
this.rootId = document.getId();
this.nodes.set(this.rootId, document);
this.eventToKindMap.set(this.rootId, 30040);
this.indexToChildrenMap.set(this.rootId, new Set<string>());
this.rootNodeId = document.getId();
this.nodes.set(this.rootNodeId, document);
this.eventToKindMap.set(this.rootNodeId, 30040);
this.indexToChildEventsMap.set(this.rootNodeId, new Set<string>());
/** FIFO queue (uses `Array.push()` and `Array.shift()`). */
const queue: AbstractNode[] = document.getBlocks();
const nodeQueue: AbstractNode[] = document.getBlocks();
while (queue.length > 0) {
const block = queue.shift();
while (nodeQueue.length > 0) {
const block = nodeQueue.shift();
if (!block) {
continue;
}
if (block instanceof Section) {
const children = this.processSection(block);
queue.push(...children);
nodeQueue.push(...children);
} else {
this.processBlock(block as Block);
}
@ -139,19 +157,19 @@ export default class Pharos extends Asciidoctor { @@ -139,19 +157,19 @@ export default class Pharos extends Asciidoctor {
* @param section The section to process.
* @returns An array of the section's child nodes. If there are no child nodes, returns an empty
* array.
* @remarks Sections are mapped as kind 30040 indexToChildrenMap by default.
* @remarks Sections are mapped as kind 30040 indexToChildEventsMap by default.
*/
private processSection(section: Section): AbstractNode[] {
const id = section.getId();
const sectionId = section.getId();
// Prevent duplicates.
if (this.nodes.has(id)) {
if (this.nodes.has(sectionId)) {
return [];
}
this.nodes.set(id, section);
this.eventToKindMap.set(id, 30040); // Sections are indexToChildrenMap by default.
this.indexToChildrenMap.set(id, new Set<string>());
this.nodes.set(sectionId, section);
this.eventToKindMap.set(sectionId, 30040); // Sections are indexToChildEventsMap by default.
this.indexToChildEventsMap.set(sectionId, new Set<string>());
const parentId = section.getParent()?.getId();
if (!parentId) {
@ -159,7 +177,7 @@ export default class Pharos extends Asciidoctor { @@ -159,7 +177,7 @@ export default class Pharos extends Asciidoctor {
}
// Add the section to its parent index.
this.indexToChildrenMap.get(parentId)?.add(id);
this.indexToChildEventsMap.get(parentId)?.add(sectionId);
// Limit to 5 levels of section depth.
if (section.getLevel() >= 5) {
@ -175,15 +193,15 @@ export default class Pharos extends Asciidoctor { @@ -175,15 +193,15 @@ export default class Pharos extends Asciidoctor {
* @remarks Blocks are mapped as kind 30041 zettels by default.
*/
private processBlock(block: Block): void {
const id = block.getId();
const blockId = block.getId();
// Prevent duplicates.
if (this.nodes.has(id)) {
if (this.nodes.has(blockId)) {
return;
}
this.nodes.set(id, block);
this.eventToKindMap.set(id, 30041); // Blocks are zettels by default.
this.nodes.set(blockId, block);
this.eventToKindMap.set(blockId, 30041); // Blocks are zettels by default.
const parentId = block.getParent()?.getId();
if (!parentId) {
@ -191,7 +209,7 @@ export default class Pharos extends Asciidoctor { @@ -191,7 +209,7 @@ export default class Pharos extends Asciidoctor {
}
// Add the block to its parent index.
this.indexToChildrenMap.get(parentId)?.add(id);
this.indexToChildEventsMap.get(parentId)?.add(blockId);
}
//#endregion
@ -201,26 +219,25 @@ export default class Pharos extends Asciidoctor { @@ -201,26 +219,25 @@ export default class Pharos extends Asciidoctor {
/**
* Generates a stack of node IDs such that processing them in LIFO order will generate any events
* used by an index before generating that index itself.
* @param rootNodeId The ID of the node from which to start processing.
* @returns An array of node IDs in the order they should be processed to generate events.
*/
private stackEventNodes(rootNodeId: string): string[] {
const traversalStack: string[] = [this.rootId!];
const eventStack: string[] = [];
private stackEventNodes(): string[] {
const tempNodeIdStack: string[] = [this.rootNodeId!];
const nodeIdStack: string[] = [];
while (traversalStack.length > 0) {
const parentId = traversalStack.pop()!;
eventStack.push(parentId);
while (tempNodeIdStack.length > 0) {
const parentId = tempNodeIdStack.pop()!;
nodeIdStack.push(parentId);
if (!this.indexToChildrenMap.has(parentId)) {
if (!this.indexToChildEventsMap.has(parentId)) {
continue;
}
const childIds = Array.from(this.indexToChildrenMap.get(parentId)!);
traversalStack.push(...childIds);
const childIds = Array.from(this.indexToChildEventsMap.get(parentId)!);
tempNodeIdStack.push(...childIds);
}
return eventStack;
return nodeIdStack;
}
/**
@ -235,7 +252,6 @@ export default class Pharos extends Asciidoctor { @@ -235,7 +252,6 @@ export default class Pharos extends Asciidoctor {
while (nodeIdStack.length > 0) {
const nodeId = nodeIdStack.pop();
let event: NDKEvent;
switch (this.eventToKindMap.get(nodeId!)) {
case 30040:
@ -244,7 +260,7 @@ export default class Pharos extends Asciidoctor { @@ -244,7 +260,7 @@ export default class Pharos extends Asciidoctor {
case 30041:
default:
// Kind 30041 is currently the default contentful kind.
// Kind 30041 (zettel) is currently the default kind for contentful events.
events.push(this.generateZettelEvent(nodeId!, pubkey));
break;
}
@ -263,7 +279,7 @@ export default class Pharos extends Asciidoctor { @@ -263,7 +279,7 @@ export default class Pharos extends Asciidoctor {
*/
private generateIndexEvent(nodeId: string, pubkey: string): NDKEvent {
const title = (this.nodes.get(nodeId)! as AbstractBlock).getTitle();
const childTags = Array.from(this.indexToChildrenMap.get(nodeId)!)
const childTags = Array.from(this.indexToChildEventsMap.get(nodeId)!)
.map(id => ['#e', this.eventIds.get(id)!]);
const event = new NDKEvent(this.ndk);
@ -277,11 +293,50 @@ export default class Pharos extends Asciidoctor { @@ -277,11 +293,50 @@ export default class Pharos extends Asciidoctor {
event.created_at = Date.now();
event.pubkey = pubkey;
// Add optional metadata to the root index event.
if (nodeId === this.rootNodeId) {
const document = this.nodes.get(nodeId) as Document;
// Store the metadata so it is available if we need it later.
this.rootIndexMetadata = {
authors: document
.getAuthors()
.map(author => author.getName())
.filter(name => name != null),
version: document.getRevisionNumber(),
edition: document.getRevisionRemark(),
publicationDate: document.getRevisionDate(),
};
if (this.rootIndexMetadata.authors) {
event.tags.push(['author', ...this.rootIndexMetadata.authors!]);
}
if (this.rootIndexMetadata.version || this.rootIndexMetadata.edition) {
event.tags.push(
[
'version',
this.rootIndexMetadata.version!,
this.rootIndexMetadata.edition!
].filter(value => value != null)
);
}
if (this.rootIndexMetadata.publicationDate) {
event.tags.push(['published_on', this.rootIndexMetadata.publicationDate!]);
}
}
// Event ID generation must be the last step.
const eventId = event.getEventHash();
this.eventIds.set(nodeId, eventId);
event.id = eventId;
// Store the root index ID in case we need it later.
if (nodeId === this.rootNodeId) {
this.rootIndexId = eventId;
}
return event;
}

Loading…
Cancel
Save