Skip to content

Commit

Permalink
refactor!: new parse logic
Browse files Browse the repository at this point in the history
this changes how parsing work fundamentally, it adds a carefully crafted
abstraction layer over the common parsing practice

BREAKING CHANGE: this is a breaking change

refactor: new parse (squash 2)

refactor: add EOF support (squash 3)
  • Loading branch information
xiaoxinghu committed Aug 12, 2021
1 parent 266566f commit 3a4ccf4
Show file tree
Hide file tree
Showing 19 changed files with 1,011 additions and 459 deletions.
4 changes: 4 additions & 0 deletions packages/oast-to-hast/src/handlers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ export default {
'text.verbatim': verbatim,
'text.strikeThrough': strikeThrough,
'text.underline': underline,
newline:
({ u }) =>
() =>
u('text', ' '),
paragraph,
link,
block,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,8 @@ Object {
},
"start": Object {
"column": 1,
"line": 3,
"offset": 26,
"line": 1,
"offset": 0,
},
},
"properties": Object {},
Expand Down Expand Up @@ -221,8 +221,8 @@ Object {
},
"start": Object {
"column": 1,
"line": 5,
"offset": 77,
"line": 1,
"offset": 0,
},
},
"properties": Object {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,8 +197,7 @@ Object {
"offset": 159,
},
},
"type": "text.plain",
"value": " ",
"type": "newline",
},
Object {
"parent": [Circular],
Expand Down Expand Up @@ -251,13 +250,29 @@ Object {
"type": "text.plain",
"value": " square holes...",
},
Object {
"parent": [Circular],
"position": Object {
"end": Object {
"column": 1,
"line": 5,
"offset": 206,
},
"start": Object {
"column": 46,
"line": 4,
"offset": 205,
},
},
"type": "newline",
},
],
"parent": [Circular],
"position": Object {
"end": Object {
"column": 1,
"line": 6,
"offset": 207,
"line": 5,
"offset": 206,
},
"start": Object {
"column": 1,
Expand Down Expand Up @@ -294,6 +309,22 @@ Object {
"type": "link",
"value": "logo.png",
},
Object {
"parent": [Circular],
"position": Object {
"end": Object {
"column": 19,
"line": 7,
"offset": 249,
},
"start": Object {
"column": 18,
"line": 7,
"offset": 248,
},
},
"type": "newline",
},
],
"parent": [Circular],
"position": Object {
Expand All @@ -319,8 +350,7 @@ Object {
},
"start": Object {
"column": 1,
"line": 3,
"offset": 40,
"line": 1,
},
},
"properties": Object {},
Expand Down
2 changes: 1 addition & 1 deletion packages/orga/src/parse/__tests__/block.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ console.log('world')
).toMatchSnapshot()
})

it('should handle broken blocks (missing end)', () => {
it.only('should handle broken blocks (missing end)', () => {
expect(
parse(
`
Expand Down
5 changes: 2 additions & 3 deletions packages/orga/src/parse/__tests__/paragraph.test.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import { Position } from 'unist'
import { tokenize } from '../../tokenize'
import { parse } from '../index'
import {
Document,
Headline,
PhrasingContent,
Section,
Stars,
} from '../../types'
import debug from './debug'
import { Position } from 'unist'
import { parse } from '../index'

describe('Parse Paragraph', () => {
it('works', () => {
Expand Down
4 changes: 3 additions & 1 deletion packages/orga/src/parse/__tests__/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,7 @@ export const debug = (text: string) => {
}

export const parse = (text: string) => {
return _parse(tokenize(text, { timezone: 'Pacific/Auckland' }))
const lexer = tokenize(text, { timezone: 'Pacific/Auckland' })
// console.log({ tokens: lexer.all() })
return _parse(lexer)
}
148 changes: 81 additions & 67 deletions packages/orga/src/parse/block.ts
Original file line number Diff line number Diff line change
@@ -1,78 +1,92 @@
import { Position } from 'unist'
import { Block } from '../types'
import { Lexer } from '../tokenize'
import { Action, Handler } from '.'
import { BlockBegin, BlockEnd } from '../types'

export default (lexer: Lexer): Block | undefined => {
const { peek, eat, substring } = lexer

const begin = peek()
/*
* find the indentation of the block and apply it to
* the rest of the block.
*
* The indentation of the first non-blank line is used as standard.
* The following lines use the lesser one between its own
* indentation and the standard. Leading and trailing blank lines
* are omitted.
*/
const align = (content: string) => {
let indent = -1
return content
.trimRight()
.split('\n')
.map((line) => {
const _indent = line.search(/\S/)
if (indent === -1) {
indent = _indent
}
if (indent === -1) return ''
return line.substring(Math.min(_indent, indent))
})
.join('\n')
.trim()
}

if (!begin || begin.type !== 'block.begin') return undefined
const block: Action = (
begin: BlockBegin,
{ save, push, enter, lexer }
): Handler => {
save()
const contentStart = begin.position.end
const blockName = begin.name.toLowerCase()

const block: Block = {
const block = enter({
type: 'block',
name: begin.name,
params: begin.params,
position: begin.position,
value: '',
attributes: {},
}
// const a = push(block)
// a(n)
eat()
let contentStart = begin.position.end
const nl = eat('newline')
if (nl) {
contentStart = nl.position.end
}
eat('newline')

const range: Position = {
start: contentStart,
end: begin.position.end,
}

/*
* find the indentation of the block and apply it to
* the rest of the block.
*
* The indentation of the first non-blank line is used as standard.
* The following lines use the lesser one between its own
* indentation and the standard. Leading and trailing blank lines
* are omitted.
*/
const align = (content: string) => {
let indent = -1
return content
.trimRight()
.split('\n')
.map((line) => {
const _indent = line.search(/\S/)
if (indent === -1) {
indent = _indent
}
if (indent === -1) return ''
return line.substring(Math.min(_indent, indent))
})
.join('\n')
}
children: [],
})
push(lexer.eat())

const parse = (): Block | undefined => {
const n = peek()
if (!n || n.type === 'stars') return undefined
eat()
if (
n.type === 'block.end' &&
n.name.toLowerCase() === begin.name.toLowerCase()
) {
range.end = n.position.start
eat('newline')
block.value = align(substring(range))
block.position.end = n.position.end
return block
}
return parse()
return {
name: 'block',
rules: [
{
test: 'newline',
action: (_, { restore }) => {
return 'next'
},
},
{
test: 'block.end',
action: (token: BlockEnd, { exit, push, lexer }) => {
const { eat } = lexer
if (token.name.toLowerCase() !== blockName) return 'next'
block.value = align(
lexer.substring({
start: contentStart,
end: token.position.start,
})
)
push(eat())
eat('newline')
exit('block')
return 'break'
},
},
{
test: ['stars', 'EOF'],
action: (token, { restore, lexer }) => {
console.log(`>> got ${token}`)
restore()
lexer.modify((t) => ({
type: 'text.plain',
value: lexer.substring(t.position),
position: t.position,
}))
return 'break'
},
},
{ test: /./, action: (_, { push, lexer }) => push(lexer.eat()) },
],
}

return parse()
}

export default block

0 comments on commit 3a4ccf4

Please sign in to comment.