-
Notifications
You must be signed in to change notification settings - Fork 2
/
number.js
93 lines (87 loc) · 2.86 KB
/
number.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
const {createInterface} = require("readline");
const fs = require("fs");
class Number {
constructor(dir) {
this.dir = dir;
this.chapters = fs.readdirSync(dir).filter(fn => fn.endsWith(".md")).sort();
}
phase1(file) {
return new Promise(function(resolve, reject) {
createInterface({input: fs.createReadStream(this.dir + "/" + file), crlfDelay: Infinity})
.on("line", function(line) {
var m = line.match(/ ##([A-Za-z]+)(_([A-Za-z]+))?/);
if (m && line[m.index + m[0].length] !== "]") {
if (m[1].endsWith("sec")) {
m = line.match(/ ##([a-z]+)\s+(.+)$/);
m[3] = m[2].replace(/[^A-Za-z]/g, "");
}
this.counter[m[1]] = (this.counter[m[1]] || 0) + 1;
for (var subc in this.counter)
if (subc.endsWith("sub" + m[1]))
this.counter[subc] = 0;
this.number[this.match] = String(this.counter[m[1]]);
for (var supc = m[1]; supc.startsWith("sub");)
this.number[this.match] = this.counter[supc = supc.substring(3)] + "." + this.number[this.match];
if (m[1].endsWith("sec")) {
var s = this.number[this.match];
this.toc[s] = {
number: s,
name: m[2],
href: m[3],
sub: []
};
this.toc[s.substring(0, s.lastIndexOf("."))].sub.push(this.toc[s]);
}
if (m[2]) {
this.refs[m[3]] = this.number[this.match];
this.number[this.match] = `<a name="${m[3]}" href="#${m[3]}">${this.number[this.match]}</a>`;
}
this.match++;
}
}.bind(this))
.on("close", resolve);
}.bind(this));
}
phase2(file, out) {
return new Promise(function(resolve, reject) {
createInterface({input: fs.createReadStream(this.dir + "/" + file), crlfDelay: Infinity})
.on("line", function(line) {
var m = line.match(/ ##([A-Za-z]+)(_([A-Za-z]+))?/);
if (m && line[m.index + m[0].length] !== "]")
line = line.substring(0, m.index) + " " + this.number[this.match++] + line.substring(m.index + m[0].length);
out.write(line.replace(/##([A-Za-z]+)\]/g, function(m, p) {
var r = this.refs[p];
if (r) return `${r}](#${p})`;
else return `~~${p}~~]`;
}.bind(this)));
if (!(/\S\s$/.test(line))) out.write("\n");
}.bind(this))
.on("close", resolve);
}.bind(this));
}
tableofcontents(t, out, indent) {
for (var s of t) {
out.write(`${indent}- [${s.number}](#${s.href}) ${s.name}\n`);
this.tableofcontents(s.sub, out, indent + " ");
}
}
async build(out) {
this.counter = {};
this.refs = {};
this.number = {};
this.toc = {"": {sub: []}};
this.match = 0;
for (var c of this.chapters) await this.phase1(c);
this.match = 0;
for (c of this.chapters) {
await this.phase2(c, out);
if (c[0] === "0") {
out.write("# Table of Contents\n\n::: toc\n");
this.tableofcontents(this.toc[""].sub, out, "");
out.write(":::\n\n");
}
}
out.end();
}
}
module.exports = Number;