Start making more generic.

This commit is contained in:
Joshua Bemenderfer 2022-11-13 16:29:28 -05:00
parent a6435368aa
commit 172f9d5ca1
4 changed files with 321 additions and 276 deletions

View File

@ -1,276 +0,0 @@
import { createLineData, useDocument } from '@terrace/core'
import { createStringReader } from '@terrace/core/readers/js-string'
const tceSchema = `
types
section object, text as content, tail as pos
content string
pos number
position number
options object
parameter1 number
parameter2 string
root object
title string
options options
options2 options
subsection
type section
collate collection
list array
- string
collection collection
section section
`
const schema = {
types: {
section: {
type: 'object',
text: 'content',
tail: 'pos',
values: {
content: 'string',
pos: 'number',
position: {
type: 'number'
}
}
},
options: {
type: 'object',
values: {
parameter1: 'number',
parameter2: 'string'
}
},
advList: {
type: 'array',
values: {
section: 'section'
}
}
},
root: {
type: 'object',
values: {
title: 'string',
options: 'options',
options2: 'options',
subsection: {
type: 'section',
// Allows a particular repeated key to collect itself under a multi-value root as an array.
collate: 'collection'
},
list: {
// Defines an array where all entries must conform to specific types. No other keys are permitted.
// Ex: [ value, value ]
type: 'array',
values: {
'-': 'string'
}
},
collection: {
// Defines an array where all entries must conform to specific types. They will be segregated by key. No other keys are permitted.
// Ex: [ {key: value }, { key: value }]
type: 'collection',
values: {
section: 'section'
}
}
}
}
}
const lines = [
`title Example`,
`options`,
` parameter1 30`,
` parameter2 Enim eu id anim minim reprehenderit nostrud eu amet deserunt ea ut do cupidatat ea.`,
`options2`,
` parameter1 0`,
` parameter2 Esse incididunt et est adipisicing eiusmod aliqua enim ea aliqua id enim.`,
`subsection`,
` position 1`,
` Ea dolore in aliquip fugiat anim adipisicing amet aute tempor et deserunt est duis sint.`,
`subsection 2`,
` position 2`,
` Aute deserunt incididunt ad in sint adipisicing est officia velit pariatur ipsum deserunt quis nulla.`,
` Ea dolore in aliquip fugiat anim adipisicing amet aute tempor et deserunt est duis sint.`,
`list`,
` - item 1`,
` - item 2`,
`collection`,
` section`,
` lorem ipsum 1`,
` section`,
` lorem ipsum 2`
]
const typeHandlers = {
string (doc) {
return doc.tail().slice(1)
},
number (doc) {
return +doc.tail().slice(1)
},
object (doc, handlers, definition, level) {
level = level != null ? level : doc.level() + 1
definition = lookup(definition)
const object = {}
for (let [key, child] of Object.entries(definition.values)) {
child = lookup(child)
addHandler(handlers, level, key, child, (key, value) => {
if (child.collate === 'array') {
if (!object[key]) object[key] = []
object[key].push(value)
return
} else if (child.collate === 'collection') {
if (!object[key]) object[key] = []
object[key].push({ [key]: value })
return
} else {
object[key] = value
}
})
}
if (definition.tail) {
const tailKey = definition.tail
const tailType = definition.values[tailKey]
object[tailKey] = typeHandlers[tailType](doc, handlers)
}
if (definition.text) {
const textKey = definition.text
const textType = definition.values[textKey]
object[textKey] = ''
addHandler(handlers, level, '', textType, (key, value) => {
object[textKey] += object[textKey] ? `\n${doc.line()}` : doc.line()
})
}
return object
},
array (doc, handlers, definition, level) {
level = level != null ? level : doc.level() + 1
definition = lookup(definition)
const array = []
for (let [key, child] of Object.entries(definition.values)) {
child = lookup(child)
addHandler(handlers, level, key, child, (key, value) => {
array.push(value)
})
}
// if (definition.tail) {
// const tailKey = definition.tail
// const tailType = definition.values[tailKey]
// object[tailKey] = typeHandlers[tailType](doc, handlers)
// }
// if (definition.text) {
// const textKey = definition.text
// const textType = definition.values[textKey]
// object[textKey] = ''
// addHandler(handlers, level, '', textType, (key, value) => {
// object[textKey] += object[textKey] ? `\n${doc.line()}` : doc.line()
// })
// }
return array
},
collection (doc, handlers, definition, level) {
level = level != null ? level : doc.level() + 1
definition = lookup(definition)
const collection = []
for (let [key, child] of Object.entries(definition.values)) {
child = lookup(child)
addHandler(handlers, level, key, child, (key, value) => {
collection.push({ [key]: value })
})
}
// if (definition.tail) {
// const tailKey = definition.tail
// const tailType = definition.values[tailKey]
// object[tailKey] = typeHandlers[tailType](doc, handlers)
// }
// if (definition.text) {
// const textKey = definition.text
// const textType = definition.values[textKey]
// object[textKey] = ''
// addHandler(handlers, level, '', textType, (key, value) => {
// object[textKey] += object[textKey] ? `\n${doc.line()}` : doc.line()
// })
// }
return collection
},
}
function lookup (definition) {
const type = typeof definition === 'string' ? definition : definition.type
const resolvedDefinition = schema.types[type] || definition
return typeof definition === 'string' ? resolvedDefinition : Object.assign({}, definition, resolvedDefinition)
}
function registerTypes(typeHandlers, types) {
for (const [key, definition] of Object.entries(types)) {
const existingType = typeof definition === 'string' ? definition : definition.type
typeHandlers[key] = typeHandlers[existingType]
}
}
function addHandler(handlers, level, key, definition, resolve) {
const type = typeof definition === 'string' ? definition : definition.type
if (!handlers[level]) handlers[level] = []
handlers[level].push({
key,
resolve,
definition,
handler: typeHandlers[type]
})
}
async function main() {
const doc = useDocument(createStringReader(lines))
const handlers = []
registerTypes(typeHandlers, schema.types)
const root = typeHandlers.object(doc, handlers, schema.root, 0)
let ended = false
while (!ended) {
ended = await doc.next()
if (ended) break;
const level = doc.level()
handlers.length = level + 1
const unmatchedHandler = handlers[level]?.find(h => h.key === '')
let matched = false
for (const { key, definition, resolve, handler } of handlers[level] || []) {
if (doc.head() !== key) continue;
resolve(doc.head(), handler(doc, handlers, definition))
matched = true
break
}
if (!matched && unmatchedHandler) {
const { resolve, definition, handler } = unmatchedHandler
resolve(doc.head(), handler(doc, handlers, definition))
}
}
console.log(root)
}
main()

