Initial commit.

This commit is contained in:
Joshua Bemenderfer
2022-08-31 22:15:07 -04:00
commit 9b5ac14082
11 changed files with 4401 additions and 0 deletions

24
implementations/js/.gitignore vendored Normal file
View File

@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

View File

@@ -0,0 +1,31 @@
import {unified} from 'unified'
import remarkParse from 'remark-parse'
import remarkRehype from 'remark-rehype'
import rehypeStringify from 'rehype-stringify'
export default function (line, lineData, doc) {
const blockLevel = lineData.level
let md = ''
function finalize() {
return unified()
.use(remarkParse)
.use(remarkRehype)
.use(rehypeStringify)
.process(md)
}
async function markdownContents(line, lineData, doc) {
if (lineData.level <= blockLevel) {
const final = String(await finalize())
page.body += final
return doc.repeat(baseHandler)
}
md += line.slice(blockLevel + 1) + '\n'
return doc.next(markdownContents)
}
return doc.next(markdownContents)
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,17 @@
{
"name": "@terrace/block-markdown",
"private": true,
"version": "0.0.0",
"scripts": {
"test": "vitest"
},
"devDependencies": {
"vitest": "^0.15.1"
},
"dependencies": {
"rehype-stringify": "^9.0.3",
"remark-parse": "^10.0.1",
"remark-rehype": "^10.1.0",
"unified": "^10.1.2"
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,11 @@
{
"name": "@terrace/core",
"private": true,
"version": "0.0.0",
"scripts": {
"test": "vitest"
},
"devDependencies": {
"vitest": "^0.15.1"
}
}

View File

@@ -0,0 +1,24 @@
export function LineData() {
return { type: 0, level: 0 }
}
export function parseLine(line, lineData, indent = ' ') {
if (typeof line !== 'string') throw new Error(`'line' must be a string`)
if ((typeof lineData !== 'object' || !lineData) || typeof lineData.type !== 'number' || typeof lineData.level !== 'number') throw new Error(`'lineData' must be an object with 'type' and 'level' integer properties`)
if (typeof indent !== 'string' || indent.length === 0 || indent.length > 1) throw new Error(`'indent' must be a single-character string`)
let type = 0
let level = 0
if (!line.length) {
if (lineData.type === 1) level += 1
if (lineData.type === 0) level = lineData.level
} else {
type = 1
while (line[level] === indent && level <= lineData.level + 1) ++level
}
lineData.type = type
lineData.level = level
return lineData
}

View File

@@ -0,0 +1,203 @@
import { assert, describe, expect, it } from 'vitest'
import { LineData, parseLine } from './parser'
describe(`LineData`, () => {
it(`is an object`, () => {
const lineData = LineData()
expect(lineData).toBeTypeOf(`object`)
})
it(`has two properties`, () => {
const lineData = LineData()
expect(Object.keys(lineData).length).to.equal(2)
})
it(`'type' is an integer initialized to zero`, () => {
const lineData = LineData()
expect(lineData.level).to.equal(0)
})
it(`'level' is an integer initialized to zero`, () => {
const lineData = LineData()
expect(lineData.type).to.equal(0)
})
})
describe(`parseLine`, () => {
it(`Requres 'line' to be a string`, () => {
const lineData = LineData()
expect(() => parseLine(0, lineData)).toThrowError(`'line' must be a string`)
expect(() => parseLine([], lineData)).toThrowError(`'line' must be a string`)
expect(() => parseLine({}, lineData)).toThrowError(`'line' must be a string`)
expect(() => parseLine(null, lineData)).toThrowError(`'line' must be a string`)
expect(() => parseLine(true, lineData)).toThrowError(`'line' must be a string`)
expect(() => parseLine(() => {}, lineData)).toThrowError(`'line' must be a string`)
})
it(`Requres 'lineData' to be an object with a numeric level and type property`, () => {
const lineData = LineData()
expect(() => parseLine(``, 0)).toThrowError(`'lineData' must be an object with 'type' and 'level' integer properties`)
expect(() => parseLine(``, [])).toThrowError(`'lineData' must be an object with 'type' and 'level' integer properties`)
expect(() => parseLine(``, {})).toThrowError(`'lineData' must be an object with 'type' and 'level' integer properties`)
expect(() => parseLine(``, null)).toThrowError(`'lineData' must be an object with 'type' and 'level' integer properties`)
expect(() => parseLine(``, true)).toThrowError(`'lineData' must be an object with 'type' and 'level' integer properties`)
expect(() => parseLine(``, () => {})).toThrowError(`'lineData' must be an object with 'type' and 'level' integer properties`)
expect(() => parseLine(``, { level: '', type: 0 })).toThrowError(`'lineData' must be an object with 'type' and 'level' integer properties`)
expect(() => parseLine(``, { level: 0, type: null })).toThrowError(`'lineData' must be an object with 'type' and 'level' integer properties`)
})
it(`Requres 'indent' to be a single-character string`, () => {
const lineData = LineData()
expect(() => parseLine(``, lineData, 0)).toThrowError(`'indent' must be a single-character string`)
expect(() => parseLine(``, lineData, [])).toThrowError(`'indent' must be a single-character string`)
expect(() => parseLine(``, lineData, {})).toThrowError(`'indent' must be a single-character string`)
expect(() => parseLine(``, lineData, null)).toThrowError(`'indent' must be a single-character string`)
expect(() => parseLine(``, lineData, true)).toThrowError(`'indent' must be a single-character string`)
expect(() => parseLine(``, lineData, () => {})).toThrowError(`'indent' must be a single-character string`)
expect(() => parseLine(``, lineData, ` `)).toThrowError(`'indent' must be a single-character string`)
})
it(`Outputs { type: 0, level: 0} for a blank line at indent level 0`, () => {
const line = ``
const lineData = LineData()
parseLine(line, lineData)
expect(lineData.type).to.equal(0)
expect(lineData.level).to.equal(0)
})
it(`Outputs { type: 1, level: 1} for line with a single space at indent level 1`, () => {
const line = ` `
const lineData = LineData()
parseLine(line, lineData)
expect(lineData.type).to.equal(1)
expect(lineData.level).to.equal(1)
})
it(`Outputs { type: 1, level: 2} for line with two spaces`, () => {
const line = ` `
const lineData = LineData()
parseLine(line, lineData)
expect(lineData.type).to.equal(1)
expect(lineData.level).to.equal(2)
})
it(`Outputs { type: 1, level: 0} for a normal line at indent level 0`, () => {
const line = `line 1`
const lineData = LineData()
parseLine(line, lineData)
expect(lineData.type).to.equal(1)
expect(lineData.level).to.equal(0)
})
it(`Outputs { type: 1, level: 1} for a normal line at indent level 1`, () => {
const line = ` line 1`
const lineData = LineData()
parseLine(line, lineData)
expect(lineData.type).to.equal(1)
expect(lineData.level).to.equal(1)
})
it(`Outputs { type: 1, level: 1} for a normal line at indent level 1`, () => {
const line = ` line 1`
const lineData = LineData()
parseLine(line, lineData)
expect(lineData.type).to.equal(1)
expect(lineData.level).to.equal(2)
})
it(`Outputs { type: 1, level: 1} for a normal line at indent level 1 indented with tabs`, () => {
const line = `\tline 1`
const lineData = LineData()
parseLine(line, lineData, `\t`)
expect(lineData.type).to.equal(1)
expect(lineData.level).to.equal(1)
})
it(`Outputs { type: 1, level: 2} for a normal line at indent level 1 indented with tabs`, () => {
const line = `\t\tline 1`
const lineData = LineData()
parseLine(line, lineData, `\t`)
expect(lineData.type).to.equal(1)
expect(lineData.level).to.equal(2)
})
it(`Nests a normal line under a preceding normal line`, () => {
const lines = [
'line 1',
' line 2'
]
const lineData = LineData()
const results = lines.map(line => {
parseLine(line, lineData)
return {...lineData}
})
expect(results).to.deep.equal([
{ type: 1, level: 0 },
{ type: 1, level: 1 }
])
})
it(`Nests multiple normal line under a preceding normal line`, () => {
const lines = [
'line 1',
' line 2',
' line 3',
' line 4',
]
const lineData = LineData()
const results = lines.map(line => {
parseLine(line, lineData)
return {...lineData}
})
expect(results).to.deep.equal([
{ type: 1, level: 0 },
{ type: 1, level: 1 },
{ type: 1, level: 1 },
{ type: 1, level: 1 }
])
})
it(`Nests an empty line under a preceding normal line`, () => {
const lines = [
'line 1',
''
]
const lineData = LineData()
const results = lines.map(line => {
parseLine(line, lineData)
return {...lineData}
})
expect(results).to.deep.equal([
{ type: 1, level: 0 },
{ type: 0, level: 1 }
])
})
it(`Nests multiple empty lines under a preceding normal line`, () => {
const lines = [
'line 1',
'',
'',
'',
]
const lineData = LineData()
const results = lines.map(line => {
parseLine(line, lineData)
return {...lineData}
})
expect(results).to.deep.equal([
{ type: 1, level: 0 },
{ type: 0, level: 1 },
{ type: 0, level: 1 },
{ type: 0, level: 1 }
])
})
})

View File

@@ -0,0 +1,23 @@
import { LineData, parseLine } from './parser';
export function document(nextFn, indent = ' ') {
let line = null
const lineData = LineData()
async function next(handler) {
line = await nextFn()
parseLine(line, lineData, indent)
return handler(line, lineData, { next, repeat, end })
}
function repeat(handler) {
return handler(line, lineData, { next, repeat, end })
}
function end() {
return
}
return { next, repeat, end }
}