Remove 'nest-whitespace-under-previous-line' logic and move it out to the same level, simplifying parser logic. Users of this lib can implement such behavior if they'd like.
This commit is contained in:
parent
f54e29acbf
commit
94767772b4
@ -110,10 +110,10 @@ async function main() {
|
||||
if (match('name')) author.name = tail().trim()
|
||||
else if (match('email')) author.email = tail().trim()
|
||||
else {
|
||||
if (!author['#text']) author['#text'] = [line()]
|
||||
if (!author['#text']) author['#text'] = [level(), line(l + 1)]
|
||||
// Loop through all remaining lines to avoid re-matching name or email above.
|
||||
while(await next(l)) {
|
||||
author['#text'].push(line())
|
||||
author['#text'].push(level(), line(l + 1))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
2
packages/js/core/dist/document.cjs
vendored
2
packages/js/core/dist/document.cjs
vendored
@ -1 +1 @@
|
||||
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const i=require("./parser.cjs");function f(r,c=" "){const e=i.createLineData("",c);let t=!1;async function o(n=-1){if(t)t=!1;else{const a=await r.next();if(a===null)return!1;e.line=a,i.parseLine(e)}return l()<=n?(t=!0,!1):!0}const l=()=>e.level,u=()=>e.line.slice(e.offsetHead),s=()=>e.line.slice(e.offsetHead,e.offsetTail);return{next:o,level:l,line:u,head:s,tail:()=>e.line.slice(e.offsetTail),match:n=>n===s()}}exports.useDocument=f;
|
||||
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const i=require("./parser.cjs");function f(r,c=" "){const e=i.createLineData("",c);let n=!1;async function o(t=-1){if(n)n=!1;else{const a=await r.next();if(a===null)return!1;e.line=a,i.parseLine(e)}return l()<=t?(n=!0,!1):!0}const l=()=>e.level,u=(t=e.offsetHead)=>e.line.slice(t),s=()=>e.line.slice(e.offsetHead,e.offsetTail);return{next:o,level:l,line:u,head:s,tail:()=>e.line.slice(e.offsetTail),match:t=>t===s()}}exports.useDocument=f;
|
||||
|
14
packages/js/core/dist/document.js
vendored
14
packages/js/core/dist/document.js
vendored
@ -1,26 +1,26 @@
|
||||
import { parseLine as r, createLineData as u } from "./parser.js";
|
||||
function h(s, f = " ") {
|
||||
const e = u("", f);
|
||||
let t = !1;
|
||||
async function c(n = -1) {
|
||||
if (t)
|
||||
t = !1;
|
||||
let n = !1;
|
||||
async function c(t = -1) {
|
||||
if (n)
|
||||
n = !1;
|
||||
else {
|
||||
const i = await s.next();
|
||||
if (i === null)
|
||||
return !1;
|
||||
e.line = i, r(e);
|
||||
}
|
||||
return l() <= n ? (t = !0, !1) : !0;
|
||||
return l() <= t ? (n = !0, !1) : !0;
|
||||
}
|
||||
const l = () => e.level, o = () => e.line.slice(e.offsetHead), a = () => e.line.slice(e.offsetHead, e.offsetTail);
|
||||
const l = () => e.level, o = (t = e.offsetHead) => e.line.slice(t), a = () => e.line.slice(e.offsetHead, e.offsetTail);
|
||||
return {
|
||||
next: c,
|
||||
level: l,
|
||||
line: o,
|
||||
head: a,
|
||||
tail: () => e.line.slice(e.offsetTail),
|
||||
match: (n) => n === a()
|
||||
match: (t) => t === a()
|
||||
};
|
||||
}
|
||||
export {
|
||||
|
2
packages/js/core/dist/parser.cjs
vendored
2
packages/js/core/dist/parser.cjs
vendored
@ -1 +1 @@
|
||||
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});function f(e="",r=" "){return{line:e,indent:r,type:0,level:0,offsetHead:0,offsetTail:0}}function o(e){if(typeof e!="object"||!e||typeof e.type!="number"||typeof e.level!="number")throw new Error("'lineData' must be an object with 'line' string, and 'type' and 'level' integer properties");if(typeof e.indent!="string"||e.indent.length===0||e.indent.length>1)throw new Error("'lineData.indent' must be a single-character string");if(typeof e.line!="string")throw new Error("'lineData.line' must be a string");let r=0,t=0;if(!e.line.length)e.type===1&&(t=e.level+1),e.type===0&&(t=e.level),e.type=r,e.level=t,e.offsetHead=0,e.offsetTail=0;else{for(r=1;e.line[t]===e.indent&&t<=e.level+1;)++t;for(e.type=r,e.level=t,e.offsetHead=t,e.offsetTail=t;e.line[e.offsetTail]&&e.line[e.offsetTail]!==" ";)++e.offsetTail}return e}exports.createLineData=f;exports.parseLine=o;
|
||||
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});function t(e="",r=" "){return{line:e,indent:r,level:0,offsetHead:0,offsetTail:0}}function f(e){if(typeof e!="object"||!e||typeof e.level!="number")throw new Error("'lineData' must be an object with 'line' string, and 'type' and 'level' integer properties");if(typeof e.indent!="string"||e.indent.length===0||e.indent.length>1)throw new Error("'lineData.indent' must be a single-character string");if(typeof e.line!="string")throw new Error("'lineData.line' must be a string");let r=0;if(!e.line.length)e.level=e.level,e.offsetHead=0,e.offsetTail=0;else{for(;e.line[r]===e.indent&&r<=e.level+1;)++r;for(e.level=r,e.offsetHead=r,e.offsetTail=r;e.line[e.offsetTail]&&e.line[e.offsetTail]!==" ";)++e.offsetTail}return e}exports.createLineData=t;exports.parseLine=f;
|
||||
|
22
packages/js/core/dist/parser.js
vendored
22
packages/js/core/dist/parser.js
vendored
@ -1,25 +1,25 @@
|
||||
function t(e = "", r = " ") {
|
||||
return { line: e, indent: r, type: 0, level: 0, offsetHead: 0, offsetTail: 0 };
|
||||
function f(e = "", r = " ") {
|
||||
return { line: e, indent: r, level: 0, offsetHead: 0, offsetTail: 0 };
|
||||
}
|
||||
function o(e) {
|
||||
if (typeof e != "object" || !e || typeof e.type != "number" || typeof e.level != "number")
|
||||
function t(e) {
|
||||
if (typeof e != "object" || !e || typeof e.level != "number")
|
||||
throw new Error("'lineData' must be an object with 'line' string, and 'type' and 'level' integer properties");
|
||||
if (typeof e.indent != "string" || e.indent.length === 0 || e.indent.length > 1)
|
||||
throw new Error("'lineData.indent' must be a single-character string");
|
||||
if (typeof e.line != "string")
|
||||
throw new Error("'lineData.line' must be a string");
|
||||
let r = 0, f = 0;
|
||||
let r = 0;
|
||||
if (!e.line.length)
|
||||
e.type === 1 && (f = e.level + 1), e.type === 0 && (f = e.level), e.type = r, e.level = f, e.offsetHead = 0, e.offsetTail = 0;
|
||||
e.level = e.level, e.offsetHead = 0, e.offsetTail = 0;
|
||||
else {
|
||||
for (r = 1; e.line[f] === e.indent && f <= e.level + 1; )
|
||||
++f;
|
||||
for (e.type = r, e.level = f, e.offsetHead = f, e.offsetTail = f; e.line[e.offsetTail] && e.line[e.offsetTail] !== " "; )
|
||||
for (; e.line[r] === e.indent && r <= e.level + 1; )
|
||||
++r;
|
||||
for (e.level = r, e.offsetHead = r, e.offsetTail = r; e.line[e.offsetTail] && e.line[e.offsetTail] !== " "; )
|
||||
++e.offsetTail;
|
||||
}
|
||||
return e;
|
||||
}
|
||||
export {
|
||||
t as createLineData,
|
||||
o as parseLine
|
||||
f as createLineData,
|
||||
t as parseLine
|
||||
};
|
||||
|
@ -4,7 +4,7 @@ import { createLineData, parseLine } from './parser'
|
||||
export type Document = {
|
||||
next: (startLevel?: number) => Promise<boolean>
|
||||
level: () => number,
|
||||
line: () => string,
|
||||
line: (startOffset?: number) => string,
|
||||
head: () => string,
|
||||
tail: () => string,
|
||||
match: (matchHead: string) => boolean
|
||||
@ -40,7 +40,7 @@ export function useDocument (reader: Reader, indent: string = ' '): Document {
|
||||
}
|
||||
|
||||
const level = () => lineData.level
|
||||
const line = () => lineData.line.slice(lineData.offsetHead)
|
||||
const line = (startOffset: number = lineData.offsetHead) => lineData.line.slice(startOffset)
|
||||
const head = () => lineData.line.slice(lineData.offsetHead, lineData.offsetTail)
|
||||
const tail = () => lineData.line.slice(lineData.offsetTail)
|
||||
const match = (matchHead: string): boolean => matchHead === head()
|
||||
|
@ -9,7 +9,7 @@ describe(`LineData`, () => {
|
||||
|
||||
it(`has five properties`, () => {
|
||||
const lineData = createLineData()
|
||||
expect(Object.keys(lineData).length).to.equal(6)
|
||||
expect(Object.keys(lineData).length).to.equal(5)
|
||||
})
|
||||
|
||||
it(`'line' is a string|null initialized to null`, () => {
|
||||
@ -17,14 +17,9 @@ describe(`LineData`, () => {
|
||||
expect(lineData.level).to.equal(0)
|
||||
})
|
||||
|
||||
it(`'type' is an integer initialized to zero`, () => {
|
||||
const lineData = createLineData()
|
||||
expect(lineData.level).to.equal(0)
|
||||
})
|
||||
|
||||
it(`'level' is an integer initialized to zero`, () => {
|
||||
const lineData = createLineData()
|
||||
expect(lineData.type).to.equal(0)
|
||||
expect(lineData.level).to.equal(0)
|
||||
})
|
||||
|
||||
it(`'offsetHead' is an integer initialized to zero`, () => {
|
||||
@ -39,24 +34,23 @@ describe(`LineData`, () => {
|
||||
})
|
||||
|
||||
describe(`parseLine`, () => {
|
||||
it(`Requres 'lineData' to be an object with a string line property and numeric level and type properties`, () => {
|
||||
const lineData = createLineData()
|
||||
it(`Requres 'lineData' to be an object with string line and numeric level properties`, () => {
|
||||
// @ts-ignore
|
||||
expect(() => parseLine(``, 0)).toThrowError(`'lineData' must be an object with 'line' string, and 'type' and 'level' integer properties`)
|
||||
expect(() => parseLine(``, 0)).toThrowError(`'lineData' must be an object with string line and numeric level properties`)
|
||||
// @ts-ignore
|
||||
expect(() => parseLine(``, [])).toThrowError(`'lineData' must be an object with 'line' string, and 'type' and 'level' integer properties`)
|
||||
expect(() => parseLine(``, [])).toThrowError(`'lineData' must be an object with string line and numeric level properties`)
|
||||
// @ts-ignore
|
||||
expect(() => parseLine(``, {})).toThrowError(`'lineData' must be an object with 'line' string, and 'type' and 'level' integer properties`)
|
||||
expect(() => parseLine(``, {})).toThrowError(`'lineData' must be an object with string line and numeric level properties`)
|
||||
// @ts-ignore
|
||||
expect(() => parseLine(``, null)).toThrowError(`'lineData' must be an object with 'line' string, and 'type' and 'level' integer properties`)
|
||||
expect(() => parseLine(``, null)).toThrowError(`'lineData' must be an object with string line and numeric level properties`)
|
||||
// @ts-ignore
|
||||
expect(() => parseLine(``, true)).toThrowError(`'lineData' must be an object with 'line' string, and 'type' and 'level' integer properties`)
|
||||
expect(() => parseLine(``, true)).toThrowError(`'lineData' must be an object with string line and numeric level properties`)
|
||||
// @ts-ignore
|
||||
expect(() => parseLine(``, () => {})).toThrowError(`'lineData' must be an object with 'line' string, and 'type' and 'level' integer properties`)
|
||||
expect(() => parseLine(``, () => {})).toThrowError(`'lineData' must be an object with string line and numeric level properties`)
|
||||
// @ts-ignore
|
||||
expect(() => parseLine(``, { line: '', level: '', type: 0 })).toThrowError(`'lineData' must be an object with 'line' string, and 'type' and 'level' integer properties`)
|
||||
expect(() => parseLine(``, { line: '', level: '' })).toThrowError(`'lineData' must be an object with string line and numeric level properties`)
|
||||
// @ts-ignore
|
||||
expect(() => parseLine(``, { line: '', level: 0, type: null })).toThrowError(`'lineData' must be an object with 'line' string, and 'type' and 'level' integer properties`)
|
||||
expect(() => parseLine(``, { line: '', level: 0 })).toThrowError(`'lineData' must be an object with string line and numeric level properties`)
|
||||
})
|
||||
|
||||
it(`Requres 'indent' to be a single-character string`, () => {
|
||||
@ -88,56 +82,56 @@ describe(`parseLine`, () => {
|
||||
const line = ``
|
||||
const lineData = createLineData(line)
|
||||
parseLine(lineData)
|
||||
expect(lineData).to.deep.equal({ line, indent: ` `, type: 0, level: 0, offsetHead: 0, offsetTail: 0 })
|
||||
expect(lineData).to.deep.equal({ line, indent: ` `, level: 0, offsetHead: 0, offsetTail: 0 })
|
||||
})
|
||||
|
||||
it(`Handles a line with a single space at indent level 1`, () => {
|
||||
const line = ` `
|
||||
const lineData = createLineData(line)
|
||||
parseLine(lineData)
|
||||
expect(lineData).to.deep.equal({ line, indent: ` `, type: 1, level: 1, offsetHead: 1, offsetTail: 1 })
|
||||
expect(lineData).to.deep.equal({ line, indent: ` `, level: 1, offsetHead: 1, offsetTail: 1 })
|
||||
})
|
||||
|
||||
it(`Handles a line with two spaces`, () => {
|
||||
const line = ` `
|
||||
const lineData = createLineData(line)
|
||||
parseLine(lineData)
|
||||
expect(lineData).to.deep.equal({ line, indent: ` `, type: 1, level: 2, offsetHead: 2, offsetTail: 2 })
|
||||
expect(lineData).to.deep.equal({ line, indent: ` `, level: 2, offsetHead: 2, offsetTail: 2 })
|
||||
})
|
||||
|
||||
it(`Handles a normal line at indent level 0`, () => {
|
||||
const line = `line 1`
|
||||
const lineData = createLineData(line)
|
||||
parseLine(lineData)
|
||||
expect(lineData).to.deep.equal({ line, indent: ` `, type: 1, level: 0, offsetHead: 0, offsetTail: 4 })
|
||||
expect(lineData).to.deep.equal({ line, indent: ` `, level: 0, offsetHead: 0, offsetTail: 4 })
|
||||
})
|
||||
|
||||
it(`Handles a normal line at indent level 1`, () => {
|
||||
const line = ` line 1`
|
||||
const lineData = createLineData(line)
|
||||
parseLine(lineData)
|
||||
expect(lineData).to.deep.equal({ line, indent: ` `, type: 1, level: 1, offsetHead: 1, offsetTail: 5 })
|
||||
expect(lineData).to.deep.equal({ line, indent: ` `, level: 1, offsetHead: 1, offsetTail: 5 })
|
||||
})
|
||||
|
||||
it(`Handles a normal line at indent level 2`, () => {
|
||||
const line = ` line 1`
|
||||
const lineData = createLineData(line)
|
||||
parseLine(lineData)
|
||||
expect(lineData).to.deep.equal({ line, indent: ` `, type: 1, level: 2, offsetHead: 2, offsetTail: 6 })
|
||||
expect(lineData).to.deep.equal({ line, indent: ` `, level: 2, offsetHead: 2, offsetTail: 6 })
|
||||
})
|
||||
|
||||
it(`Handles a normal line at indent level 1 indented with tabs`, () => {
|
||||
const line = `\tline 1`
|
||||
const lineData = createLineData(line, `\t`)
|
||||
parseLine(lineData)
|
||||
expect(lineData).to.deep.equal({ line, indent: `\t`, type: 1, level: 1, offsetHead: 1, offsetTail: 5 })
|
||||
expect(lineData).to.deep.equal({ line, indent: `\t`, level: 1, offsetHead: 1, offsetTail: 5 })
|
||||
})
|
||||
|
||||
it(`Handles a normal line at indent level 2 indented with tabs`, () => {
|
||||
const line = `\t\tline 1`
|
||||
const lineData = createLineData(line, `\t`)
|
||||
parseLine(lineData)
|
||||
expect(lineData).to.deep.equal({ line, indent: `\t`, type: 1, level: 2, offsetHead: 2, offsetTail: 6})
|
||||
expect(lineData).to.deep.equal({ line, indent: `\t`, level: 2, offsetHead: 2, offsetTail: 6})
|
||||
})
|
||||
|
||||
it(`Nests a normal line under a preceding normal line`, () => {
|
||||
@ -154,8 +148,8 @@ describe(`parseLine`, () => {
|
||||
})
|
||||
|
||||
expect(results).to.deep.equal([
|
||||
{ line: lines[0], indent: ' ', type: 1, level: 0, offsetHead: 0, offsetTail: 4 },
|
||||
{ line: lines[1], indent: ' ', type: 1, level: 1, offsetHead: 1, offsetTail: 5 }
|
||||
{ line: lines[0], indent: ' ', level: 0, offsetHead: 0, offsetTail: 4 },
|
||||
{ line: lines[1], indent: ' ', level: 1, offsetHead: 1, offsetTail: 5 }
|
||||
])
|
||||
})
|
||||
|
||||
@ -175,14 +169,14 @@ describe(`parseLine`, () => {
|
||||
})
|
||||
|
||||
expect(results).to.deep.equal([
|
||||
{ line: lines[0], indent: ' ', type: 1, level: 0, offsetHead: 0, offsetTail: 4 },
|
||||
{ line: lines[1], indent: ' ', type: 1, level: 1, offsetHead: 1, offsetTail: 5 },
|
||||
{ line: lines[2], indent: ' ', type: 1, level: 1, offsetHead: 1, offsetTail: 5 },
|
||||
{ line: lines[3], indent: ' ', type: 1, level: 1, offsetHead: 1, offsetTail: 5 }
|
||||
{ line: lines[0], indent: ' ', level: 0, offsetHead: 0, offsetTail: 4 },
|
||||
{ line: lines[1], indent: ' ', level: 1, offsetHead: 1, offsetTail: 5 },
|
||||
{ line: lines[2], indent: ' ', level: 1, offsetHead: 1, offsetTail: 5 },
|
||||
{ line: lines[3], indent: ' ', level: 1, offsetHead: 1, offsetTail: 5 }
|
||||
])
|
||||
})
|
||||
|
||||
it(`Nests an empty line under a preceding normal line`, () => {
|
||||
it(`Does not nest an empty line under a preceding normal line`, () => {
|
||||
const lines = [
|
||||
'line 1',
|
||||
''
|
||||
@ -196,12 +190,12 @@ describe(`parseLine`, () => {
|
||||
})
|
||||
|
||||
expect(results).to.deep.equal([
|
||||
{ line: lines[0], indent: ' ', type: 1, level: 0, offsetHead: 0, offsetTail: 4 },
|
||||
{ line: lines[1], indent: ' ', type: 0, level: 1, offsetHead: 0, offsetTail: 0 }
|
||||
{ line: lines[0], indent: ' ', level: 0, offsetHead: 0, offsetTail: 4 },
|
||||
{ line: lines[1], indent: ' ', level: 0, offsetHead: 0, offsetTail: 0 }
|
||||
])
|
||||
})
|
||||
|
||||
it(`Nests multiple empty lines under a preceding normal line`, () => {
|
||||
it(`Does not nest multiple empty lines under a preceding normal line`, () => {
|
||||
const lines = [
|
||||
'line 1',
|
||||
'',
|
||||
@ -217,10 +211,10 @@ describe(`parseLine`, () => {
|
||||
})
|
||||
|
||||
expect(results).to.deep.equal([
|
||||
{ line: lines[0], indent: ' ', type: 1, level: 0, offsetHead: 0, offsetTail: 4 },
|
||||
{ line: lines[1], indent: ' ', type: 0, level: 1, offsetHead: 0, offsetTail: 0 },
|
||||
{ line: lines[2], indent: ' ', type: 0, level: 1, offsetHead: 0, offsetTail: 0 },
|
||||
{ line: lines[3], indent: ' ', type: 0, level: 1, offsetHead: 0, offsetTail: 0 }
|
||||
{ line: lines[0], indent: ' ', level: 0, offsetHead: 0, offsetTail: 4 },
|
||||
{ line: lines[1], indent: ' ', level: 0, offsetHead: 0, offsetTail: 0 },
|
||||
{ line: lines[2], indent: ' ', level: 0, offsetHead: 0, offsetTail: 0 },
|
||||
{ line: lines[3], indent: ' ', level: 0, offsetHead: 0, offsetTail: 0 }
|
||||
])
|
||||
})
|
||||
|
||||
|
@ -1,44 +1,29 @@
|
||||
enum LineType {
|
||||
BLANK,
|
||||
NORMAL,
|
||||
}
|
||||
|
||||
export type LineData = {
|
||||
line: string;
|
||||
indent: string;
|
||||
type: number;
|
||||
level: number;
|
||||
offsetHead: number;
|
||||
offsetTail: number;
|
||||
}
|
||||
|
||||
export function createLineData(line: string = '', indent: string = ' '): LineData {
|
||||
return { line, indent, type: 0, level: 0, offsetHead: 0, offsetTail: 0 }
|
||||
return { line, indent, level: 0, offsetHead: 0, offsetTail: 0 }
|
||||
}
|
||||
|
||||
export function parseLine(lineData: LineData): LineData {
|
||||
if ((typeof lineData !== 'object' || !lineData) || typeof lineData.type !== 'number' || typeof lineData.level !== 'number') throw new Error(`'lineData' must be an object with 'line' string, and 'type' and 'level' integer properties`)
|
||||
if ((typeof lineData !== 'object' || !lineData) || typeof lineData.level !== 'number') throw new Error(`'lineData' must be an object with string line and numeric level properties`)
|
||||
if (typeof lineData.indent !== 'string' || lineData.indent.length === 0 || lineData.indent.length > 1) throw new Error(`'lineData.indent' must be a single-character string`)
|
||||
if (typeof lineData.line !== 'string') throw new Error(`'lineData.line' must be a string`)
|
||||
|
||||
let type = LineType.BLANK
|
||||
let level = 0
|
||||
|
||||
// Repeat previous level for blank lines.
|
||||
if (!lineData.line.length) {
|
||||
// TODO: Not sure if this is necessary. If the previous line was a normal line, it makes the blank line a child of the normal line.
|
||||
// If the previous line was a blank line, the blank line retains the same level.
|
||||
if (lineData.type === LineType.NORMAL) level = lineData.level + 1
|
||||
if (lineData.type === LineType.BLANK) level = lineData.level
|
||||
|
||||
lineData.type = type
|
||||
lineData.level = level
|
||||
lineData.level = lineData.level
|
||||
lineData.offsetHead = 0
|
||||
lineData.offsetTail = 0
|
||||
} else {
|
||||
type = LineType.NORMAL
|
||||
|
||||
while (lineData.line[level] === lineData.indent && level <= lineData.level + 1) ++level
|
||||
lineData.type = type
|
||||
lineData.level = level
|
||||
lineData.offsetHead = level
|
||||
lineData.offsetTail = level
|
||||
|
Loading…
x
Reference in New Issue
Block a user