import { ParsedTypings } from '../shared/types_domain_specific'; import { ParserTypings } from './types_parser'; import { transformInputText } from './utils_parser'; import { visitors } from './visitors'; import { ParserNode } from './parser_node'; export class Parser implements ParserTypings.Parser { public zoneObj: ParserTypings.Parser['zoneObj']; public parsingMeta: ParserTypings.Parser['parsingMeta'] = new Map(); public stack: ParserTypings.Parser['stack'] = []; public visitors: ParserTypings.Parser['visitors'] = visitors; public input: ParserTypings.Parser['input'] = { textInput: null as any, textInputFlattened: '', textInputSplitByLine: [], }; constructor($originName: string = '') { this.zoneObj = { $ORIGIN: $originName } as ParsedTypings.Obj; this.input.$originName = $originName; } public setText(textInput: string): this { const [flattened, splitByLine] = transformInputText(textInput); this.input.textInput = textInput; this.input.textInputFlattened = flattened; this.input.textInputSplitByLine = splitByLine; return this; } /** * @perf can optimize this looping * @note sharing the node instance across iterations can save memory but also add confusion like React SyntheticEvent */ public parse(): this { /* istanbul ignore next */ if (process.env.NODE_ENV !== 'production' && this.input.textInput == null) { console.error(`[Parser] must setText(string) before calling parse()`); } const node = new ParserNode(this); const findVisitor = (x: ParserTypings.Visitor) => x.isSatisfied(node); for (const [ index, lineContent, ] of this.input.textInputSplitByLine.entries()) { node.update(lineContent, index); this.visitors.find(findVisitor)?.visit(this, node); } return this; } }