UNPKG

bramble-parser

Version:

Bramble is a lightweight recursive descent parser that processes .havenfs files, returning a structured Json tree that can be used to construct an in-memory FS representation. The parser is based on line-based grammar, chunk headers, and metadata declarat

80 lines (63 loc) 2.65 kB
import { ELexerTokens, ErrorCode } from '../common'; import { BaseParser } from './baseParser'; import { HavenException } from '../errors'; export class ReferenceParser extends BaseParser { references: HavenReference[]; nodes: HavenFSNode[]; constructor(references: HavenReference[], nodes: HavenFSNode[], entries: ILexerToken[][]) { super(entries); this.nodes = nodes; this.references = references; this.parse(); } parse(): void { for (const line of this.entries) { const first = line[0]; const position = this.getPosition(first); const fromIdToken = this.getFromIdToken(line); const toToken = this.getTokenValueAt(line, ELexerTokens.ATT_TO); const typeToken = this.getTokenValueAt(line, ELexerTokens.ATT_TYPE); const contextToken = this.getTokenValueAt(line, ELexerTokens.ATT_CONTEXT, true); if (!fromIdToken || !toToken || !typeToken) { new HavenException('Missing mandatory fields in REF', position, ErrorCode.MISSING_TOKEN); continue; } if (this.isTokenInvalid(toToken) || this.isTokenInvalid(typeToken)) { new HavenException('Missing mandatory reference field', position, ErrorCode.MISSING_TOKEN); continue; } if (!this.hasFileById(fromIdToken.value)) { new HavenException(`Missing FILE: ${fromIdToken.value}`, position, ErrorCode.MISSING_TOKEN); continue; } if (!this.hasFileById(toToken)) { new HavenException(`Missing FILE: ${toToken}`, position, ErrorCode.MISSING_TOKEN); continue; } this.references.push(this.createReference(fromIdToken.value, toToken, typeToken, contextToken)); } } private hasFileById(id: string): boolean { return this.nodes.some((node) => node.type === 'file' && node.id === id); } private getFromIdToken(line: ILexerToken[]): ILexerToken | undefined { return line.find(t => t.type === ELexerTokens.ID); } private getTokenValueAt(line: ILexerToken[], tokenType: ELexerTokens, optional = false): string | undefined { const index = line.findIndex(t => t.type === tokenType); if (index === -1) return optional ? undefined : ''; return line[index + 2]?.value; } private isTokenInvalid(value: string): boolean { return !value || value.trim() === ''; } private getPosition(first: ILexerToken | undefined): { line: number; column: number } { return { line: first?.line ?? 0, column: first?.start ?? 0, }; } private createReference(from: string, to: string, type: string, context?: string): HavenReference { return { from, to, type, context }; } }