-
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathindex.js
117 lines (100 loc) · 2.74 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
const combine = require('stream-combiner')
const jsYaml = require('js-yaml').load
const split = require('split')
const through = require('through2')
function isSeparator (line) {
// the '---' separator can have trailing whitespace but not leading whitespace
return line[0] === '-' && line.trim() === '---'
}
const NEWLINE = '\n'
function fastmatter (string) {
if (typeof string !== 'string') {
throw new Error('Need a string')
}
const bodyOnly = {
attributes: {},
body: string
}
const lines = string.split(NEWLINE)
if (!isSeparator(lines[0])) {
// no attributes; entire `string` is body
return bodyOnly
}
const attributes = []
const len = lines.length
let i = 1
while (i < len) {
if (isSeparator(lines[i])) {
// end of attributes
break
}
attributes.push(lines[i])
i += 1
}
if (i === lines.length) {
// second '---' is missing; assume entire `string` is body
return bodyOnly
}
return {
attributes: attributes.length ? jsYaml(attributes.join(NEWLINE)) : {},
body: lines.slice(i + 1).join(NEWLINE)
}
}
const SPLIT_REGEX = /(\n)/
function noop () {}
fastmatter.stream = function (callback) {
callback = callback || noop
let isFirstLine = true
let bodyFlag = 0
let firstSeparator = ''
let attributes = []
function transform (chunk, encoding, transformCallback) {
let line = chunk.toString()
if (bodyFlag === 0) {
// not in `body`
if (isFirstLine) {
isFirstLine = false
if (isSeparator(line)) {
// start of `attributes`
firstSeparator = line // we need this if the second '---' is missing
} else {
// no attributes; the entire stream is `body`
bodyFlag = 2 // the next line is the second line of `body`
callback.call(this, {})
callback = noop
this.push(line)
}
} else {
if (isSeparator(line)) {
bodyFlag = 1 // the next line is the first line of `body`
callback.call(this, jsYaml(attributes.join('')) || {})
callback = noop
firstSeparator = ''
attributes = []
} else {
attributes.push(line)
}
}
} else {
// in `body`
if (bodyFlag === 1) {
bodyFlag = 2 // the next line is the second line of `body`
line = line.substring(1) // drop the initial '\n'
}
this.push(line)
}
transformCallback()
}
function flush (flushCallback) {
callback.call(this, {})
if (firstSeparator.length) {
this.push(firstSeparator)
}
if (attributes.length) {
this.push(attributes.join(''))
}
flushCallback()
}
return combine(split(SPLIT_REGEX), through(transform, flush))
}
module.exports = fastmatter