Reorganize repo.
This commit is contained in:
23
packages/c/parser.c
Normal file
23
packages/c/parser.c
Normal file
@@ -0,0 +1,23 @@
|
||||
struct terrace_linedata_s {
|
||||
char type;
|
||||
unsigned int level;
|
||||
unsigned int offset;
|
||||
};
|
||||
|
||||
typedef struct terrace_linedata_s terrace_linedata_t;
|
||||
|
||||
void terrace_parse_line(char* line, terrace_linedata_t *lineData) {
|
||||
char type = 0;
|
||||
unsigned int level = 0;
|
||||
|
||||
if (line[0] == '\n') {
|
||||
if (lineData->type == 1) level++;
|
||||
if (lineData->type == 0) level = lineData->level;
|
||||
} else {
|
||||
type = 1;
|
||||
while(line[level] == ' ' && level <= lineData->level + 1) ++level;
|
||||
}
|
||||
|
||||
lineData->type = type;
|
||||
lineData->level = level;
|
||||
}
|
||||
1
packages/js/.gitignore
vendored
Normal file
1
packages/js/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
**/node_modules
|
||||
21
packages/js/block-markdown/LICENSE.md
Normal file
21
packages/js/block-markdown/LICENSE.md
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 Joshua Michael Bemenderfer
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
34
packages/js/block-markdown/index.js
Normal file
34
packages/js/block-markdown/index.js
Normal file
@@ -0,0 +1,34 @@
|
||||
import {unified} from 'unified'
|
||||
import remarkParse from 'remark-parse'
|
||||
import remarkRehype from 'remark-rehype'
|
||||
import rehypeStringify from 'rehype-stringify'
|
||||
|
||||
export default function (config) {
|
||||
|
||||
return async function ({ lineData, ended, next }) {
|
||||
if (ended) return ''
|
||||
const blockLevel = lineData.level
|
||||
|
||||
let md = ''
|
||||
|
||||
function finalize() {
|
||||
return unified()
|
||||
.use(remarkParse)
|
||||
.use(remarkRehype)
|
||||
.use(rehypeStringify)
|
||||
.process(md)
|
||||
}
|
||||
|
||||
async function markdownContents({ line, lineData, ended }) {
|
||||
if (ended || lineData.level <= blockLevel) {
|
||||
const final = String(await finalize())
|
||||
return final
|
||||
}
|
||||
|
||||
md += line.slice(blockLevel + 1) + '\n'
|
||||
return markdownContents(await next())
|
||||
}
|
||||
|
||||
return markdownContents(await next())
|
||||
}
|
||||
}
|
||||
2812
packages/js/block-markdown/package-lock.json
generated
Normal file
2812
packages/js/block-markdown/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
18
packages/js/block-markdown/package.json
Normal file
18
packages/js/block-markdown/package.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "@terrace/block-markdown",
|
||||
"type": "module",
|
||||
"version": "0.0.1",
|
||||
"main": "./index.js",
|
||||
"scripts": {
|
||||
"test": "vitest"
|
||||
},
|
||||
"devDependencies": {
|
||||
"vitest": "^0.24.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"rehype-stringify": "^9.0.3",
|
||||
"remark-parse": "^10.0.1",
|
||||
"remark-rehype": "^10.1.0",
|
||||
"unified": "^10.1.2"
|
||||
}
|
||||
}
|
||||
21
packages/js/core/LICENSE.md
Normal file
21
packages/js/core/LICENSE.md
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 Joshua Michael Bemenderfer
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
1282
packages/js/core/package-lock.json
generated
Normal file
1282
packages/js/core/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
12
packages/js/core/package.json
Normal file
12
packages/js/core/package.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "@terrace/core",
|
||||
"version": "0.0.1",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"test": "vitest"
|
||||
},
|
||||
"devDependencies": {
|
||||
"vitest": "^0.24.5"
|
||||
}
|
||||
}
|
||||
24
packages/js/core/src/parser.js
Normal file
24
packages/js/core/src/parser.js
Normal file
@@ -0,0 +1,24 @@
|
||||
export function LineData() {
|
||||
return { type: 0, level: 0, offset: 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
|
||||
}
|
||||
216
packages/js/core/src/parser.test.js
Normal file
216
packages/js/core/src/parser.test.js
Normal file
@@ -0,0 +1,216 @@
|
||||
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 three properties`, () => {
|
||||
const lineData = LineData()
|
||||
expect(Object.keys(lineData).length).to.equal(3)
|
||||
})
|
||||
|
||||
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)
|
||||
})
|
||||
|
||||
it(`'offset' is an integer initialized to zero`, () => {
|
||||
const lineData = LineData()
|
||||
expect(lineData.offset).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, offset: 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)
|
||||
expect(lineData.offset).to.equal(0)
|
||||
})
|
||||
|
||||
it(`Outputs { type: 1, level: 1, offset: 0 } 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)
|
||||
expect(lineData.offset).to.equal(0)
|
||||
})
|
||||
|
||||
it(`Outputs { type: 1, level: 2, offset: 0 } 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)
|
||||
expect(lineData.offset).to.equal(0)
|
||||
})
|
||||
|
||||
it(`Outputs { type: 1, level: 0, offset: 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)
|
||||
expect(lineData.offset).to.equal(0)
|
||||
})
|
||||
|
||||
it(`Outputs { type: 1, level: 1, offset: 0 } 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)
|
||||
expect(lineData.offset).to.equal(0)
|
||||
})
|
||||
|
||||
it(`Outputs { type: 1, level: 1, offset: 0 } 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)
|
||||
expect(lineData.offset).to.equal(0)
|
||||
})
|
||||
|
||||
it(`Outputs { type: 1, level: 1, offset: 0 } 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)
|
||||
expect(lineData.offset).to.equal(0)
|
||||
})
|
||||
|
||||
it(`Outputs { type: 1, level: 2, offset: 0 } 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)
|
||||
expect(lineData.offset).to.equal(0)
|
||||
})
|
||||
|
||||
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, offset: 0 },
|
||||
{ type: 1, level: 1, offset: 0 }
|
||||
])
|
||||
})
|
||||
|
||||
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, offset: 0 },
|
||||
{ type: 1, level: 1, offset: 0 },
|
||||
{ type: 1, level: 1, offset: 0 },
|
||||
{ type: 1, level: 1, offset: 0 }
|
||||
])
|
||||
})
|
||||
|
||||
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, offset: 0 },
|
||||
{ type: 0, level: 1, offset: 0 }
|
||||
])
|
||||
})
|
||||
|
||||
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, offset: 0 },
|
||||
{ type: 0, level: 1, offset: 0 },
|
||||
{ type: 0, level: 1, offset: 0 },
|
||||
{ type: 0, level: 1, offset: 0 }
|
||||
])
|
||||
})
|
||||
})
|
||||
20
packages/js/core/src/terrace.js
Normal file
20
packages/js/core/src/terrace.js
Normal file
@@ -0,0 +1,20 @@
|
||||
import { LineData, parseLine } from './parser.js'
|
||||
|
||||
export function document(nextFn, indent = ' ') {
|
||||
let line = null
|
||||
let lineData = LineData()
|
||||
let ended = false
|
||||
|
||||
async function next() {
|
||||
line = await nextFn()
|
||||
if (line == null) ended = true
|
||||
else parseLine(line, lineData, indent)
|
||||
return { line, lineData, ended, next, current }
|
||||
}
|
||||
|
||||
function current() {
|
||||
return { line, lineData, ended, next, current }
|
||||
}
|
||||
|
||||
return { next, current }
|
||||
}
|
||||
Reference in New Issue
Block a user