forked from marijnh/Eloquent-JavaScript
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtransform.js
More file actions
108 lines (97 loc) · 3.37 KB
/
transform.js
File metadata and controls
108 lines (97 loc) · 3.37 KB
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
function childrenText(children) {
let text = ""
for (let i = 0; i < children.length; i++)
if (children[i].type == "text") text += children[i].content
return text
}
function hash(text) {
let sum = require("crypto").createHash("sha1")
sum.update(text)
return sum.digest("base64").slice(0, 10)
}
function startAndEnd(text) {
var words = text.split(/\W+/);
if (!words[0]) words.shift();
if (!words[words.length - 1]) words.pop();
if (words.length <= 6) return words.join(" ");
return words.slice(0, 3).join(" ") + " " + words.slice(words.length - 3).join(" ");
}
function tokenText(token) {
if (token.type == "text") return token.content
else if (token.type == "softbreak") return " "
}
function smartQuotes(tokens, i) {
let text = tokens[i].content, from = 0
for (let j = i - 1, tt; j >= 0; j--) if (tt = tokenText(tokens[j])) {
text = tt + text
from = tt.length
break
}
let to = text.length
for (let j = i + 1, tt; j < tokens.length; j++) if (tt = tokenText(tokens[j])) {
text += tt
break
}
return text
.replace(/([\w\.,!?\)])'/g, "$1’")
.replace(/'(\w)/g, "‘$1")
.replace(/([\w\.,!?\)])"/g, "$1”")
.replace(/"(\w)/g, "“$1")
.slice(from, to)
}
function handleIf(tokens, i, options) {
let tag = tokens[i].args[0]
if (options.defined.indexOf(tag) > -1) return i
for (let j = i + 1; j < tokens.length; j++) if (tokens[j].type == "meta_if_close" && tokens[j].args[0] == tag)
return j
}
function transformInline(tokens, options) {
let result = []
for (let i = 0; i < tokens.length; i++) {
let tok = tokens[i], type = tok.type
if (type == "meta_if_close" || (options.index === false && type == "meta_index")) {
// Drop
} else if (type == "meta_if_open") {
i = handleIf(tokens, i, options)
} else {
if (type == "text" && /[\'\"]/.test(tok.content)) tok.content = smartQuotes(tokens, i)
result.push(tok)
}
}
return result
}
function nextTag(tokens, i) {
for (let j = i + 1; j < tokens.length; j++) if (tokens[j].tag) return tokens[j];
}
exports.transformTokens = function(tokens, options) {
let meta = {}, result = []
for (let i = 0; i < tokens.length; i++) {
let tok = tokens[i], type = tok.type
if (type == "meta_meta") {
for (let prop in tok.args[0]) meta[prop] = tok.args[0][prop]
} else if (type == "meta_id") {
let next = nextTag(tokens, i)
;(next.attrs || (next.attrs = [])).push(["id", tok.args[0]])
} else if (type == "meta_table") {
nextTag(tokens, i).tableData = tok.args[0]
} else if (type == "meta_if_open") {
i = handleIf(tokens, i, options)
} else if (type == "meta_if_close" || (options.index === false && (type == "meta_indexsee" || type == "meta_index"))) {
// Drop
} else if (tok.tag == "h1") {
if (tokens[i + 1].children.length != 1) throw new Error("Complex H1 not supported")
meta.title = tokens[i + 1].children[0].content
i += 2
} else {
if (type == "paragraph_open")
tok.hashID = "p_" + hash(startAndEnd(childrenText(tokens[i + 1])))
else if (type == "heading_open")
tok.hashID = "h_" + hash(childrenText(tokens[i + 1]))
else if (type == "fence")
tok.hashID = "c_" + hash(tok.content)
if (tok.children) tok.children = transformInline(tok.children, options)
result.push(tok)
}
}
return {tokens: result, metadata: meta}
}