import { useDocument } from '@terrace/core' import { createStringReader } from '@terrace/core/readers/js-string' export async function parse(lines) { const { tail, each, match, buildObject } = useDocument(createStringReader(lines)) const structure = { name: null, version: null, license: null, exports: null, scripts: null, devDependencies: null, author: null } await each(async () => { if (match('name')) structure.name = tail().trim() if (match('version')) structure.version = tail().trim() if (match('license')) structure.license = tail().trim() // FIXME: Order of operations causes other parts to break if this doesn't run first?! if (match('exports')) structure.exports = await parseObjectKV(null, async () => { const section = { import: null, require: null } await each(() => { if (match('import')) section.import = tail().trim() if (match('require')) section.require = tail().trim() if (section.import && section.require) return true }) return section }) if (match('scripts')) structure.scripts = await buildObject() if (match('devDependencies')) structure.devDependencies = await buildObject() if (match('author')) structure.author = await buildObject(['name', 'email', '#text']) return structure.name && structure.version && structure.license && structure.exports && structure.scripts && structure.devDependencies && structure.author }) return structure } export async function toArrays(lines) { const { next, level, line } = useDocument(createStringReader(lines)) const levelTracker = [] function createScope(level, line) { levelTracker.length = level const scope = levelTracker[level] = [line, []] return scope } createScope(0, 'root') // Simple parser that produces canonical array structure for blocks. while (true) { // If next() returns true we've ended the document. if (await next()) break; // Determine parent for this scope. const parent = levelTracker[level()] // If there's no parent, skip this line. if (!parent) continue // Create new scope const scope = createScope(level() + 1, line()) // Add current scope to parent. parent[1].push(scope) } return levelTracker[0] }