View File

@ -0,0 +1,164 @@
import { createLineData, useDocument } from '@terrace/core'
import { createStringReader } from '@terrace/core/readers/js-string'
export async function parse(lines, schema) {
const typeHandlers = {
string (doc) {
return doc.tail().slice(1)
},
number (doc) {
return +doc.tail().slice(1)
},
object (doc, handlers, definition, level) {
level = level != null ? level : doc.level() + 1
definition = lookup(definition)
const object = {}
for (let [key, child] of Object.entries(definition.values)) {
child = lookup(child)
addHandler(handlers, level, key, child, (key, value) => {
if (child.collate === 'array') {
if (!object[key]) object[key] = []
object[key].push(value)
return
} else if (child.collate === 'collection') {
if (!object[key]) object[key] = []
object[key].push({ [key]: value })
return
} else {
object[key] = value
}
})
}
if (definition.tail) {
const tailKey = definition.tail
const tailType = definition.values[tailKey]
object[tailKey] = typeHandlers[tailType](doc, handlers)
}
if (definition.text) {
const textKey = definition.text
const textType = definition.values[textKey]
object[textKey] = ''
addHandler(handlers, level, '', textType, (key, value) => {
object[textKey] += object[textKey] ? `\n${doc.line()}` : doc.line()
})
}
return object
},
array (doc, handlers, definition, level) {
level = level != null ? level : doc.level() + 1
definition = lookup(definition)
const array = []
for (let [key, child] of Object.entries(definition.values)) {
child = lookup(child)
addHandler(handlers, level, key, child, (key, value) => {
array.push(value)
})
}
// if (definition.tail) {
// const tailKey = definition.tail
// const tailType = definition.values[tailKey]
// object[tailKey] = typeHandlers[tailType](doc, handlers)
// }
// if (definition.text) {
// const textKey = definition.text
// const textType = definition.values[textKey]
// object[textKey] = ''
// addHandler(handlers, level, '', textType, (key, value) => {
// object[textKey] += object[textKey] ? `\n${doc.line()}` : doc.line()
// })
// }
return array
},
collection (doc, handlers, definition, level) {
level = level != null ? level : doc.level() + 1
definition = lookup(definition)
const collection = []
for (let [key, child] of Object.entries(definition.values)) {
child = lookup(child)
addHandler(handlers, level, key, child, (key, value) => {
collection.push({ [key]: value })
})
}
// if (definition.tail) {
// const tailKey = definition.tail
// const tailType = definition.values[tailKey]
// object[tailKey] = typeHandlers[tailType](doc, handlers)
// }
// if (definition.text) {
// const textKey = definition.text
// const textType = definition.values[textKey]
// object[textKey] = ''
// addHandler(handlers, level, '', textType, (key, value) => {
// object[textKey] += object[textKey] ? `\n${doc.line()}` : doc.line()
// })
// }
return collection
},
}
function lookup (definition) {
const type = typeof definition === 'string' ? definition : definition.type
const resolvedDefinition = schema.types[type] || definition
return typeof definition === 'string' ? resolvedDefinition : Object.assign({}, definition, resolvedDefinition)
}
function registerTypes(typeHandlers, types) {
for (const [key, definition] of Object.entries(types)) {
const existingType = typeof definition === 'string' ? definition : definition.type
typeHandlers[key] = typeHandlers[existingType]
}
}
function addHandler(handlers, level, key, definition, resolve) {
const type = typeof definition === 'string' ? definition : definition.type
if (!handlers[level]) handlers[level] = []
handlers[level].push({
key,
resolve,
definition,
handler: typeHandlers[type]
})
}
const doc = useDocument(createStringReader(lines))
const handlers = []
registerTypes(typeHandlers, schema.types)
const root = typeHandlers.object(doc, handlers, schema.root, 0)
let ended = false
while (!ended) {
ended = await doc.next()
if (ended) break;
const level = doc.level()
handlers.length = level + 1
const unmatchedHandler = handlers[level]?.find(h => h.key === '')
let matched = false
for (const { key, definition, resolve, handler } of handlers[level] || []) {
if (doc.head() !== key) continue;
resolve(doc.head(), handler(doc, handlers, definition))
matched = true
break
}
if (!matched && unmatchedHandler) {
const { resolve, definition, handler } = unmatchedHandler
resolve(doc.head(), handler(doc, handlers, definition))
}
}
return root
}

