import type { Line } from "./tokenize" ; import { tokenize } from "./tokenize" ; import { FORMAL_NAMES } from "./formal_names" ; import { Parent } from "unist" ; const rTerminator = new RegExp ( "(\\r|\\n|\\r\\n|\\n\\r)" , "g" ) ; function lineToNode ( { tag , value , xref_id , pointer } ) { const formal_name = FORMAL_NAMES [ tag ] ; const node = { type : tag , data : { formal_name , } , value , children : [ ] , } ; if ( xref_id ) node . data ! . xref_id = xref_id ; if ( pointer ) node . data ! . pointer = pointer ; if ( tag . startsWith ( "_" ) ) node . data ! . custom_tag = true ; return node ; } function handleContinued ( { tag , value , pointer } , head ) { if ( ! ( tag === "CONC" || tag === "CONT" ) ) return false ; if ( pointer ) throw new Error ( "Cannot concatenate a pointer" ) ; if ( ! head . value ) head . value = "" ; if ( tag === "CONT" ) head . value += "\n" ; if ( value ) { head . value += value ; } return true ; } param input returns export function parse ( input ) { let root = { type : "root" , children : [ ] , } ; const lines = input . split ( rTerminator ) . filter ( ( str ) => str . trim ( ) ) ; let stack = [ ] ; let lastLevel = 0 ; for ( const line of lines ) { const tokens = tokenize ( line ) ; if ( handleContinued ( tokens , stack [ stack . length - 1 ] ) ) { continue ; } const node = lineToNode ( tokens ) ; const { level } = tokens ; if ( level == 0 ) { root . children . push ( node ) ; stack = [ node ] ; } else if ( lastLevel == level - 1 || level <= lastLevel ) { for ( let i = 0 ; i <= lastLevel - level ; i ++ ) { stack . pop ( ) ; } stack [ stack . length - 1 ] . children . push ( node ) ; stack . push ( node ) ; } else { throw new Error ( `Illegal nesting: transition from ${ lastLevel } to ${ level }` ) ; } lastLevel = level ; } return root ; }