79 lines
2.1 KiB
JavaScript
79 lines
2.1 KiB
JavaScript
import { useDocument } from '@terrace/core'
|
|
import { createStringReader } from '@terrace/core/readers/js-string'
|
|
|
|
export async function parse(lines, schema) {
|
|
const doc = useDocument(createStringReader(lines))
|
|
|
|
function createScope(line, matchers) {
|
|
return {
|
|
block: [line, []],
|
|
handlers: [],
|
|
matchers: matchers
|
|
}
|
|
}
|
|
|
|
const macros = schema.macros
|
|
|
|
const scopes = [createScope('root', {
|
|
title ({ addHandler }) {
|
|
addHandler(scope => [scope[0].split(' ')[0], scope[0].split(' ').slice(1).join(' ')])
|
|
},
|
|
options ({ addMatcher }) {
|
|
addMatcher({
|
|
parameter1({ addHandler }) {
|
|
addHandler(scope => [scope[0].split(' ')[0], +scope[0].split(' ').slice(1).join(' ')])
|
|
}
|
|
})
|
|
}
|
|
})]
|
|
|
|
let ended = false
|
|
while (!ended) {
|
|
ended = await doc.next()
|
|
if (ended) break;
|
|
const level = doc.level() + 1
|
|
|
|
// Trigger macros for closed scopes.
|
|
for (let i = scopes.length - 1; i >= level; --i) {
|
|
const scope = scopes[i]
|
|
const parent = scopes[i - 1]
|
|
|
|
// Remove empty arrays from scopes without children.
|
|
if (scope.block[1] && !scope.block[1].length) scope.block.length = 1
|
|
|
|
// Postprocess scope with relevant macros.
|
|
scope.block = scope.handlers.reduce((block, handler) => {
|
|
return handler(block)
|
|
}, [...scope.block])
|
|
|
|
// Add to parent block.
|
|
parent.block[1].push(scope.block)
|
|
}
|
|
|
|
// Reset scope length to avoid dangling scopes.
|
|
scopes.length = level
|
|
|
|
// Define current scope
|
|
const scope = scopes[level] = createScope(doc.line(), {})
|
|
// Determine parent for this scope.
|
|
const parent = scopes[level - 1]
|
|
|
|
// Add a postprocess handler for this scope.
|
|
// Ie. When we leave the scope, rewrite it using this handler.
|
|
function addHandler(handler) {
|
|
scope.handlers.push(handler)
|
|
}
|
|
|
|
// Add matchers for this scope's children.
|
|
function addMatcher(definition) {
|
|
scope.matchers = definition
|
|
}
|
|
|
|
// Run matching matchers for this scope.
|
|
if (parent.matchers[doc.head()]) {
|
|
parent.matchers[doc.head()]({ addHandler, addMatcher })
|
|
}
|
|
}
|
|
|
|
return scopes[0].block
|
|
} |