View File

@ -0,0 +1,114 @@
import { parse } from './core.js'
const schemaTCE = `
types
section object, text as content, tail as pos
content string
pos number
position number
options object
parameter1 number
parameter2 string
root object
title string
options options
options2 options
subsection section
collate collection
list array
- string
collection collection
section section
`
const schema = {
types: {
section: {
type: 'object',
text: 'content',
tail: 'pos',
values: {
content: 'string',
pos: 'number',
position: {
type: 'number'
}
}
},
options: {
type: 'object',
values: {
parameter1: 'number',
parameter2: 'string'
}
},
advList: {
type: 'array',
values: {
section: 'section'
}
}
},
root: {
type: 'object',
values: {
title: 'string',
options: 'options',
options2: 'options',
subsection: {
type: 'section',
// Allows a particular repeated key to collect itself under a multi-value root as an array.
collate: 'collection'
},
list: {
// Defines an array where all entries must conform to specific types. No other keys are permitted.
// Ex: [ value, value ]
type: 'array',
values: {
'-': 'string'
}
},
collection: {
// Defines an array where all entries must conform to specific types. They will be segregated by key. No other keys are permitted.
// Ex: [ {key: value }, { key: value }]
type: 'collection',
values: {
section: 'section'
}
}
}
}
}
const lines = [
`title Example`,
`options`,
` parameter1 30`,
` parameter2 Enim eu id anim minim reprehenderit nostrud eu amet deserunt ea ut do cupidatat ea.`,
`options2`,
` parameter1 0`,
` parameter2 Esse incididunt et est adipisicing eiusmod aliqua enim ea aliqua id enim.`,
`subsection`,
` position 1`,
` Ea dolore in aliquip fugiat anim adipisicing amet aute tempor et deserunt est duis sint.`,
`subsection 2`,
` position 2`,
` Aute deserunt incididunt ad in sint adipisicing est officia velit pariatur ipsum deserunt quis nulla.`,
` Ea dolore in aliquip fugiat anim adipisicing amet aute tempor et deserunt est duis sint.`,
`list`,
` - item 1`,
` - item 2`,
`collection`,
` section`,
` lorem ipsum 1`,
` section`,
` lorem ipsum 2`
]
async function main() {
console.log(await parse(lines, schema))
}
main()

View File

@ -0,0 +1,43 @@
const schemaSchemaTCE = `
types
primitive object, tail as type
any primitive
root object
types object, optional
any primitive
root object
any primitive
`
const schemaSchemaJSON = {
types: {
primitive: {
type: 'object',
tail: 'type',
values: {
type: 'string',
any: 'primitive'
}
},
},
root: {
type: 'object',
values: {
types: {
type: 'object',
optional: true,
values: {
any: 'primitive'
}
},
root: {
type: 'object',
values: {
any: 'primitive'
}
}
},
}
}